Merge pull request #5081 from sguilhen/KC6543

[KEYCLOAK-6543] Remove the authz examples from the Keycloak codebase.
This commit is contained in:
Pedro Igor 2018-03-20 09:09:04 -03:00 committed by GitHub
commit 66507cbf91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 3 additions and 3306 deletions

View file

@ -1,47 +0,0 @@
# 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

View file

@ -1,48 +0,0 @@
{
"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
}
]
}

View file

@ -1,36 +0,0 @@
{
"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\"]"
}
}
]
}

View file

@ -1,54 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,12 +0,0 @@
{
"realm": "hello-world-authz",
"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"
}
}

View file

@ -1,45 +0,0 @@
<?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>

View file

@ -1,30 +0,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.
~
--%>
<%@ 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>

View file

@ -1,49 +0,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.
~
--%>
<%@page import="org.keycloak.AuthorizationContext" %>
<%@ page import="org.keycloak.KeycloakSecurityContext" %>
<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
<%@ 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.getResourceName() %></p>
<p>ID: <%= permission.getResourceId() %></p>
</li>
<%
}
%>
</ul>
</body>
</html>

View file

@ -1,49 +0,0 @@
{
"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
}
]
}

View file

@ -1,30 +0,0 @@
{
"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\"]"
}
}
]
}

View file

@ -1,43 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,154 +0,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.
*
*/
package org.keycloak.authz.helloworld;
import org.keycloak.authorization.client.AuthzClient;
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.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.Permission;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationClientExample {
public static void main(String[] args) {
obtainEntitlementsForResource();
obtainAllEntitlements();
createResource();
updateResource();
introspectRequestingPartyToken();
}
private static void introspectRequestingPartyToken() {
// create a new instance based on the configuration defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();
// send the authorization request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize();
String rpt = response.getToken();
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 defined in 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();
ResourceRepresentation existingResource = resourceClient.findByName(newResource.getName());
if (existingResource != null) {
resourceClient.delete(existingResource.getId());
}
// create the resource on the server
ResourceRepresentation response = resourceClient.create(newResource);
String resourceId = response.getId();
// query the resource using its newly generated id
ResourceRepresentation resource = resourceClient.findById(resourceId);
System.out.println(resource);
}
private static void updateResource() {
// create a new instance based on the configuration defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();
// create a new resource representation with the information we want
ResourceRepresentation resource = new ResourceRepresentation();
resource.setName("New Resource");
ProtectedResource resourceClient = authzClient.protection().resource();
ResourceRepresentation existingResource = resourceClient.findByName(resource.getName());
if (existingResource == null) {
createResource();
}
resource.setId(existingResource.getId());
resource.setUri("Changed URI");
// update the resource on the server
resourceClient.update(resource);
// query the resource using its newly generated id
ResourceRepresentation existing = resourceClient.findById(resource.getId());
System.out.println(existing);
}
private static void obtainEntitlementsForResource() {
// create a new instance based on the configuration define at keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();
// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();
// add permissions to the request based on the resources and scopes you want to check access
request.addPermission("Default Resource");
// send the entitlement request to the server in order to
// obtain an RPT with permissions for a single resource
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();
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 defined in keycloak-authz.json
AuthzClient authzClient = AuthzClient.create();
// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();
// send the entitlement request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();
System.out.println("You got a RPT: " + rpt);
// now you can use the RPT to access protected resources on the resource server
}
}

View file

@ -1,8 +0,0 @@
{
"realm": "hello-world-authz",
"auth-server-url" : "http://localhost:8180/auth",
"resource" : "hello-world-authz-service",
"credentials": {
"secret": "secret"
}
}

View file

@ -1,100 +0,0 @@
# 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
> Please make sure you have the environment variable M2_HOME set. It should reference the path for your Maven installation. If not set, you will see some WARN messages in the logs when booting Keycloak.
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/target/classes/photoz-restful-api-authz-service.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

View file

@ -1,22 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kmodule
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>

View file

