You are viewing a plain text version of this content. The canonical link for it is here.
Posted to rampart-dev@ws.apache.org by mi...@apache.org on 2008/02/15 18:27:51 UTC

svn commit: r628127 - in /webservices/rampart/scratch/c/fed/c: include/fed_constants.h include/fed_metadata.h src/fed/ src/fed/fed_metadata.c

Author: milinda
Date: Fri Feb 15 09:27:50 2008
New Revision: 628127

URL: http://svn.apache.org/viewvc?rev=628127&view=rev
Log:
Add initial federation related implementations.

Added:
    webservices/rampart/scratch/c/fed/c/include/fed_constants.h
    webservices/rampart/scratch/c/fed/c/include/fed_metadata.h
    webservices/rampart/scratch/c/fed/c/src/fed/
    webservices/rampart/scratch/c/fed/c/src/fed/fed_metadata.c

Added: webservices/rampart/scratch/c/fed/c/include/fed_constants.h
URL: http://svn.apache.org/viewvc/webservices/rampart/scratch/c/fed/c/include/fed_constants.h?rev=628127&view=auto
==============================================================================
--- webservices/rampart/scratch/c/fed/c/include/fed_constants.h (added)
+++ webservices/rampart/scratch/c/fed/c/include/fed_constants.h Fri Feb 15 09:27:50 2008
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * 		http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+*/
+
+#ifndef FED_CONSTANTS_H
+#define FED_CONSTANTS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	/* Federation Namespaces and Prefixes*/
+	#define FED_WSF				"fed"
+	#define FED_FED_XML_NS 		"http://schemas.xmlsoap.org/ws/2006/12/federation"
+
+	#define FED_AUTH			"auth"
+	#define FED_AUTH_XML_NS 	"http://schemas.xmlsoap.org/ws/2006/12/authorization"
+
+	#define FED_WSA        		"wsa"
+	#define FED_WSA_XMLNS  		"http://schemas.xmlsoap.org/ws/2004/08/addressing"
+
+	#define FED_DS         "ds"
+	#define FED_DS_XMLNS   "http://www.w3.org/2000/09/xmldsig#"
+
+
+	/* Federation Local Names*/
+	#define FED_FEDERATION								"Federation"
+	#define FED_FEDERATION_METADATA						"FederationMetadata"
+	#define FED_TOKEN_SIGNING_KEY_INFO					"TokenSigningKeyInfo"
+	#define FED_TOKEN_KEY_TRANSFER_KEY_INFO				"TokenKeyTransferKeyInfo"
+	#define FED_ISSER_NAMES_OFFERED						"IssuerNamesOffered"
+	#define FED_ISSER_NAMES_OFFERED_ISSUER_NAME			"IssuerNamesOffered"
+	#define FED_TOKEN_ISSUER_NAME						"TokenIssuerName"
+	#define FED_TOKEN_ISSUER_END_POINT					"TokenIssuerEndpoint"
+	#define FED_PSEUDONYM_SERVICE_END_POINT				"PseudonymServiceEndpoint"
+	#define FED_ATTRIBUTE_SERVICE_END_POINT				"AttributeServiceEndpoint"
+	#define FED_SINGLE_SIGNOUT_SUBSCRIPTION_END_POINT	"SingleSignOutSubscripionEndpoint"
+	#define FED_SINGLE_SIGNOUT_NOTIFICATION_END_POINT	"SingleSignOutNotificationEndpoint"
+	#define FED_TOKEN_TYPES_OFFERED						"TokenTypesOffered"
+	#define FED_TOKEN_TYPE								"TokenType"
+	#define FED_URI_NAMED_CLAIM_TYPES_OFFERED			"UriNamedClaimTypesOffered"
+	#define FED_URI_NAMED_CLAIM_TYPE					"ClaimType"
+	#define FED_URI_NAMED_CLAIM_TYPE_DISPLAY_NAME		"DisplayName"
+	#define FED_URI_NAMED_CLAIM_TYPE_DESCRIPTION		"Description"
+	#define FED_WSA_ADDRESS								"Address"
+
+	/* Federation Attribute Names */
+	#define FED_ATTR_FED_ID					"FederationID"
+	#define FED_ATTR_TOKEN_TYPE_URI			"Uri"
+	#define FED_ATTR_METADATA_WSU_ID		"Id"
+	#define FED_ATTR_URI					"Uri"
+
+
+
+
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FED_CONSTANTS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: webservices/rampart/scratch/c/fed/c/include/fed_metadata.h
URL: http://svn.apache.org/viewvc/webservices/rampart/scratch/c/fed/c/include/fed_metadata.h?rev=628127&view=auto
==============================================================================
--- webservices/rampart/scratch/c/fed/c/include/fed_metadata.h (added)
+++ webservices/rampart/scratch/c/fed/c/include/fed_metadata.h Fri Feb 15 09:27:50 2008
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * 		http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+*/
+
+#ifndef FED_METADATA_CONTEXT_H
+#define FED_METADATA_CONTEXT_H
+
+#include <axiom.h>
+#include <axutil_utils.h>
+#include <axutil_hash.h>
+#include <axutil_array_list.h>
+
+#include "fed_constants.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	typedef struct fed_metadata_context fed_metadata_context_t;
+
+	typedef struct fed_metadata_claim_type 
+	{
+		axis2_char_t *claim_type_uri_attr;
+		axis2_char_t *display_name;
+		axis2_char_t *description;
+	}fed_metadata_claim_type_t;
+	
+	AXIS2_EXTERN fed_metadata_context_t* AXIS2_CALL
+	fed_metadata_context_create(
+			axiom_node_t *metadata_node,
+			const axutil_env_t * env);
+
+	AXIS2_EXTERN void AXIS2_CALL
+	fed_metadata_context_free(
+			fed_metadata_context_t *metadata_context,
+			const axutil_env_t * env);
+
+	/** 
+	 * Populate the Federation Metadata context from federation metadata node. (of a given federation)
+	 * @param fed_metadata_context object . cannot be NULL
+	 * @param metadata axiom node. cannot be NULL
+	 * @return status
+	 */
+	AXIS2_EXTERN axis2_status_t AXIS2_CALL
+		fed_metadata_context_populate_metadata(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t * env);
+
+
+	/**
+	 * Generate the axiom node of the populated metadata context (for a given federation)
+	 * @param fed_metadata_context . cannot be NULL
+	 */
+	AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+		fed_metadata_context_build_metadata_om(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+
+	/* Getters*/
+	AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+		fed_metadata_context_get_token_signing_key(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+
+	AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+		fed_metadata_context_get_federation_id(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+		fed_metadata_context_get_token_issuer_name(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+
+	AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+		fed_metadata_context_get_metadata_node(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN axutil_array_list_t* AXIS2_CALL
+		fed_metadata_context_get_token_types_offered_list(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+		fed_metadata_context_get_token_signing_info_node(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+		fed_metadata_context_get_token_key_transfer_key_info_node(
+				fed_metadata_context_t *metadata_context,
+				const axutil_env_t *env);
+
+	/*Setters*/
+	AXIS2_EXTERN void AXIS2_CALL
+		fed_metadata_context_set_token_signing_key(
+				fed_metadata_context_t *metadata_context,
+				axis2_char_t *signing_key,
+				const axutil_env_t *env);
+
+		/* Set function pointers */
+	AXIS2_EXTERN void AXIS2_CALL
+		fed_metadata_context_set_process_token_key_signing_info_fp(
+				fed_metadata_context_t *metadata_context,
+				void *processing_logic_fp,
+				const axutil_env_t *env);
+	
+	AXIS2_EXTERN void AXIS2_CALL
+		fed_metadata_context_set_build_token_key_signing_info_fp(
+				fed_metadata_context_t *metadata_context,
+				void *build_logic_fp,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN void AXIS2_CALL
+		fed_metadata_context_set_process_token_key_transfer_key_info_fp(
+				fed_metadata_context_t *metadata_context,
+				void *processing_logic_fp,
+				const axutil_env_t *env);
+
+	AXIS2_EXTERN void AXIS2_CALL
+		fed_metadata_context_set_build_token_key_transfer_key_info_fp(
+				fed_metadata_context_t *metadata_context,
+				void *build_logic_fp,
+				const axutil_env_t *env);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FED_METADATA_CONTEXT_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: webservices/rampart/scratch/c/fed/c/src/fed/fed_metadata.c
URL: http://svn.apache.org/viewvc/webservices/rampart/scratch/c/fed/c/src/fed/fed_metadata.c?rev=628127&view=auto
==============================================================================
--- webservices/rampart/scratch/c/fed/c/src/fed/fed_metadata.c (added)
+++ webservices/rampart/scratch/c/fed/c/src/fed/fed_metadata.c Fri Feb 15 09:27:50 2008
@@ -0,0 +1,950 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * 		http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+*/
+
+#include "fed_metadata_context.h"
+
+struct fed_metadata_context
+{
+	/* Metadata Context Node . full node for a single federation*/
+	axiom_node_t *metadata_context_node;
+
+	/* Federation ID : unique for a given federation*/
+	axis2_char_t *federation_id;
+
+	/* The key that is used to sign the tokens issued by the metadata owner*/
+	axiom_node_t *token_signing_key_info_node;
+	axis2_char_t *token_signing_key;
+
+	/* The key that is used to encrypt key and key materials*/
+	axiom_node_t *token_key_transfer_key_info_node;
+	axis2_char_t *token_key_transfer_key;
+
+	/*Token issuers logical name*/
+	axis2_char_t *token_issuer_name;
+
+	/* Indicate a set logical names associated with the issuer*/
+	axutil_array_list_t *issuer_names_offered_list;
+
+	/* Allows a federation metadata provider to specify the end point [STS] that can be used to 
+	 * get sec tokens to consume metadata provider*/
+	axis2_char_t *token_issuer_end_point;
+
+	/* Allows a federation metadata provider to specify the end point address of the pseudonym service */
+	axis2_char_t *pseudonym_service_end_point;
+
+	/* Allows a federation metadata provider to specify the end point address of the attribute service */
+	axis2_char_t *attribute_service_end_point;
+
+	/* Allows a federation metadata provider to specify the end point address of its subscription service that is used to subscribe to 
+	 * fed sign out*/
+	axis2_char_t *single_signout_subscription_end_point;
+
+	/* Allows a federation metadata provider to specify the endpoint address to which push notifications of sign-out are to be sent*/
+	axis2_char_t *single_signout_notification_end_point;
+
+	/* Allows a metadata provider to specify the list of token types offered by its sts */
+	axutil_array_list_t *token_types_offered_list;
+
+
+	/* Allows a metadata provider to specify list of publicly offered claim types that can be asserted in sec tokens issued by its STS */
+	axutil_array_list_t *uri_named_claim_types_offered_list; /* Set of axiom_nodes - <ClaimType URI="id"> <DisplayName><Description> ...*/
+
+	/* xs:boolean */
+	int automatic_pseudonyms_element;
+
+
+	/* Generic Implementations for various key types e.g. x509, RSA etc*/
+	/* Function pointers*/
+
+	/* TokenSigningKey : fp*/
+		/*Extract Key*/
+	axis2_char_t* (AXIS2_CALL *extract_token_signing_key) (fed_metadata_context_t *metadata_context, const axutil_env_t * env);
+		/*Build OM*/
+	axiom_node_t* (AXIS2_CALL *build_token_signing_info) (fed_metadata_context_t *metadata_context, axis2_char_t *token_signing_key, const axutil_env_t * env);
+
+	/*TokenKeyTransferKey : fp*/
+		/*Extract Key*/
+	axis2_char_t* (AXIS2_CALL *extract_token_key_transfer_key_info) (fed_metadata_context_t *metadata_context, const axutil_env_t * env);
+		/* Build OM*/
+	axiom_node_t* (AXIS2_CALL *build_token_key_transfer_key_info) (fed_metadata_context_t *metadata_context, 
+			axis2_char_t *token_key_transfer_key, const axutil_env_t * env);
+
+};
+
+AXIS2_EXTERN fed_metadata_context_t* AXIS2_CALL
+fed_metadata_context_create(
+		axiom_node_t *metadata_node,
+		const axutil_env_t * env)
+{
+	fed_metadata_context_t *metadata_context = NULL;
+	AXIS2_ENV_CHECK(env, NULL);
+
+	metadata_context = (fed_metadata_context_t *) AXIS2_MALLOC(env->allocator, sizeof(fed_metadata_context_t));
+
+        
+	if(!metadata_context)
+	{
+		return NULL;
+	}
+	/*Initializations*/
+	metadata_context->metadata_context_node = metadata_node;
+	metadata_context->extract_token_signing_key = NULL;
+	metadata_context->build_token_signing_info = NULL;
+	metadata_context->extract_token_key_transfer_key_info = NULL;
+	metadata_context->build_token_key_transfer_key_info = NULL;
+        metadata_context->single_signout_notification_end_point = NULL;
+        metadata_context->single_signout_subscription_end_point = NULL;
+        
+        
+
+	/* Create Array List*/
+	metadata_context->token_types_offered_list = axutil_array_list_create(env, 5);
+	metadata_context->issuer_names_offered_list = axutil_array_list_create(env, 5);
+	metadata_context->uri_named_claim_types_offered_list = axutil_array_list_create(env, 5);
+
+	return metadata_context;
+}
+
+AXIS2_EXTERN void AXIS2_CALL
+fed_metadata_context_free(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t * env)
+{
+	AXIS2_ENV_CHECK(env, void);
+
+	if(metadata_context)
+	{
+		AXIS2_FREE(env->allocator, metadata_context);
+	}
+}
+
+AXIS2_EXTERN axis2_status_t AXIS2_CALL
+fed_metadata_context_populate_metadata(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t * env)
+{
+	/*Metadata Context*/
+	axiom_element_t *metadata_context_element = NULL;
+	
+	/*TokenSigningKeyInfo*/
+	axiom_node_t *token_signing_key_info_node = NULL;
+	axiom_element_t *token_signing_key_info_element = NULL;
+	axutil_qname_t *token_signing_key_info_qname = NULL;
+
+	/*TokenSigningKeyTransferKeyInfo*/
+	axiom_node_t *token_key_transfer_key_info_node = NULL;
+	axiom_element_t *token_key_transfer_key_info_element = NULL;
+	axutil_qname_t *token_key_transfer_key_info_qname = NULL;
+
+	/*IssuerName*/
+	axiom_node_t *token_issuer_name_node = NULL;
+	axiom_element_t *token_issuer_name_element = NULL;
+	axutil_qname_t *token_issuer_name_qname = NULL;
+
+	/*TokenIssuerEndpoint*/
+	axiom_node_t *token_issuer_endpoint_node = NULL;
+	axiom_element_t *token_issuer_endpoint_element = NULL;
+	axutil_qname_t *token_issuer_endpoint_qname = NULL;
+	axutil_qname_t *token_issuer_endpoint_addr_qname = NULL;
+	axiom_node_t *token_issuer_endpoint_addr_node = NULL;
+	axiom_element_t *token_issuer_endpoint_addr_element = NULL;
+
+        /*SingleSignOutSubscriptionEndpoint*/
+        axiom_node_t *sso_subscription_endpoint_node = NULL;
+        axiom_element_t *sso_subscription_endpoint_element = NULL;
+        axutil_qname_t *sso_subscription_endpoint_qname = NULL;
+        axutil_qname_t *sso_subscription_endpoint_addr_qname = NULL;
+        axiom_node_t *sso_subscription_endpoint_addr_node = NULL;
+        axiom_element_t *sso_subscription_endpoint_addr_element = NULL;
+
+        /*SingleSignOutNotificationEndPoint*/
+        axiom_node_t *sso_notification_endpoint_node = NULL;
+        axiom_element_t *sso_notification_endpoint_element = NULL;
+        axutil_qname_t *sso_notification_endpoint_qname = NULL;
+        axutil_qname_t *sso_notification_endpoint_addr_qname = NULL;
+        axiom_node_t *sso_notification_endpoint_addr_node = NULL;
+        axiom_element_t *sso_notification_endpoint_addr_element = NULL;
+
+        /*PseudonymServiceEndpoint*/
+        axiom_node_t *pseudonym_service_endpoint_node = NULL;
+        axiom_element_t *pseudonym_service_endpoint_element = NULL;
+        axutil_qname_t *pseudonym_service_endpoint_qname = NULL;
+        axutil_qname_t *pseudonym_service_endpoint_addr_qname = NULL;
+        axiom_node_t *pseudonym_service_endpoint_addr_node = NULL;
+        axiom_element_t *pseudonym_service_endpoint_addr_element = NULL;
+
+        /*AttributeServiceEndpoint*/
+        axiom_node_t *attribute_service_endpoint_node = NULL;
+        axiom_element_t *attribute_service_endpoint_element = NULL;
+        axutil_qname_t *attribute_service_endpoint_qname = NULL;
+        axutil_qname_t *attribute_service_endpoint_addr_qname = NULL;
+        axiom_node_t *attribute_service_endpoint_addr_node = NULL;
+        axiom_element_t *attribute_service_endpoint_addr_element = NULL;
+        
+
+	/*TokenTypesOffered*/
+	axiom_node_t *token_types_offered_node = NULL;
+	axiom_element_t *token_types_offered_element = NULL;
+	axutil_qname_t *token_types_offered_qname = NULL;
+	axiom_children_qname_iterator_t *token_types_offered_qname_iter = NULL;
+	axutil_qname_t *token_type_qname = NULL;
+	axiom_node_t *token_type_node = NULL;
+	axiom_element_t *token_type_element = NULL;
+	axutil_qname_t *token_type_uri_attr_qname = NULL;
+
+	/*IssuerNamedOffered*/
+	axiom_node_t *issuer_names_offered_node = NULL;
+	axiom_element_t *issuer_names_offered_element = NULL;
+	axutil_qname_t *issuer_names_offered_qname = NULL;
+	axiom_children_qname_iterator_t *issuer_names_offered_qname_iter = NULL;
+	axutil_qname_t *issuer_name_qname = NULL;
+	axiom_node_t *issuer_name_node = NULL;
+	axiom_element_t *issuer_name_element = NULL;
+	axutil_qname_t *issuer_name_uri_attr_qname = NULL;
+
+	/*UriNamedClaimTypesOffered*/
+	axiom_node_t *uri_named_claim_types_offered_node = NULL;
+	axiom_element_t *uri_named_claim_types_offered_element = NULL;
+	axutil_qname_t *uri_named_claim_types_offered_qname = NULL;
+	axiom_children_qname_iterator_t *uri_named_claim_types_qname_iter = NULL;
+	fed_metadata_claim_type_t *uri_named_claim_type = NULL;
+
+
+
+
+	AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
+
+	if(metadata_context->metadata_context_node)
+	{
+                metadata_context_element = (axiom_element_t *) 
+			(axiom_node_get_data_element(metadata_context->metadata_context_node, env));
+
+		/*Get Federation ID*/
+                metadata_context->federation_id = axiom_element_get_attribute_value_by_name( metadata_context_element, env,
+				                                    FED_ATTR_FED_ID);
+
+		
+		/*TokenKeySigningInfo*/
+		token_signing_key_info_qname = axutil_qname_create(env, FED_TOKEN_SIGNING_KEY_INFO, 
+				FED_FED_XML_NS, FED_WSF);
+		token_signing_key_info_element = axiom_element_get_first_child_with_qname(metadata_context_element, 
+				env, token_signing_key_info_qname, metadata_context->metadata_context_node, &token_signing_key_info_node);
+			/* Set TokenSigningInfoNode */
+		metadata_context->token_signing_key_info_node = token_signing_key_info_node;
+			/* Process TokenSigningInfoNode and extract the key : using call back fn*/
+		if(metadata_context->extract_token_signing_key)
+		{
+			/*Set Key value*/
+			metadata_context->token_signing_key = metadata_context->extract_token_signing_key(metadata_context, env);
+		}
+
+		/*TokenKeyTransferKeyInfo*/
+		token_key_transfer_key_info_qname = axutil_qname_create(env, FED_TOKEN_KEY_TRANSFER_KEY_INFO, 
+				                FED_FED_XML_NS, FED_WSF);
+		token_key_transfer_key_info_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				 env, token_key_transfer_key_info_qname,
+				 metadata_context->metadata_context_node, &token_key_transfer_key_info_node);
+		metadata_context->token_key_transfer_key_info_node = token_key_transfer_key_info_node;
+
+		if(metadata_context->extract_token_key_transfer_key_info)
+		{
+			metadata_context->token_key_transfer_key = metadata_context->extract_token_key_transfer_key_info(
+					metadata_context, env);
+		}
+
+		/*TokenIssuerName*/
+		token_issuer_name_qname = axutil_qname_create(env, FED_TOKEN_ISSUER_NAME, FED_FED_XML_NS, FED_WSF);
+		token_issuer_name_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				env, token_issuer_name_qname, metadata_context->metadata_context_node, &token_issuer_name_node);
+		if (token_issuer_name_node)
+		{
+			metadata_context->token_issuer_name = axiom_element_get_text(token_issuer_name_element, 
+					env, token_issuer_name_node);
+		}
+
+		/*TokenIssuerEndpoint*/
+		token_issuer_endpoint_qname = axutil_qname_create(env, FED_TOKEN_ISSUER_END_POINT, FED_FED_XML_NS, FED_WSF);
+		token_issuer_endpoint_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				env, token_issuer_endpoint_qname, metadata_context->metadata_context_node, &token_issuer_endpoint_node);
+		if (token_issuer_endpoint_node)
+		{
+			
+			token_issuer_endpoint_addr_qname = axutil_qname_create(env, FED_WSA_ADDRESS, FED_WSA_XMLNS, FED_WSA);
+			token_issuer_endpoint_addr_element = axiom_element_get_first_child_with_qname(token_issuer_endpoint_element,
+					env, token_issuer_endpoint_addr_qname, token_issuer_endpoint_node, &token_issuer_endpoint_addr_node);
+
+			metadata_context->token_issuer_end_point = axiom_element_get_text(token_issuer_endpoint_addr_element, 
+				env, token_issuer_endpoint_addr_node); 
+		}
+
+
+		/*PseudonymServiceEndpoint*/
+                
+
+		/*AttributeServiceEndpoint*/
+
+		/*SingleSignOutSubscripionEndpoint*/
+                sso_subscription_endpoint_qname = axutil_qname_create(env, FED_SINGLE_SIGNOUT_SUBSCRIPTION_END_POINT,
+                                                                        FED_FED_XML_NS, FED_WSF);
+                sso_subscription_endpoint_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				env, sso_subscription_endpoint_qname, metadata_context->metadata_context_node, &sso_subscription_endpoint_node);
+                if(sso_subscription_endpoint_node)
+                {
+                    sso_subscription_endpoint_addr_qname = axutil_qname_create(env, FED_WSA_ADDRESS, FED_WSA_XMLNS, FED_WSA);
+                    sso_subscription_endpoint_addr_element = axiom_element_get_first_child_with_qname(sso_subscription_endpoint_element,
+					env, sso_subscription_endpoint_addr_qname, sso_subscription_endpoint_node, &sso_subscription_endpoint_addr_node);
+                    metadata_context->single_signout_subscription_end_point = axiom_element_get_text(sso_subscription_endpoint_addr_element, 
+				env, sso_subscription_endpoint_addr_node);
+                }
+                
+                
+		/*SingleSignOutNotificationEndpoint*/
+                sso_notification_endpoint_qname = axutil_qname_create(env, FED_SINGLE_SIGNOUT_NOTIFICATION_END_POINT,
+                                                                        FED_FED_XML_NS, FED_WSF);
+                sso_notification_endpoint_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				env, sso_notification_endpoint_qname, metadata_context->metadata_context_node, &sso_notification_endpoint_node);
+                if(sso_notification_endpoint_node)
+                {
+                    sso_notification_endpoint_addr_qname = axutil_qname_create(env, FED_WSA_ADDRESS, FED_WSA_XMLNS, FED_WSA);
+                    sso_notification_endpoint_addr_element = axiom_element_get_first_child_with_qname(sso_notification_endpoint_element,
+					env, sso_notification_endpoint_addr_qname, sso_notification_endpoint_node, &sso_notification_endpoint_addr_node);
+                    metadata_context->single_signout_notification_end_point = axiom_element_get_text(sso_notification_endpoint_addr_element, 
+				env, sso_notification_endpoint_addr_node);
+                }
+
+
+		/*TokenTypesOffered*/
+		token_types_offered_qname = axutil_qname_create(env, FED_TOKEN_TYPES_OFFERED, FED_FED_XML_NS, FED_WSF);
+		token_types_offered_element = axiom_element_get_first_child_with_qname(metadata_context_element,
+				env, token_types_offered_qname, metadata_context->metadata_context_node, &token_types_offered_node);
+		
+		if(token_types_offered_node)
+		{
+			token_type_qname = axutil_qname_create(env, FED_TOKEN_TYPE, FED_FED_XML_NS, FED_WSF);
+			token_types_offered_qname_iter =  axiom_element_get_children_with_qname(token_types_offered_element, 
+					env, token_type_qname, token_types_offered_node);
+
+			while(axiom_children_qname_iterator_has_next(token_types_offered_qname_iter, env))
+			{
+				token_type_node = axiom_children_qname_iterator_next(token_types_offered_qname_iter, env);
+				
+				if(axiom_node_get_node_type(token_type_node, env) == AXIOM_ELEMENT)
+				{
+					token_type_element = axiom_node_get_data_element(token_type_node, env);
+
+					if(token_type_element)
+					{
+						token_type_uri_attr_qname = axutil_qname_create(env, 
+								FED_ATTR_TOKEN_TYPE_URI, FED_FED_XML_NS, FED_WSF);
+						axutil_array_list_add(metadata_context->token_types_offered_list, env, 
+								axiom_element_get_attribute_value_by_name( token_type_element, env,
+									FED_ATTR_TOKEN_TYPE_URI));
+					}
+
+				}	
+			}
+			
+		}
+
+		/*IssuerNamesOffered*/
+		issuer_names_offered_qname = axutil_qname_create(env, FED_ISSER_NAMES_OFFERED, FED_FED_XML_NS, FED_WSF);
+		issuer_names_offered_element = axiom_element_get_first_child_with_qname(metadata_context_element, 
+				env, issuer_names_offered_qname, metadata_context->metadata_context_node, &issuer_names_offered_node);
+		if(issuer_names_offered_node)
+		{
+			issuer_name_qname = axutil_qname_create(env, FED_ISSER_NAMES_OFFERED_ISSUER_NAME, FED_FED_XML_NS, FED_WSF);
+			issuer_names_offered_qname_iter = axiom_element_get_children_with_qname(issuer_names_offered_element, 
+					env, issuer_name_qname, issuer_names_offered_node);
+			while(axiom_children_qname_iterator_has_next(issuer_names_offered_qname_iter, env))
+			{
+				issuer_name_node = axiom_children_qname_iterator_next(issuer_names_offered_qname_iter, env);
+				if(axiom_node_get_node_type(issuer_name_node, env) == AXIOM_ELEMENT)
+				{
+					issuer_name_element = axiom_node_get_data_element(issuer_name_node, env);
+					if(issuer_name_element)
+					{
+						issuer_name_uri_attr_qname =  axutil_qname_create(env, 
+							FED_ATTR_URI, FED_FED_XML_NS, FED_WSF);
+						axutil_array_list_add(metadata_context->issuer_names_offered_list, env, 
+							axiom_element_get_attribute_value_by_name( issuer_name_element, env,
+								FED_ATTR_URI));
+					}
+				}
+			}
+		}
+
+		/*UriNamedClaimTypesOffered*/
+		uri_named_claim_types_offered_qname = axutil_qname_create(env, FED_URI_NAMED_CLAIM_TYPES_OFFERED,
+				FED_FED_XML_NS, FED_WSF);
+		uri_named_claim_types_offered_element = axiom_element_get_first_child_with_qname(metadata_context_element, 
+				env, uri_named_claim_types_offered_qname, metadata_context->metadata_context_node, 
+				&uri_named_claim_types_offered_node);
+
+		if(uri_named_claim_types_offered_node)
+		{
+			axiom_node_t *claim_type_node = NULL;
+			axiom_element_t *claim_type_element = NULL;
+			axiom_node_t *display_name_node = NULL;
+			axiom_element_t *display_name_element = NULL;
+			axiom_node_t *description_node = NULL;
+			axiom_element_t *description_element = NULL;
+			axutil_qname_t *claim_type_qname = NULL;
+			axutil_qname_t *claim_type_uri_attr_qname = NULL;
+			axutil_qname_t *display_name_qname = NULL;
+			axutil_qname_t *description_qname = NULL;
+
+			/*creating claim type object*/
+			uri_named_claim_types_offered_qname = axutil_qname_create(env, FED_URI_NAMED_CLAIM_TYPES_OFFERED, 
+					FED_FED_XML_NS, FED_WSF);
+			
+			claim_type_qname = axutil_qname_create(env, FED_URI_NAMED_CLAIM_TYPE, FED_FED_XML_NS, FED_WSF);
+
+			uri_named_claim_types_qname_iter = axiom_element_get_children_with_qname(
+					uri_named_claim_types_offered_element,
+					env, claim_type_qname, uri_named_claim_types_offered_node);
+			
+			/*Iterating through the claim type elements */
+			while(axiom_children_qname_iterator_has_next(uri_named_claim_types_qname_iter, env))
+			{
+				claim_type_node = axiom_children_qname_iterator_next(uri_named_claim_types_qname_iter, env);
+				if(axiom_node_get_node_type(claim_type_node, env) == AXIOM_ELEMENT)
+				{
+					claim_type_element = axiom_node_get_data_element(claim_type_node, env);
+					if(claim_type_element)
+					{
+						/*Creating Claim Type object*/
+						uri_named_claim_type = AXIS2_MALLOC(env->allocator, sizeof(fed_metadata_claim_type_t));
+						uri_named_claim_type->claim_type_uri_attr = NULL;
+						uri_named_claim_type->display_name = NULL;
+						uri_named_claim_type->description = NULL;
+
+						if(uri_named_claim_type)
+						{
+							/*Processing The Uri Attribute*/
+							claim_type_uri_attr_qname =  axutil_qname_create(env, FED_ATTR_URI, FED_FED_XML_NS, FED_WSF);
+							uri_named_claim_type->claim_type_uri_attr =  axiom_element_get_attribute_value_by_name( 
+																			claim_type_element, env,
+																						FED_ATTR_URI);
+							/*Processing DisplayName element*/
+							display_name_qname = axutil_qname_create(env, FED_URI_NAMED_CLAIM_TYPE_DISPLAY_NAME, 
+									FED_FED_XML_NS, FED_WSF);
+							display_name_element = axiom_element_get_first_child_with_qname(claim_type_element,
+									env, display_name_qname, 
+									claim_type_node, &display_name_node);
+							if(display_name_node)
+							{
+								uri_named_claim_type->display_name = axiom_element_get_text(display_name_element,
+																							env, display_name_node);
+							}
+
+							/*Processing Description element*/
+							description_qname = axutil_qname_create(env, FED_URI_NAMED_CLAIM_TYPE_DESCRIPTION, 
+									FED_FED_XML_NS, FED_WSF);
+							description_element = axiom_element_get_first_child_with_qname(claim_type_element,
+									env, description_qname, claim_type_node, &description_node);
+							if(description_node)
+							{
+								uri_named_claim_type->description = axiom_element_get_text(description_element,
+										                                            env, description_node);
+							}
+
+							/*Add UriClaimType object to the UriNamedClaimType list*/
+							axutil_array_list_add(metadata_context->uri_named_claim_types_offered_list, env, 
+									uri_named_claim_type);
+
+						}
+
+					}
+				}
+			}
+		}
+	}
+}
+
+
+/*Build FED Context OM*/
+AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+fed_metadata_context_build_metadata_om(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	axiom_node_t *federation_node = NULL;
+	axiom_element_t *federation_element = NULL;
+	axiom_namespace_t *wsf_ns = NULL;
+	axiom_attribute_t *fed_id_attr = NULL;
+
+	axiom_node_t *token_issuer_name_node = NULL;
+	axiom_element_t *token_issuer_name_element = NULL;
+
+	axiom_node_t *token_issuer_endpoint_node = NULL;
+	axiom_element_t *token_issuer_endpoint_element = NULL;
+	axiom_node_t *token_issuer_endpoint_addr_node = NULL;
+	axiom_element_t *token_issuer_endpoint_addr_element = NULL;
+	axiom_namespace_t *wsa_ns = NULL;
+
+	axiom_node_t *token_types_offered_node = NULL;
+	axiom_element_t *token_types_offered_element = NULL;
+
+	axiom_node_t *issuer_names_offered_node = NULL;
+	axiom_element_t *issuer_names_offered_element = NULL;
+
+	axiom_node_t *uri_named_claim_types_offered_node = NULL;
+	axiom_element_t *uri_named_claim_types_offered_element = NULL;
+	
+	AXIS2_ENV_CHECK(env, NULL);
+	
+	if(metadata_context->federation_id)
+	{
+		wsf_ns = axiom_namespace_create(env, FED_FED_XML_NS, FED_WSF);
+		federation_element = axiom_element_create(env, NULL, FED_FEDERATION, wsf_ns, &federation_node);
+		fed_id_attr = axiom_attribute_create(env, FED_ATTR_FED_ID, metadata_context->federation_id, NULL);
+		axiom_element_add_attribute(federation_element, env, fed_id_attr, federation_node);
+
+		/*Token Key Signing Info*/
+		if(metadata_context->token_signing_key)
+		{
+			if(metadata_context->build_token_signing_info)
+			{
+				axiom_node_t *token_siging_info_node = NULL;
+				/*Callback function to create the token signing key element*/
+				token_siging_info_node =metadata_context->build_token_signing_info(metadata_context, 
+						(axis2_char_t*)metadata_context->token_signing_key, env);
+			
+				if(token_siging_info_node)
+					axiom_node_add_child(federation_node, env, token_siging_info_node);
+			}
+		}
+
+		/*TokenIssuerName*/
+		if(metadata_context->token_issuer_name)
+		{
+			token_issuer_name_element = axiom_element_create(env, federation_node, FED_TOKEN_ISSUER_NAME, 
+					wsf_ns, &token_issuer_name_node);
+			axiom_element_set_text(token_issuer_name_element, env, 
+					metadata_context->token_issuer_name, token_issuer_name_node);
+		}
+
+		/*TokenIssuerEndPoint*/
+		if(metadata_context->token_issuer_end_point)
+		{
+			token_issuer_endpoint_element = axiom_element_create(env, federation_node, FED_TOKEN_ISSUER_END_POINT, 
+					wsf_ns, &token_issuer_endpoint_node);
+
+			wsa_ns = axiom_namespace_create(env, FED_WSA_XMLNS, FED_WSA);
+
+			token_issuer_endpoint_addr_element = axiom_element_create(env, token_issuer_endpoint_node,
+					FED_WSA_ADDRESS, wsa_ns, &token_issuer_endpoint_addr_node);
+			axiom_element_set_text(token_issuer_endpoint_addr_element, env, metadata_context->token_issuer_end_point,
+					token_issuer_endpoint_addr_node);
+		}
+
+		/*TokenTypesOffered*/
+		if(metadata_context->token_types_offered_list)
+		{
+			axiom_node_t *token_type_node = NULL;
+			axiom_element_t *token_type_element = NULL;
+			axiom_attribute_t *token_type_uri_attr = NULL;
+			int list_size = 0;
+			int index = 0;
+
+			list_size = axutil_array_list_size( metadata_context->token_types_offered_list, env);
+			
+			token_types_offered_element = axiom_element_create(env, federation_node, FED_TOKEN_TYPES_OFFERED,
+					wsf_ns, &token_types_offered_node);
+			for(index = 0; index < list_size; index++)
+			{
+				token_type_element = axiom_element_create(env, token_types_offered_node, FED_TOKEN_TYPE, 
+						wsf_ns, &token_type_node);
+				token_type_uri_attr = axiom_attribute_create(env, FED_ATTR_TOKEN_TYPE_URI,
+						(axis2_char_t*)axutil_array_list_get(metadata_context->token_types_offered_list, env, index), 
+						wsf_ns);
+				axiom_element_add_attribute(token_type_element, env, token_type_uri_attr, token_type_node);
+			}
+
+			
+		}
+
+		/* IssuerNamesOffered*/
+		if(metadata_context->issuer_names_offered_list)
+		{
+			axiom_node_t *issuer_name_node = NULL;
+			axiom_element_t *issuer_name_element = NULL;
+			axiom_attribute_t *issuer_name_uri_attr = NULL;
+			int list_size = 0;
+			int index = 0;
+
+			list_size = axutil_array_list_size( metadata_context->issuer_names_offered_list, env);
+			issuer_names_offered_element = axiom_element_create(env, federation_node, FED_ISSER_NAMES_OFFERED,
+					                    wsf_ns, &issuer_names_offered_node);
+			for(index = 0; index < list_size; index++)
+			{
+				issuer_name_element = axiom_element_create(env, issuer_names_offered_node, 
+						FED_ISSER_NAMES_OFFERED_ISSUER_NAME,
+						wsf_ns, &issuer_name_node);
+				issuer_name_uri_attr = axiom_attribute_create(env, 
+						FED_ATTR_URI,
+						(axis2_char_t*)axutil_array_list_get(metadata_context->issuer_names_offered_list, env, index),
+						NULL);
+				axiom_element_add_attribute(issuer_name_element, env, issuer_name_uri_attr, issuer_name_node);
+			}
+		}
+
+		/*UriNamedClaimTypes*/
+		if(metadata_context->uri_named_claim_types_offered_list)
+		{
+			fed_metadata_claim_type_t *uri_named_claim_type;
+			axiom_node_t *claim_type_node = NULL;
+			axiom_element_t *claim_type_element = NULL;
+			axiom_attribute_t *claim_type_uri_attr = NULL;
+			axiom_node_t *display_name_node = NULL;
+			axiom_element_t *display_name_element = NULL;
+			axiom_node_t *description_node = NULL;
+			axiom_element_t *description_element = NULL;
+			int list_size = 0;
+			int index = 0;
+
+
+			list_size = axutil_array_list_size( metadata_context->uri_named_claim_types_offered_list, env);
+			uri_named_claim_types_offered_element =  axiom_element_create(env, federation_node, 
+					FED_URI_NAMED_CLAIM_TYPES_OFFERED,
+					wsf_ns, &uri_named_claim_types_offered_node);
+			for(index = 0; index < list_size; index++)
+			{
+				claim_type_element = axiom_element_create(env, uri_named_claim_types_offered_node,
+						FED_URI_NAMED_CLAIM_TYPE,
+						wsf_ns, &claim_type_node);
+
+				uri_named_claim_type = (fed_metadata_claim_type_t*)axutil_array_list_get(
+						metadata_context->uri_named_claim_types_offered_list, env, index);
+				if(uri_named_claim_type)
+				{
+					if(uri_named_claim_type->claim_type_uri_attr)
+					{
+						claim_type_uri_attr = axiom_attribute_create(env, FED_ATTR_URI, 
+								uri_named_claim_type->claim_type_uri_attr, NULL);
+						axiom_element_add_attribute(claim_type_element, env, claim_type_uri_attr, claim_type_node);
+					}
+					if(uri_named_claim_type->display_name)
+					{
+						display_name_element = axiom_element_create(env, claim_type_node, FED_URI_NAMED_CLAIM_TYPE_DISPLAY_NAME,
+								wsf_ns, &display_name_node);
+						axiom_element_set_text(display_name_element, env,
+								                    uri_named_claim_type->display_name, display_name_node);
+					}
+					if(uri_named_claim_type->description)
+					{
+						description_element = axiom_element_create(env, claim_type_node, FED_URI_NAMED_CLAIM_TYPE_DESCRIPTION,
+								                                wsf_ns, &description_node);
+						axiom_element_set_text(description_element, env,
+								uri_named_claim_type->description, description_node);
+
+					}
+				}
+
+			}
+		}
+	}
+	
+	if(!federation_element)
+	{
+		AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[fed]Build Fed Context Failed");
+		return NULL;
+	}
+
+	
+	return federation_node;
+
+}
+
+AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+fed_metadata_context_get_token_signing_key(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+		return metadata_context->token_signing_key;
+	return NULL;
+}
+
+AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+fed_metadata_context_get_federation_id(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->federation_id;
+	}
+	return NULL;
+
+}
+
+AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+fed_metadata_context_get_metadata_node(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->metadata_context_node;
+	}
+	return NULL;
+}
+
+
+
+AXIS2_EXTERN axis2_char_t* AXIS2_CALL
+fed_metadata_context_get_token_issuer_name(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->token_issuer_name;
+	}
+	return NULL;
+}
+
+AXIS2_EXTERN axutil_array_list_t* AXIS2_CALL
+fed_metadata_context_get_token_types_offered_list(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->token_types_offered_list;
+	}
+	return NULL;
+}
+
+AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+fed_metadata_context_get_token_signing_info_node(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->token_signing_key_info_node;
+	}
+}
+
+AXIS2_EXTERN axiom_node_t* AXIS2_CALL
+fed_metadata_context_get_token_key_transfer_key_info_node(
+		fed_metadata_context_t *metadata_context,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		return metadata_context->token_key_transfer_key_info_node;
+	}
+}
+
+
+
+/*Setters*/
+AXIS2_EXTERN void AXIS2_CALL
+fed_metadata_context_set_token_signing_key(
+		fed_metadata_context_t *metadata_context,
+		axis2_char_t *signing_key,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		metadata_context->token_signing_key = signing_key;
+		return;
+	}
+
+}
+
+
+	/*Set Function Pointers*/
+AXIS2_EXTERN void AXIS2_CALL
+fed_metadata_context_set_process_token_key_signing_info_fp(
+		fed_metadata_context_t *metadata_context,
+		void *processing_logic_fp,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		metadata_context->extract_token_signing_key = processing_logic_fp;
+		return;
+	}
+}
+
+AXIS2_EXTERN void AXIS2_CALL
+fed_metadata_context_set_build_token_key_signing_info_fp(
+		fed_metadata_context_t *metadata_context,
+		void *build_logic_fp,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		metadata_context->build_token_signing_info = build_logic_fp;
+	}
+}
+
+AXIS2_EXTERN void AXIS2_CALL
+fed_metadata_context_set_process_token_key_transfer_key_info_fp(
+		fed_metadata_context_t *metadata_context,
+		void *processing_logic_fp,
+		const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		metadata_context->extract_token_key_transfer_key_info = processing_logic_fp;
+	}
+}
+
+ AXIS2_EXTERN void AXIS2_CALL
+ fed_metadata_context_set_build_token_key_transfer_key_info_fp(
+		 fed_metadata_context_t *metadata_context,
+		 void *build_logic_fp,
+		 const axutil_env_t *env)
+{
+	if(metadata_context)
+	{
+		metadata_context->build_token_key_transfer_key_info = build_logic_fp;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+