@ -1,14 +0,0 @@
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.hasRealmRole("admin")
)
then
$evaluation.grant();
end

View file

@ -1,15 +0,0 @@
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

View file

@ -1,14 +0,0 @@
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.hasRealmRole("user")
)
then
$evaluation.grant();
end

View file

@ -1,15 +0,0 @@
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

View file

@ -1,37 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,9 +0,0 @@
<?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>

View file

@ -1,31 +0,0 @@
<!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.account()">My Account</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>

View file

@ -1,231 +0,0 @@
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;
});
Album.shares(function (albums) {
$scope.shares = albums;
});
$scope.Identity = Identity;
$scope.deleteAlbum = function (album) {
new Album(album).$delete({id: album.id}, function () {
$route.reload();
});
}
$scope.requestDeleteAccess = function (album) {
new Album(album).$delete({id: album.id}, function () {
// no-op
}, function () {
document.getElementById("output").innerHTML = 'Sent authorization request to resource owner, please, wait for approval.';
});
}
$scope.hasAccess = function (share, scope) {
for (i = 0; i < share.scopes.length; i++) {
if (share.scopes[i] == scope) {
return true;
}
}
return false;
}
});
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.showRpt()
});
}
$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('/');
});
};
$scope.goto = function (path) {
$location.path(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', {id: '@id'}, {
shares: {url: apiUrl + '/album/shares', method: 'GET', isArray: true}
});
}]);
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) {
// 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.
var wwwAuthenticateHeader = rejection.headers('WWW-Authenticate');
// when using UMA, a WWW-Authenticate header should be returned by the resource server
if (!wwwAuthenticateHeader) {
return $q.reject(rejection);
}
// when using UMA, a WWW-Authenticate header should contain UMA data
if (wwwAuthenticateHeader.indexOf('UMA') == -1) {
return $q.reject(rejection);
}
var deferred = $q.defer();
var params = wwwAuthenticateHeader.split(',');
var ticket;
// try to extract the permission ticket from the WWW-Authenticate header
for (i = 0; i < params.length; i++) {
var param = params[i].split('=');
if (param[0] == 'ticket') {
ticket = param[1].substring(1, param[1].length - 1).trim();
break;
}
}
// a permission ticket must exist in order to send an authorization request
if (!ticket) {
return $q.reject(rejection);
}
// prepare a authorization request with the permission ticket
var authorizationRequest = {};
authorizationRequest.ticket = ticket;
// send the authorization request, if successful retry the request
Identity.authorization.authorize(authorizationRequest).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);
}
};
});

View file

@ -1,64 +0,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.
*
*/
/**
* 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.account = function () {
keycloak.accountManagement();
}
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 );

View file

@ -1,7 +0,0 @@
{
"realm": "photoz",
"auth-server-url" : "http://localhost:8180/auth",
"ssl-required" : "external",
"resource" : "photoz-html5-client",
"public-client" : true
}

View file

@ -1,13 +0,0 @@
/*
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

View file

@ -1,14 +0,0 @@
/*
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

View file

@ -1,214 +0,0 @@
/*
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

View file

@ -1 +0,0 @@
!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]);

View file

@ -1,22 +0,0 @@
<h2>All Albums</h2>
<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>
<p>
<a href="#/">Back to main page</a>
</p>

View file

@ -1,7 +0,0 @@
<h2>Create an Album</h2>
<form>
Name: <input type="text" id="album.name" ng-model="album.name"/>
<button ng-click="create()" id="save-album">Save</button> <button ng-click="goto('/')">Cancel</button>
</form>

View file

@ -1,4 +0,0 @@
<h2>{{album.name}}</h2>
<div data-ng-show="Identity.isAdmin()"><a href="#/admin/album">Back to albums</a></div>
<div data-ng-show="!Identity.isAdmin()"><a href="#/">Back to main page</a></div>

View file

@ -1,22 +0,0 @@
<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/>
<h3>Your Albums</h3>
<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">
<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>
</table>
<h3>Shared With Me</h3>
<span data-ng-show="shares.length == 0" id="share-list-empty">You don't have any shares, yet.</span>
<table class="table" data-ng-show="shares.length > 0">
<tr data-ng-repeat="p in shares">
<td><a id="view-share-{{p.album.name}}" href="#/album/{{p.album.id}}">{{p.album.name}}</a> - <a href="#" id="delete-share-{{p.album.name}}" data-ng-show="hasAccess(p, 'album:delete')" ng-click="deleteAlbum(p.album)">[X]</a><a href="#" id="request-delete-share-{{p.album.name}}" data-ng-hide="hasAccess(p, 'album:delete')" ng-click="requestDeleteAccess(p.album)">Request Delete Access</a></td>
</tr>
</table>
</div>

View file

@ -1,9 +0,0 @@
<h2>My Profile</h2>
<form>
<p>Name: {{profile.userName}}</p>
<p>Total of albums: {{profile.totalAlbums}}</p>
</form>
<p>
<a href="#/">Back to main page</a>
</p>

View file

@ -1,132 +0,0 @@
{
"realm": "photoz",
"enabled": true,
"userManagedAccessAllowed": "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"
],
"account": [
"manage-account"
]
}
},
{
"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"
],
"account": [
"manage-account"
]
}
},
{
"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": "http://localhost:8080/photoz-html5-client",
"baseUrl": "http://localhost:8080/photoz-html5-client",
"publicClient": true,
"consentRequired" : true,
"fullScopeAllowed" : true,
"redirectUris": [
"http://localhost:8080/photoz-html5-client/*"
],
"webOrigins": ["http://localhost:8080"]
},
{
"clientId": "photoz-restful-api",
"secret": "secret",
"enabled": true,
"baseUrl": "http://localhost:8080/photoz-restful-api",
"authorizationServicesEnabled" : true,
"redirectUris": [
"http://localhost:8080/photoz-html5-client"
],
"webOrigins" : ["http://localhost:8080"]
}
]
}

View file

@ -1,81 +0,0 @@
<?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>4.0.0.CR1-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>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.0-SP4</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>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<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>

View file

@ -1,32 +0,0 @@
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();
}
}

View file

@ -1,12 +0,0 @@
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 {
}

View file

@ -1,61 +0,0 @@
/*
* 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.keycloak.example.photoz.entity.Album;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@Path("/admin/album")
public class AdminAlbumService {
@Inject
private EntityManager entityManager;
@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) {
List<Album> userAlbums = albums.get(album.getUserId());
if (userAlbums == null) {
userAlbums = new ArrayList<>();
albums.put(album.getUserId(), userAlbums);
}
userAlbums.add(album);
}
return Response.ok(albums).build();
}
}

View file

@ -1,181 +0,0 @@
package org.keycloak.example.photoz.album;
import java.security.Principal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
import javax.persistence.EntityManager;
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 org.keycloak.KeycloakSecurityContext;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthorizationContext;
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.example.photoz.util.Transaction;
import org.keycloak.representations.idm.authorization.PermissionTicketRepresentation;
@Path("/album")
@Transaction
public class AlbumService {
public static final String SCOPE_ALBUM_VIEW = "album:view";
public static final String SCOPE_ALBUM_DELETE = "album:delete";
@Inject
private EntityManager entityManager;
@Context
private HttpServletRequest request;
@POST
@Consumes("application/json")
public Response create(Album newAlbum) {
Principal userPrincipal = request.getUserPrincipal();
newAlbum.setId(UUID.randomUUID().toString());
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);
}
try {
this.entityManager.persist(newAlbum);
createProtectedResource(newAlbum);
} catch (Exception e) {
getAuthzClient().protection().resource().delete(newAlbum.getExternalId());
}
return Response.ok(newAlbum).build();
}
@Path("{id}")
@DELETE
public Response delete(@PathParam("id") String id) {
Album album = this.entityManager.find(Album.class, 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 = :id").setParameter("id", request.getUserPrincipal().getName()).getResultList()).build();
}
@GET
@Path("/shares")
@Produces("application/json")
public Response findShares() {
List<PermissionTicketRepresentation> permissions = getAuthzClient().protection().permission().find(null, null, null, getKeycloakSecurityContext().getToken().getSubject(), true, true, null, null);
Map<String, SharedAlbum> shares = new HashMap<>();
for (PermissionTicketRepresentation permission : permissions) {
SharedAlbum share = shares.get(permission.getResource());
if (share == null) {
share = new SharedAlbum(Album.class.cast(entityManager.createQuery("from Album where externalId = :externalId").setParameter("externalId", permission.getResource()).getSingleResult()));
shares.put(permission.getResource(), share);
}
if (permission.getScope() != null) {
share.addScope(permission.getScopeName());
}
}
return Response.ok(shares.values()).build();
}
@GET
@Path("{id}")
@Produces("application/json")
public Response findById(@PathParam("id") String id) {
List result = this.entityManager.createQuery("from Album where id = :id").setParameter("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());
albumResource.setOwnerManagedAccess(true);
ResourceRepresentation response = getAuthzClient().protection().resource().create(albumResource);
album.setExternalId(response.getId());
} 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();
List<ResourceRepresentation> search = protection.resource().findByUri(uri);
if (search.isEmpty()) {
throw new RuntimeException("Could not find protected resource with URI [" + uri + "]");
}
protection.resource().delete(search.get(0).getId());
} catch (Exception e) {
throw new RuntimeException("Could not search protected resource.", e);
}
}
private AuthzClient getAuthzClient() {
return getAuthorizationContext().getClient();
}
private ClientAuthorizationContext getAuthorizationContext() {
return ClientAuthorizationContext.class.cast(getKeycloakSecurityContext().getAuthorizationContext());
}
private KeycloakSecurityContext getKeycloakSecurityContext() {
return KeycloakSecurityContext.class.cast(request.getAttribute(KeycloakSecurityContext.class.getName()));
}
}

View file

@ -1,67 +0,0 @@
/*
* 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.inject.Inject;
import javax.persistence.EntityManager;
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 java.security.Principal;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@Path("/profile")
public class ProfileService {
private static final String PROFILE_VIEW = "urn:photoz.com:scopes:profile:view";
@Inject
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 = :id").setParameter("id", 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;
}
}
}

View file

@ -1,47 +0,0 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS 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 java.util.ArrayList;
import java.util.List;
import org.keycloak.example.photoz.entity.Album;
public class SharedAlbum {
private Album album;
private List<String> scopes;
public SharedAlbum(Album album) {
this.album = album;
}
public Album getAlbum() {
return album;
}
public List<String> getScopes() {
return scopes;
}
public void addScope(String scope) {
if (scopes == null) {
scopes = new ArrayList<>();
}
scopes.add(scope);
}
}

View file

@ -1,91 +0,0 @@
/*
* 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 java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
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
private String 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;
@Column
private String externalId;
public String getId() {
return this.id;
}
public void setId(final String 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;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public String getExternalId() {
return externalId;
}
}

View file

@ -1,81 +0,0 @@
/*
* 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;
}
}

View file

@ -1,51 +0,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.
*/
package org.keycloak.example.photoz.util;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@ApplicationScoped
public class Resources {
private EntityManagerFactory entityManagerFactory;
@PostConstruct
public void init() {
entityManagerFactory = Persistence.createEntityManagerFactory("primary");
}
@PreDestroy
public void dispose() {
entityManagerFactory.close();
}
@RequestScoped
@Produces
public EntityManager createEntityManager() {
return entityManagerFactory.createEntityManager();
}
}

View file

@ -1,33 +0,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.
*/
package org.keycloak.example.photoz.util;
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@InterceptorBinding
@Target({ TYPE })
@Retention(RUNTIME)
public @interface Transaction {
}

View file

@ -1,56 +0,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.
*/
package org.keycloak.example.photoz.util;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@Interceptor
@Transaction
public class TransactionInterceptor {
@Inject
private Instance<EntityManager> entityManager;
@AroundInvoke
public Object aroundInvoke(InvocationContext context) {
EntityManager entityManager = this.entityManager.get();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
Object proceed = context.proceed();
transaction.commit();
return proceed;
} catch (Exception cause) {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
throw new RuntimeException(cause);
} finally {
entityManager.close();
}
}
}

View file

@ -1,9 +0,0 @@
<?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">
<interceptors>
<class>org.keycloak.example.photoz.util.TransactionInterceptor</class>
</interceptors>
</beans>

View file

@ -1,23 +0,0 @@
<?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" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<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.H2Dialect" />
<property name="hibernate.connection.driver_class" value="org.h2.Driver" />
<property name="hibernate.connection.url" value="jdbc:h2:~/keycloak-photoz-example" />
<property name="hibernate.connection.user" value="sa" />
<property name="hibernate.flushMode" value="FLUSH_AUTO" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>

View file

@ -1,152 +0,0 @@
{
"allowRemoteResourceManagement": true,
"policyEnforcementMode": "ENFORCING",
"resources": [
{
"name": "Admin Resources",
"uri": "/admin/*",
"type": "http://photoz.com/admin",
"scopes": [
{
"name": "admin:manage"
}
]
},
{
"name": "User Profile Resource",
"uri": "/profile",
"type": "http://photoz.com/profile",
"scopes": [
{
"name": "profile:view"
}
]
},
{
"name": "Album Resource",
"uri": "/album/*",
"type": "http://photoz.com/album",
"scopes": [
{
"name": "album:delete"
},
{
"name": "album:view"
}
]
}
],
"policies": [
{
"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": "Administration Policy",
"description": "Defines that only administrators from a specific network address can do something.",
"type": "aggregate",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"applyPolicies": "[\"Any Admin Policy\",\"Only From a Specific Client Address\"]"
}
},
{
"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.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {\n $evaluation.grant();\n}"
}
},
{
"name": "Only Owner Policy",
"description": "Defines that only the resource owner is allowed to do something",
"type": "rules",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"mavenArtifactVersion": "${project.version}",
"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": "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": "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\",\"required\":false},{\"id\":\"photoz-restful-api/manage-albums\",\"required\":true}]"
}
},
{
"name": "Admin Resource Permission",
"description": "General policy for any administrative resource.",
"type": "resource",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"defaultResourceType": "http://photoz.com/admin",
"applyPolicies": "[\"Administration Policy\"]",
"default": "true"
}
},
{
"name": "Album Resource Permission",
"description": "A default permission that defines access for any album resource",
"type": "scope",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"resources": "[\"Album Resource\"]",
"scopes": "[\"album:view\",\"album:delete\"]",
"applyPolicies": "[\"Only Owner and Administrators Policy\"]"
}
},
{
"name": "View User Permission",
"description": "Defines who is allowed to view an user profile",
"type": "scope",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"scopes": "[\"profile:view\"]",
"applyPolicies": "[\"Only From @keycloak.org or Admin\"]"
}
}
]
}

View file

@ -1,27 +0,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.
~
-->
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-authz-client" services="import"/>
<module name="com.h2database.h2" services="import"/>
</dependencies>
</deployment>
</jboss-deployment-structure>

View file

@ -1,42 +0,0 @@
{
"realm": "photoz",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "photoz-restful-api",
"bearer-only" : true,
"credentials": {
"secret": "secret"
},
"policy-enforcer": {
"enforcement-mode": "PERMISSIVE",
"user-managed-access": {},
"paths": [
{
"name" : "Album Resource",
"path" : "/album/{id}",
"methods" : [
{
"method": "DELETE",
"scopes" : ["album:delete"]
},
{
"method": "GET",
"scopes" : ["album:view"]
}
]
},
{
"name" : "Album Resource",
"path" : "/album/shares",
"enforcement-mode": "DISABLED"
},
{
"path" : "/profile"
},
{
"name" : "Admin Resources",
"path" : "/admin/*"
}
]
}
}

View file

@ -1,41 +0,0 @@
<?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>

View file

@ -1,24 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,30 +0,0 @@
<?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>4.0.0.CR1-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.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
</properties>
<modules>
<module>photoz</module>
<module>servlet-authz</module>
<module>hello-world</module>
<module>hello-world-authz-service</module>
</modules>
</project>

View file

@ -1,54 +0,0 @@
# 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

View file

@ -1,54 +0,0 @@
<?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>4.0.0.CR1-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>

View file

@ -1,145 +0,0 @@
{
"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/*",
"scopes": [
{
"name": "urn:servlet-authz:protected:premium:access"
}
]
},
{
"name": "Main Page",
"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\"]"
}
}
]
}

View file

@ -1,95 +0,0 @@
{
"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"
}
]
}

View file

@ -1,25 +0,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.
~
-->
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-authz-client" services="import"/>
</dependencies>
</deployment>
</jboss-deployment-structure>

View file

@ -1,10 +0,0 @@
{
"realm": "servlet-authz",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "servlet-authz-app",
"credentials": {
"secret": "secret"
},
"policy-enforcer": {}
}

View file

@ -1,43 +0,0 @@
<?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>
<role-name>admin</role-name>
<role-name>user_premium</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>
<security-role>
<role-name>user_premium</role-name>
</security-role>
<error-page>
<error-code>403</error-code>
<location>/accessDenied.jsp</location>
</error-page>
</web-app>

View file

@ -1,6 +0,0 @@
<html>
<body>
<h2 style="color: red">You can not access this resource.</h2>
<%@include file="logout-include.jsp"%>
</body>
</html>

View file

@ -1,35 +0,0 @@
<%@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.getResourceName() %></p>
<p>ID: <%= permission.getResourceId() %></p>
<p>Scopes: <%= permission.getScopes() %></p>
</li>
<%
}
%>
</ul>
</body>
</html>

View file

@ -1,11 +0,0 @@
<%@ 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>

View file

@ -1,6 +0,0 @@
<html>
<body>
<h2>Only Administrators can access this page.</h2>
<%@include file="../../logout-include.jsp"%>
</body>
</html>

View file

@ -1,48 +0,0 @@
<%@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>

View file

@ -1,6 +0,0 @@
<html>
<body>
<h2>Only for premium users.</h2>
<%@include file="../../logout-include.jsp"%>
</body>
</html>

View file

@ -66,6 +66,5 @@
<module>themes</module>
<module>saml</module>
<module>ldap</module>
<module>authz</module>
</modules>
</project>

View file

@ -95,7 +95,7 @@ public class RulesPolicyManagementTest extends AbstractPolicyManagementTest {
representation.setDescription("description");
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
representation.setLogic(Logic.NEGATIVE);
representation.setArtifactGroupId("org.keycloak");
representation.setArtifactGroupId("org.keycloak.testsuite");
representation.setArtifactId("photoz-authz-policy");
representation.setArtifactVersion(System.getProperty("project.version"));
representation.setModuleName("PhotozAuthzOwnerPolicy");

View file

@ -61,7 +61,7 @@
"mavenArtifactVersion": "${project.version}",
"mavenArtifactId": "photoz-authz-policy",
"sessionName": "MainOwnerSession",
"mavenArtifactGroupId": "org.keycloak",
"mavenArtifactGroupId": "org.keycloak.testsuite",
"moduleName": "PhotozAuthzOwnerPolicy",
"scannerPeriod": "1",
"scannerPeriodUnit": "Hours"

View file

@ -88,7 +88,7 @@ public class RulePolicyManagementTest extends AbstractAuthorizationSettingsTest
expected.setName(name);
expected.setDescription("description");
expected.setArtifactGroupId("org.keycloak");
expected.setArtifactGroupId("org.keycloak.testsuite");
expected.setArtifactId("photoz-authz-policy");
expected.setArtifactVersion(Version.VERSION);
expected.setModuleName("PhotozAuthzOwnerPolicy");