From 12ae0cfc7f2cafb13bab1fe8e92ef430acdb149b Mon Sep 17 00:00:00 2001 From: erititan <elemer.lelik@ericsson.com> Date: Sat, 1 Aug 2015 09:25:44 +0200 Subject: [PATCH] Initial contribution --- README.md | 9 + demo/RADIUS_Demo_new.prj | 60 ++ demo/RADIUS_Demo_orig.prj | 60 ++ demo/RADIUS_Mapping_new.ttcn | 428 +++++++++ demo/RADIUS_Mapping_orig.ttcn | 427 +++++++++ demo/RADIUSandEAP.cfg | 21 + demo/RADIUSandEAP_Demo.prj | 59 ++ demo/RADIUSandEAP_Mapping.ttcn | 492 +++++++++++ demo/RadiusAndEAP_Demo.ttcn | 821 ++++++++++++++++++ demo/Radius_Test_new.ttcn | 606 +++++++++++++ demo/Radius_Test_orig.ttcn | 604 +++++++++++++ demo/gui_make_RPMG_new.sh | 33 + demo/gui_make_RPMG_orig.sh | 33 + demo/gui_make_RPMGandEAP.sh | 34 + demo/radius.cfg | 28 + ...rotocolModule_Generator_CNL113600_1551.doc | Bin 0 -> 355328 bytes ...ProtocolModule_Generator_CNL113600_PRI.doc | Bin 0 -> 84480 bytes src/ATTR.awk | 388 +++++++++ src/ATTR.sh | 107 +++ src/Accounting_IETF_RFC2866_RFC2867.rdf | 129 +++ src/BaseTypes_IETF_RFC2865.rdf | 137 +++ src/Base_IETF_RFC2865.rdf | 305 +++++++ src/ChargeableUserIdentity_IETF_RFC4372.rdf | 32 + src/Cisco.rdf | 133 +++ ...icAuthorizationExtensions_IETF_RFC5176.rdf | 66 ++ src/Extensions_IETF_RFC2869.rdf | 125 +++ src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf | 55 ++ src/IPv6_IETF_RFC3162.rdf | 64 ++ src/Juniper.rdf | 185 ++++ src/RADIUS_EncDec.cc | 299 +++++++ src/Scap.rdf | 161 ++++ src/Smartedge.rdf | 138 +++ src/TunnelAuthentication_IETF_RFC2868.rdf | 166 ++++ src/Vendor.rdf | 326 +++++++ src/Vendor_detailed_ericsson.rdf | 334 +++++++ src/obsolete/RadiusAccountingAttributes.rdf | 114 +++ src/obsolete/RadiusAndIPv6.rdf | 63 ++ src/obsolete/RadiusAuthExtensions.rdf | 63 ++ src/obsolete/RadiusBaseAttributes.rdf | 772 ++++++++++++++++ src/obsolete/RadiusBaseTypes.rdf | 92 ++ src/obsolete/RadiusExtensions.rdf | 124 +++ src/obsolete/RadiusGGSN.rdf | 54 ++ .../TunnelAuthenticationAttributes.rdf | 159 ++++ src/skt.rdf | 60 ++ 44 files changed, 8366 insertions(+) create mode 100644 README.md create mode 100644 demo/RADIUS_Demo_new.prj create mode 100644 demo/RADIUS_Demo_orig.prj create mode 100644 demo/RADIUS_Mapping_new.ttcn create mode 100644 demo/RADIUS_Mapping_orig.ttcn create mode 100644 demo/RADIUSandEAP.cfg create mode 100644 demo/RADIUSandEAP_Demo.prj create mode 100644 demo/RADIUSandEAP_Mapping.ttcn create mode 100644 demo/RadiusAndEAP_Demo.ttcn create mode 100644 demo/Radius_Test_new.ttcn create mode 100644 demo/Radius_Test_orig.ttcn create mode 100644 demo/gui_make_RPMG_new.sh create mode 100644 demo/gui_make_RPMG_orig.sh create mode 100644 demo/gui_make_RPMGandEAP.sh create mode 100644 demo/radius.cfg create mode 100644 doc/RADIUS_ProtocolModule_Generator_CNL113600_1551.doc create mode 100644 doc/RADIUS_ProtocolModule_Generator_CNL113600_PRI.doc create mode 100644 src/ATTR.awk create mode 100644 src/ATTR.sh create mode 100644 src/Accounting_IETF_RFC2866_RFC2867.rdf create mode 100644 src/BaseTypes_IETF_RFC2865.rdf create mode 100644 src/Base_IETF_RFC2865.rdf create mode 100644 src/ChargeableUserIdentity_IETF_RFC4372.rdf create mode 100644 src/Cisco.rdf create mode 100644 src/DynamicAuthorizationExtensions_IETF_RFC5176.rdf create mode 100644 src/Extensions_IETF_RFC2869.rdf create mode 100644 src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf create mode 100644 src/IPv6_IETF_RFC3162.rdf create mode 100644 src/Juniper.rdf create mode 100644 src/RADIUS_EncDec.cc create mode 100644 src/Scap.rdf create mode 100644 src/Smartedge.rdf create mode 100644 src/TunnelAuthentication_IETF_RFC2868.rdf create mode 100644 src/Vendor.rdf create mode 100644 src/Vendor_detailed_ericsson.rdf create mode 100644 src/obsolete/RadiusAccountingAttributes.rdf create mode 100644 src/obsolete/RadiusAndIPv6.rdf create mode 100644 src/obsolete/RadiusAuthExtensions.rdf create mode 100644 src/obsolete/RadiusBaseAttributes.rdf create mode 100644 src/obsolete/RadiusBaseTypes.rdf create mode 100644 src/obsolete/RadiusExtensions.rdf create mode 100644 src/obsolete/RadiusGGSN.rdf create mode 100644 src/obsolete/TunnelAuthenticationAttributes.rdf create mode 100644 src/skt.rdf diff --git a/README.md b/README.md new file mode 100644 index 0000000..9262aac --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# titan.ProtocolModules.RADIUS_ProtocolModule_Generator + +Main project page: + +https://projects.eclipse.org/projects/tools.titan + +The source code of the TTCN-3 compiler and executor: + +https://github.com/eclipse/titan.core diff --git a/demo/RADIUS_Demo_new.prj b/demo/RADIUS_Demo_new.prj new file mode 100644 index 0000000..f50fac9 --- /dev/null +++ b/demo/RADIUS_Demo_new.prj @@ -0,0 +1,60 @@ +<!DOCTYPE TITAN_GUI_project_file> +<Project TITAN_version="1.8.pl2" > + <General> + <Project_Name>RADIUS_Demo_new</Project_Name> + <Executable_Path>myTest</Executable_Path> + <Working_Dir>.</Working_Dir> + <Build_Host>alpha</Build_Host> + <Execution_Mode>Parallel</Execution_Mode> + <Code_Splitting_Mode>None</Code_Splitting_Mode> + <ScriptFile_AfterMake>gui_make_RPMG_new.sh</ScriptFile_AfterMake> + <Log_Format>yes</Log_Format> + <Update_Symlinks>yes</Update_Symlinks> + <Create_Absolute_Symlinks>no</Create_Absolute_Symlinks> + <Update_Makefile>yes</Update_Makefile> + <Localhost_Execute>yes</Localhost_Execute> + <Execute_Command>rsh %host "cd %project_working_dir ; "%executable" %localhost %mctr_port"</Execute_Command> + <Execute_Hosts>alfa, beta, gamma</Execute_Hosts> + <UnUsed_List></UnUsed_List> + </General> + <Modules> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PortType.ttcn</Module> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_Types.ttcn</Module> + <Module>RADIUS_Mapping_new.ttcn</Module> + <Module>Radius_Test_new.ttcn</Module> + </Modules> + <TestPorts> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.cc</TestPort> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.hh</TestPort> + </TestPorts> + <Other_Sources> + <Other_Source>../src/RADIUS_EncDec.cc</Other_Source> + </Other_Sources> + <Configs> + <Config>radius.cfg</Config> + </Configs> + <Test_Cases> + <Test_Case>Radius_Test_new.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_correct_auth</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_incorrect_auth</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_client_sendAccessRequest</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_client_sendAccessRequest_receiveAccessAccept</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_client_sendAccessAccept</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_client_sendAccountingRequest_receiveAccountingResponse</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_server_receiveAccessRequest_sendAccessChallenge</Test_Case> + <Test_Case>Radius_Test_new.tc_RADIUS_server_receiveAccountingRequest_sendAccountingResponse</Test_Case> + </Test_Cases> + <Others> + <Other>gui_make_RPMG_new.sh</Other> + <Other>../src/ATTR.awk</Other> + <Other>../src/IPv6_IETF_RFC3162.rdf</Other> + <Other>../src/Base_IETF_RFC2865.rdf</Other> + <Other>../src/BaseTypes_IETF_RFC2865.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/TunnelAuthentication_IETF_RFC2868.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf</Other> + <Other>../src/Accounting_IETF_RFC2866_RFC2867.rdf</Other> + </Others> + <File_Group name="MainFileGroup" /> +</Project> diff --git a/demo/RADIUS_Demo_orig.prj b/demo/RADIUS_Demo_orig.prj new file mode 100644 index 0000000..89b3aa2 --- /dev/null +++ b/demo/RADIUS_Demo_orig.prj @@ -0,0 +1,60 @@ +<!DOCTYPE TITAN_GUI_project_file> +<Project TITAN_version="1.8.pl2" > + <General> + <Project_Name>RADIUS_Demo_orig</Project_Name> + <Executable_Path>myTest</Executable_Path> + <Working_Dir>.</Working_Dir> + <Build_Host>alpha</Build_Host> + <Execution_Mode>Parallel</Execution_Mode> + <Code_Splitting_Mode>None</Code_Splitting_Mode> + <ScriptFile_AfterMake>gui_make_RPMG_orig.sh</ScriptFile_AfterMake> + <Log_Format>yes</Log_Format> + <Update_Symlinks>yes</Update_Symlinks> + <Create_Absolute_Symlinks>no</Create_Absolute_Symlinks> + <Update_Makefile>yes</Update_Makefile> + <Localhost_Execute>yes</Localhost_Execute> + <Execute_Command>rsh %host "cd %project_working_dir ; "%executable" %localhost %mctr_port"</Execute_Command> + <Execute_Hosts>alfa, beta, gamma</Execute_Hosts> + <UnUsed_List></UnUsed_List> + </General> + <Modules> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PortType.ttcn</Module> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_Types.ttcn</Module> + <Module>RADIUS_Mapping_orig.ttcn</Module> + <Module>Radius_Test_orig.ttcn</Module> + </Modules> + <TestPorts> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.cc</TestPort> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.hh</TestPort> + </TestPorts> + <Other_Sources> + <Other_Source>../src/RADIUS_EncDec.cc</Other_Source> + </Other_Sources> + <Configs> + <Config>radius.cfg</Config> + </Configs> + <Test_Cases> + <Test_Case>Radius_Test_orig.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_correct_auth</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_incorrect_auth</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_client_sendAccessRequest</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_client_sendAccessRequest_receiveAccessAccept</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_client_sendAccessAccept</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_client_sendAccountingRequest_receiveAccountingResponse</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_server_receiveAccessRequest_sendAccessChallenge</Test_Case> + <Test_Case>Radius_Test_orig.tc_RADIUS_server_receiveAccountingRequest_sendAccountingResponse</Test_Case> + </Test_Cases> + <Others> + <Other>gui_make_RPMG_orig.sh</Other> + <Other>../src/ATTR.awk</Other> + <Other>../src/IPv6_IETF_RFC3162.rdf</Other> + <Other>../src/Base_IETF_RFC2865.rdf</Other> + <Other>../src/BaseTypes_IETF_RFC2865.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/TunnelAuthentication_IETF_RFC2868.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf</Other> + <Other>../src/Accounting_IETF_RFC2866_RFC2867.rdf</Other> + </Others> + <File_Group name="MainFileGroup" /> +</Project> diff --git a/demo/RADIUS_Mapping_new.ttcn b/demo/RADIUS_Mapping_new.ttcn new file mode 100644 index 0000000..ba6f1e2 --- /dev/null +++ b/demo/RADIUS_Mapping_new.ttcn @@ -0,0 +1,428 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: RADIUS_Mapping_new.ttcn +// Description: Example module providing UDP Mapping for RPMG +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + + +module RADIUS_Mapping_new +{ + import from RADIUS_Types all; + import from UDPasp_Types all; + import from UDPasp_PortType all; + + modulepar{ + charstring tsp_SharedSecret := "sharedSecret" + } + + +type record ASP_UDP_RADIUS { + PDU_RADIUS data, + AddressType addressf, + PortType portf +} + +type port UDPasp_RADIUS_PT message { + + inout ASP_UDP_RADIUS +} with {extension "internal"} + + +type component RADIUS_mapping_CT { + + var RADIUS_port_descriptor v_RADIUS_port_descriptor; + + port UDPasp_RADIUS_PT UDP_RADIUS_PCO; // upper port + port UDPasp_PT UDP_PCO; // lower port + +} + +template ASP_UDP t_ASP_UDP := ?; +template ASP_UDP_RADIUS t_ASP_UDP_RADIUS := ?; + + + type record of vsa_descriptor vsa_descriptor_list; + + type record vsa_descriptor { + integer vendor_id, + integer_list subattr_types + } + +//================================================================ +// Types from RADIUS test port, info needed for external functions +//================================================================ +type record RADIUS_port_descriptor { + boolean global_keying, // if this is set to true, 256 will be used instead of EAP Identifier + charstring secret, + integer mode, + octetstring req_auth[256], + octetstring req_acct[256], + boolean debugging +} + +type record of integer integer_list; + +type enumerated generic_attrib_value_union_selection { + unbound, + text_val, + string_val, + address_val, + integer_val, + time_val +} + +type enumerated RADIUS_Mode {client, server}; + +//================================================================ +//================================================================ +//================================================================ + + +// Sending in Server mode +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// == Disconnect_Request == NOT HANDLED +function f_handle_outgoing_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Accept) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Reject) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Server mode!") } +} + +// Sending in Client mode +// -- Access_Request or +// -- Accounting_Request +// == Access_Challenge == NOT HANDLED +// == Disconnect_Ack == NOT HANDLED +// == Disconnect_Nak == NOT HANDLED +function f_handle_outgoing_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + { + // fill out authenticator with random number if template has 0s + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + var integer i; + for ( i := 0; i < 16; i := i+1) + { + pl_ASP_UDP_RADIUS.data.authenticator[i] := int2oct(float2int(int2float(256)*rnd()),1) + } + } + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + + // Calulate hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_User_Password) + { + var integer v_pw_len :=lengthof(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password); + var integer v_padding_length := 16 - (v_pw_len mod 16); + var octetstring v_padded_password := + +pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password & int2oct(0,v_padding_length) + var octetstring v_hidden_password := f_calculate_password( + v_padded_password, + pl_ASP_UDP_RADIUS.data.authenticator, + false + ); + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password := v_hidden_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + f_encode_send(pl_ASP_UDP_RADIUS); + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + pl_ASP_UDP_RADIUS.data.authenticator := f_calc_MD5(f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data) & char2oct(tsp_SharedSecret)); + } + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + f_encode_send(pl_ASP_UDP_RADIUS); + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Client mode!") } +} + + + +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// == Disconnect_Request == NOT HANDLED +function f_handle_incoming_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS, octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Accept) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Access_Reject) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Client mode") } +} + +// Access_Request or +// Accounting_Request +// == Access_Challenge == NOT HANDLED +// == Disconnect_Ack == NOT HANDLED +// == Disconnect_Nak == NOT HANDLED +function f_handle_incoming_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS,octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + + { + + // Calulate password from hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_User_Password) + { + var octetstring v_padded_password := f_calculate_password( + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password, + pl_ASP_UDP_RADIUS.data.authenticator, + true + ); + + var integer v_padding_length := 0; + while (v_padded_password[lengthof(v_padded_password) - v_padding_length - 1] == '00'O) + { + v_padding_length := v_padding_length + 1; + } + + var octetstring v_password:= substr (v_padded_password,0,lengthof(v_padded_password) - v_padding_length); + + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password := v_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & '00000000000000000000000000000000'O + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret) + ) + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Server mode")} +} + + +// Encrypts Password field in Access Request using Request Authentication +// field and shared secret (modulepar) +function f_calculate_password( octetstring pl_password,octetstring pl_authenticatior, boolean pl_decrypt) runs on RADIUS_mapping_CT return octetstring{ + return f_crypt_password (pl_password,pl_authenticatior,''O,pl_decrypt,tsp_SharedSecret) // false = encode, true = decode +} + +function f_encode_send(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + var ASP_UDP v_asp_udp; + v_asp_udp.data := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + v_asp_udp.addressf := pl_ASP_UDP_RADIUS.addressf; + v_asp_udp.portf := pl_ASP_UDP_RADIUS.portf; + UDP_PCO.send(v_asp_udp); +} + + +//function f_store_RequestAuth_Field +//function f_store_last + +function f_RADIUS_EncDec_Start(RADIUS_Mode pl_RADIUS_Mode) runs on RADIUS_mapping_CT { + + var ASP_UDP_RADIUS v_asp_udp_radius; + var ASP_UDP v_asp_udp; + + while (true) { + alt { + ///////////////////////////////// + // incoming messages on upper port + ///////////////////////////////// + [] UDP_RADIUS_PCO.receive(t_ASP_UDP_RADIUS) -> value v_asp_udp_radius { + if (pl_RADIUS_Mode == server) { + f_handle_outgoing_server_message(v_asp_udp_radius) + } + else { // client mode + f_handle_outgoing_client_message(v_asp_udp_radius) + } + } + + ///////////////////////////////// + // incoming messages on lower port + ///////////////////////////////// + [] UDP_PCO.receive(t_ASP_UDP) -> value v_asp_udp { + + v_asp_udp_radius.data := f_RADIUS_Dec(v_asp_udp.data); + v_asp_udp_radius.addressf := v_asp_udp.addressf; + v_asp_udp_radius.portf := v_asp_udp.portf; + + if (pl_RADIUS_Mode == server) { + f_handle_incoming_client_message(v_asp_udp_radius,v_asp_udp.data) + } + else { // client mode + f_handle_incoming_server_message(v_asp_udp_radius,v_asp_udp.data) + } + } + } + } +} + + + +} // end of module diff --git a/demo/RADIUS_Mapping_orig.ttcn b/demo/RADIUS_Mapping_orig.ttcn new file mode 100644 index 0000000..b1197c7 --- /dev/null +++ b/demo/RADIUS_Mapping_orig.ttcn @@ -0,0 +1,427 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: RADIUS_Mapping_orig.ttcn +// Description: Example module providing UDP Mapping for RPMG +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + +module RADIUS_Mapping_orig +{ + import from RADIUS_Types all; + import from UDPasp_Types all; + import from UDPasp_PortType all; + + modulepar{ + charstring tsp_SharedSecret := "sharedSecret" + } + + +type record ASP_UDP_RADIUS { + PDU_RADIUS data, + AddressType addressf, + PortType portf +} + +type port UDPasp_RADIUS_PT message { + + inout ASP_UDP_RADIUS +} with {extension "internal"} + + +type component RADIUS_mapping_CT { + + var RADIUS_port_descriptor v_RADIUS_port_descriptor; + + port UDPasp_RADIUS_PT UDP_RADIUS_PCO; // upper port + port UDPasp_PT UDP_PCO; // lower port + +} + +template ASP_UDP t_ASP_UDP := ?; +template ASP_UDP_RADIUS t_ASP_UDP_RADIUS := ?; + + + type record of vsa_descriptor vsa_descriptor_list; + + type record vsa_descriptor { + integer vendor_id, + integer_list subattr_types + } + +//================================================================ +// Types from RADIUS test port, info needed for external functions +//================================================================ +type record RADIUS_port_descriptor { + boolean global_keying, // if this is set to true, 256 will be used instead of EAP Identifier + charstring secret, + integer mode, + octetstring req_auth[256], + octetstring req_acct[256], + boolean debugging +} + +type record of integer integer_list; + +type enumerated generic_attrib_value_union_selection { + unbound, + text_val, + string_val, + address_val, + integer_val, + time_val +} + +type enumerated RADIUS_Mode {client, server}; + +//================================================================ +//================================================================ +//================================================================ + + +// Sending in Server mode +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// == Disconnect_Request == NOT HANDLED +function f_handle_outgoing_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Accept) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Reject) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Server mode!") } +} + +// Sending in Client mode +// -- Access_Request or +// -- Accounting_Request +// == Access_Challenge == NOT HANDLED +// == Disconnect_Ack == NOT HANDLED +// == Disconnect_Nak == NOT HANDLED +function f_handle_outgoing_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + { + // fill out authenticator with random number if template has 0s + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + var integer i; + for ( i := 0; i < 16; i := i+1) + { + pl_ASP_UDP_RADIUS.data.authenticator[i] := int2oct(float2int(int2float(256)*rnd()),1) + } + } + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + + // Calulate hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (ischosen(pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password)) + { + var integer v_pw_len :=lengthof(pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password.base_user_password); + var integer v_padding_length := 16 - (v_pw_len mod 16); + var octetstring v_padded_password := + +pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password.base_user_password & int2oct(0,v_padding_length) + var octetstring v_hidden_password := f_calculate_password( + v_padded_password, + pl_ASP_UDP_RADIUS.data.authenticator, + false + ); + pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password.base_user_password := v_hidden_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + f_encode_send(pl_ASP_UDP_RADIUS); + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + pl_ASP_UDP_RADIUS.data.authenticator := f_calc_MD5(f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data) & char2oct(tsp_SharedSecret)); + } + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + f_encode_send(pl_ASP_UDP_RADIUS); + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Client mode!") } +} + + + +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// == Disconnect_Request == NOT HANDLED +function f_handle_incoming_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS, octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Accept) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Access_Reject) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Client mode") } +} + +// Access_Request or +// Accounting_Request +// == Access_Challenge == NOT HANDLED +// == Disconnect_Ack == NOT HANDLED +// == Disconnect_Nak == NOT HANDLED +function f_handle_incoming_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS,octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + + { + + // Calulate password from hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (ischosen(pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password)) + { + var octetstring v_padded_password := f_calculate_password( + pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password.base_user_password, + pl_ASP_UDP_RADIUS.data.authenticator, + true + ); + + var integer v_padding_length := 0; + while (v_padded_password[lengthof(v_padded_password) - v_padding_length - 1] == '00'O) + { + v_padding_length := v_padding_length + 1; + } + + var octetstring v_password:= substr (v_padded_password,0,lengthof(v_padded_password) - v_padding_length); + + pl_ASP_UDP_RADIUS.data.attributes[j].attrib_Base_User_Password.base_user_password := v_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & '00000000000000000000000000000000'O + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret) + ) + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Server mode")} +} + + +// Encrypts Password field in Access Request using Request Authentication +// field and shared secret (modulepar) +function f_calculate_password( octetstring pl_password,octetstring pl_authenticatior, boolean pl_decrypt) runs on RADIUS_mapping_CT return octetstring{ + return f_crypt_password (pl_password,pl_authenticatior,''O,pl_decrypt,tsp_SharedSecret) // false = encode, true = decode +} + +function f_encode_send(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + var ASP_UDP v_asp_udp; + v_asp_udp.data := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + v_asp_udp.addressf := pl_ASP_UDP_RADIUS.addressf; + v_asp_udp.portf := pl_ASP_UDP_RADIUS.portf; + UDP_PCO.send(v_asp_udp); +} + + +//function f_store_RequestAuth_Field +//function f_store_last + +function f_RADIUS_EncDec_Start(RADIUS_Mode pl_RADIUS_Mode) runs on RADIUS_mapping_CT { + + var ASP_UDP_RADIUS v_asp_udp_radius; + var ASP_UDP v_asp_udp; + + while (true) { + alt { + ///////////////////////////////// + // incoming messages on upper port + ///////////////////////////////// + [] UDP_RADIUS_PCO.receive(t_ASP_UDP_RADIUS) -> value v_asp_udp_radius { + if (pl_RADIUS_Mode == server) { + f_handle_outgoing_server_message(v_asp_udp_radius) + } + else { // client mode + f_handle_outgoing_client_message(v_asp_udp_radius) + } + } + + ///////////////////////////////// + // incoming messages on lower port + ///////////////////////////////// + [] UDP_PCO.receive(t_ASP_UDP) -> value v_asp_udp { + + v_asp_udp_radius.data := f_RADIUS_Dec(v_asp_udp.data); + v_asp_udp_radius.addressf := v_asp_udp.addressf; + v_asp_udp_radius.portf := v_asp_udp.portf; + + if (pl_RADIUS_Mode == server) { + f_handle_incoming_client_message(v_asp_udp_radius,v_asp_udp.data) + } + else { // client mode + f_handle_incoming_server_message(v_asp_udp_radius,v_asp_udp.data) + } + } + } + } +} + + + +} // end of module diff --git a/demo/RADIUSandEAP.cfg b/demo/RADIUSandEAP.cfg new file mode 100644 index 0000000..dbd977e --- /dev/null +++ b/demo/RADIUSandEAP.cfg @@ -0,0 +1,21 @@ +[MODULE_PARAMETERS] +tsp_addressf := "159.107.193.33" +tsp_portf := 1100 +tsp_portf2 := 1101 +#tsp_skip_auth_encr := true + +[TESTPORT_PARAMETERS] +system.RADIUS_Port.localPort := "50000" +#system.RADIUS_Port.localPort := "10002" +system.RADIUS_ClientPort.localPort := "1101" +system.RADIUS_ServerPort.localPort := "1100" + + +[LOGGING] +FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING +ConsoleMask := TTCN_ERROR | TTCN_WARNING | TTCN_TESTCASE | TTCN_STATISTICS | TTCN_PORTEVENT +SourceInfoFormat := Yes + +[EXECUTE] +RadiusAndEAP_Demo.tc_RADIUS_EAP_AKA_full_authentication +RadiusAndEAP_Demo.tc_RADIUS_EAP_SIM_full_authentication diff --git a/demo/RADIUSandEAP_Demo.prj b/demo/RADIUSandEAP_Demo.prj new file mode 100644 index 0000000..1f7f3c6 --- /dev/null +++ b/demo/RADIUSandEAP_Demo.prj @@ -0,0 +1,59 @@ +<!DOCTYPE TITAN_GUI_project_file> +<Project TITAN_version="1.8.pl2" > + <General> + <Project_Name>RADIUSandEAP_Demo</Project_Name> + <Executable_Path>myTest</Executable_Path> + <Working_Dir>.</Working_Dir> + <Build_Host>alpha</Build_Host> + <Execution_Mode>Parallel</Execution_Mode> + <Code_Splitting_Mode>None</Code_Splitting_Mode> + <ScriptFile_AfterMake>gui_make_RPMGandEAP.sh</ScriptFile_AfterMake> + <Log_Format>yes</Log_Format> + <Update_Symlinks>yes</Update_Symlinks> + <Create_Absolute_Symlinks>no</Create_Absolute_Symlinks> + <Update_Makefile>yes</Update_Makefile> + <Localhost_Execute>yes</Localhost_Execute> + <Execute_Command>rsh %host "cd %project_working_dir ; "%executable" %localhost %mctr_port"</Execute_Command> + <Execute_Hosts>alfa, beta, gamma</Execute_Hosts> + <UnUsed_List></UnUsed_List> + </General> + <Modules> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PortType.ttcn</Module> + <Module>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_Types.ttcn</Module> + <Module>RADIUSandEAP_Mapping.ttcn</Module> + <Module>RadiusAndEAP_Demo.ttcn</Module> + <Module>../../PPP_CNL113599/src/EAP_Types.ttcn</Module> + <Module>../../COMMON/src/General_Types.ttcn</Module> + </Modules> + <TestPorts> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.cc</TestPort> + <TestPort>../../../TestPorts/UDPasp_CNL113346/src/UDPasp_PT.hh</TestPort> + </TestPorts> + <Other_Sources> + <Other_Source>../../PPP_CNL113599/src/EAP_EncDec.cc</Other_Source> + <Other_Source>../src/RADIUS_EncDec.cc</Other_Source> + </Other_Sources> + <Configs> + <Config>RADIUSandEAP.cfg</Config> + </Configs> + <Test_Cases> + <Test_Case>RadiusAndEAP_Demo.control</Test_Case> + <Test_Case>RadiusAndEAP_Demo.tc_RADIUS_EAP_AKA_full_authentication</Test_Case> + <Test_Case>RadiusAndEAP_Demo.tc_RADIUS_EAP_SIM_full_authentication</Test_Case> + <Test_Case>RadiusAndEAP_Demo.tc_RADIUS_EAP_SIM_reauthentication</Test_Case> + </Test_Cases> + <Others> + <Other>gui_make_RPMGandEAP.sh</Other> + <Other>../src/ATTR.awk</Other> + <Other>../src/IPv6_IETF_RFC3162.rdf</Other> + <Other>../src/Base_IETF_RFC2865.rdf</Other> + <Other>../src/BaseTypes_IETF_RFC2865.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/TunnelAuthentication_IETF_RFC2868.rdf</Other> + <Other>../src/Extensions_IETF_RFC2869.rdf</Other> + <Other>../src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf</Other> + <Other>../src/Accounting_IETF_RFC2866_RFC2867.rdf</Other> + <Other>../src/DynamicAuthorizationExtensions_IETF_RFC5176.rdf</Other> + </Others> + <File_Group name="MainFileGroup" /> +</Project> diff --git a/demo/RADIUSandEAP_Mapping.ttcn b/demo/RADIUSandEAP_Mapping.ttcn new file mode 100644 index 0000000..80a1174 --- /dev/null +++ b/demo/RADIUSandEAP_Mapping.ttcn @@ -0,0 +1,492 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: RADIUSandEAP_Mapping.ttcn +// Description: Example module providing UDP Mapping for RPMG +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + + +module RADIUSandEAP_Mapping +{ + import from EAP_Types all; + import from RADIUS_Types all; + import from UDPasp_Types all; + import from UDPasp_PortType all; + + modulepar{ + charstring tsp_SharedSecret := "sharedSecret" + } + + +type record ASP_UDP_RADIUS { + PDU_RADIUS data, + AddressType addressf, + PortType portf +} + +type port UDPasp_RADIUS_PT message { + + inout ASP_UDP_RADIUS +} with {extension "internal"} + + +type component RADIUS_mapping_CT { + + var RADIUS_port_descriptor v_RADIUS_port_descriptor; + var EAP_port_descriptor v_EAP_port_descriptor; + + port UDPasp_RADIUS_PT UDP_RADIUS_PCO; // upper port + port UDPasp_PT UDP_PCO; // lower port + +} + +template ASP_UDP t_ASP_UDP := ?; +template ASP_UDP_RADIUS t_ASP_UDP_RADIUS := ?; + + + +//================================================================ +// Types from RADIUS test port, info needed for external functions +//================================================================ +type record RADIUS_port_descriptor { + charstring secret, + octetstring req_auth[256], + octetstring req_acct[256], + octetstring req_disc[256] +} + +type enumerated RADIUS_Mode {client, server}; + +//================================================================ +//================================================================ +//================================================================ + +// Sending in Server mode +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// -- Disconnect_Request +function f_handle_outgoing_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + // Calculate s-key + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_Vendor_Specific) + { + if(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.vendor_id==cdma2000) + { + var integer i:=0; + while (i<sizeof(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list)) + { + if(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].f_cdma2000_type==s_key) + { + var octetstring v_s_key:=pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].string_val; + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].string_val := f_crypt_s_key(v_s_key,v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier],tsp_SharedSecret,false); + } + i:=i+1; + } + } + }j:=j+1; + } + + + if ((pl_ASP_UDP_RADIUS.data.code == Access_Accept) or + (pl_ASP_UDP_RADIUS.data.code == Access_Reject) or + (pl_ASP_UDP_RADIUS.data.code == Access_Challenge)) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else if (pl_ASP_UDP_RADIUS.data.code == Disconnect_Request) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + if (isvalue(v_RADIUS_port_descriptor.req_disc[pl_ASP_UDP_RADIUS.data.identifier])) + { + var octetstring v_RADIUS_encoded := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + pl_ASP_UDP_RADIUS.data.authenticator := + f_calc_MD5( + substr(v_RADIUS_encoded,0,4) + & v_RADIUS_port_descriptor.req_disc[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(v_RADIUS_encoded,20,(lengthof(v_RADIUS_encoded)-20)) + & char2oct(tsp_SharedSecret)); + } + } + f_encode_send(pl_ASP_UDP_RADIUS) + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Server mode!") } +} + +// Sending in Client mode +// -- Access_Request or +// -- Accounting_Request +// -- Access_Challenge +// -- Disconnect_Ack +// -- Disconnect_Nak +function f_handle_outgoing_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + { + // fill out authenticator with random number if template has 0s + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + var integer i; + for ( i := 0; i < 16; i := i+1) + { + pl_ASP_UDP_RADIUS.data.authenticator[i] := int2oct(float2int(int2float(256)*rnd()),1) + } + } + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + + // Calulate hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_User_Password) + { + var integer v_pw_len :=lengthof(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password); + var integer v_padding_length := 16 - (v_pw_len mod 16); + var octetstring v_padded_password :=pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password & int2oct(0,v_padding_length) + var octetstring v_hidden_password := f_calculate_password( + v_padded_password, + pl_ASP_UDP_RADIUS.data.authenticator, + false + ); + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password := v_hidden_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + f_encode_send(pl_ASP_UDP_RADIUS); + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + pl_ASP_UDP_RADIUS.data.authenticator := f_calc_MD5(f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data) & char2oct(tsp_SharedSecret)); + } + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + f_encode_send(pl_ASP_UDP_RADIUS); + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + pl_ASP_UDP_RADIUS.data.authenticator :=v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier]; + pl_ASP_UDP_RADIUS.data.authenticator := f_calc_MD5(f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data) & char2oct(tsp_SharedSecret)); + } + // v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + f_encode_send(pl_ASP_UDP_RADIUS); + } + else if ((pl_ASP_UDP_RADIUS.data.code == Disconnect_ACK) or + (pl_ASP_UDP_RADIUS.data.code == Disconnect_NAK)) + { + if (pl_ASP_UDP_RADIUS.data.authenticator == '00000000000000000000000000000000'O) + { + pl_ASP_UDP_RADIUS.data.authenticator := f_calc_MD5(f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data) & char2oct(tsp_SharedSecret)); + } + v_RADIUS_port_descriptor.req_disc[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator; + f_encode_send(pl_ASP_UDP_RADIUS); + } + else {log("Warning : Will not send out Radius message with code ", pl_ASP_UDP_RADIUS.data.code, " in Client mode!") } +} + + + +// -- Access_Accept or +// -- Access_Reject or +// -- Access_Challenge or +// -- Accounting_Response +// -- Disconnect_Request +function f_handle_incoming_server_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS, octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + // Calculate s-key + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_Vendor_Specific) + { + if(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.vendor_id==cdma2000) + { + var integer i:=0; + while (i<sizeof(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list)) + { + if(pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].f_cdma2000_type==s_key) + { + var octetstring v_s_key:=pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].string_val; + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_vendor_specific.attrib_value.f_cdma2000_subattr_list[i].string_val := f_crypt_s_key(v_s_key,v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier],tsp_SharedSecret,true); + } + i:=i+1; + } + } + }j:=j+1; + } + + if ((pl_ASP_UDP_RADIUS.data.code == Access_Accept) or + (pl_ASP_UDP_RADIUS.data.code == Access_Reject) or + (pl_ASP_UDP_RADIUS.data.code == Access_Challenge)) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Response) + { + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else if (pl_ASP_UDP_RADIUS.data.code == Disconnect_Request) + { + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_disc[pl_ASP_UDP_RADIUS.data.identifier] // stored value + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret)) + + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Client mode") } +} + +// Access_Request or +// Accounting_Request +// Access_Challenge +// Disconnect_Ack +// Disconnect_Nak +function f_handle_incoming_client_message(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS,octetstring pl_asp_udp_data) runs on RADIUS_mapping_CT { + + if (pl_ASP_UDP_RADIUS.data.code == Access_Request) + + { + + // Calulate password from hidden password + var integer j := 0; + while (j < sizeof(pl_ASP_UDP_RADIUS.data.attributes)) + { + if (pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_type==Base_User_Password) + { + var octetstring v_padded_password := f_calculate_password( + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password, + pl_ASP_UDP_RADIUS.data.authenticator, + true + ); + + var integer v_padding_length := 0; + while (v_padded_password[lengthof(v_padded_password) - v_padding_length - 1] == '00'O) + { + v_padding_length := v_padding_length + 1; + } + + var octetstring v_password:= substr (v_padded_password,0,lengthof(v_padded_password) - v_padding_length); + + pl_ASP_UDP_RADIUS.data.attributes[j].genericAttrib.attrib_data.base_user_password := v_password; + j := sizeof(pl_ASP_UDP_RADIUS.data.attributes) // stop while loop + } + j := j + 1; + } + + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + } + else if (pl_ASP_UDP_RADIUS.data.code == Accounting_Request) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_acct[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & '00000000000000000000000000000000'O + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret) + ) + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else if (pl_ASP_UDP_RADIUS.data.code == Access_Challenge) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + // v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & v_RADIUS_port_descriptor.req_auth[pl_ASP_UDP_RADIUS.data.identifier] + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret) + ) + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { + log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else if ((pl_ASP_UDP_RADIUS.data.code == Disconnect_ACK) or + (pl_ASP_UDP_RADIUS.data.code == Disconnect_NAK)) + { + UDP_RADIUS_PCO.send(pl_ASP_UDP_RADIUS); + + v_RADIUS_port_descriptor.req_disc[pl_ASP_UDP_RADIUS.data.identifier] := pl_ASP_UDP_RADIUS.data.authenticator // store value + + var octetstring v_calc_auth := f_calc_MD5( + substr(pl_asp_udp_data,0,4) + & '00000000000000000000000000000000'O + & substr(pl_asp_udp_data,20, lengthof(pl_asp_udp_data)-20) + & char2oct(tsp_SharedSecret) + ) + if (v_calc_auth != pl_ASP_UDP_RADIUS.data.authenticator) + { log("Warning : Unexpected authentication value received in message with code ", pl_ASP_UDP_RADIUS.data.code) } + } + else {log("Warning : Unexpected message with code ", pl_ASP_UDP_RADIUS.data.code, " received in Server mode")} +} + + +// Encrypts Password field in Access Request using Request Authentication +// field and shared secret (modulepar) +function f_calculate_password( octetstring pl_password,octetstring pl_authenticatior, boolean pl_decrypt) runs on RADIUS_mapping_CT return octetstring{ + return f_crypt_password (pl_password,pl_authenticatior,''O,pl_decrypt,tsp_SharedSecret) // false = encode, true = decode +} + +function f_encode_send(in ASP_UDP_RADIUS pl_ASP_UDP_RADIUS) runs on RADIUS_mapping_CT { + var ASP_UDP v_asp_udp; + v_asp_udp.data := f_RADIUS_Enc(pl_ASP_UDP_RADIUS.data); + v_asp_udp.addressf := pl_ASP_UDP_RADIUS.addressf; + v_asp_udp.portf := pl_ASP_UDP_RADIUS.portf; + UDP_PCO.send(v_asp_udp); +} + + +function f_get_Ext_EAP_Message(inout PDU_RADIUS pl_asp_udp_radius_data,RADIUS_Mode pl_RADIUS_Mode,boolean pl_incoming_message) runs on RADIUS_mapping_CT +{ + for (var integer j := 0;j < sizeof(pl_asp_udp_radius_data.attributes);j:=j+1) + { + if (pl_asp_udp_radius_data.attributes[j].genericAttrib.attrib_type==Ext_EAP_Message) + { + var octetstring vl_ext_eap:=pl_asp_udp_radius_data.attributes[j].genericAttrib.attrib_data.ext_eap_message; + if (pl_RADIUS_Mode == server){v_EAP_port_descriptor.serverMode:=true;} + f_get_EAP_parameters(vl_ext_eap,v_EAP_port_descriptor,pl_incoming_message); + pl_asp_udp_radius_data.attributes[j].genericAttrib.attrib_data.ext_eap_message:=vl_ext_eap; + } + } +} + +function f_RADIUS_EncDec_Start(RADIUS_Mode pl_RADIUS_Mode, EAP_port_descriptor pl_EAP_port_descriptor) runs on RADIUS_mapping_CT { + + var ASP_UDP_RADIUS v_asp_udp_radius; + var ASP_UDP v_asp_udp; + v_EAP_port_descriptor:=pl_EAP_port_descriptor; + while (true) { + alt { + ///////////////////////////////// + // incoming messages on upper port + ///////////////////////////////// + [] UDP_RADIUS_PCO.receive(t_ASP_UDP_RADIUS) -> value v_asp_udp_radius { + if (pl_RADIUS_Mode == server) { + f_get_Ext_EAP_Message(v_asp_udp_radius.data,pl_RADIUS_Mode,false); + f_handle_outgoing_server_message(v_asp_udp_radius) + } + else { // client mode + f_get_Ext_EAP_Message(v_asp_udp_radius.data,pl_RADIUS_Mode,false); + f_handle_outgoing_client_message(v_asp_udp_radius) + } + } + + ///////////////////////////////// + // incoming messages on lower port + ///////////////////////////////// + [] UDP_PCO.receive(t_ASP_UDP) -> value v_asp_udp { + v_asp_udp_radius.data := f_RADIUS_Dec(v_asp_udp.data); + v_asp_udp_radius.addressf := v_asp_udp.addressf; + v_asp_udp_radius.portf := v_asp_udp.portf; + + if (pl_RADIUS_Mode == server) { + f_handle_incoming_client_message(v_asp_udp_radius,v_asp_udp.data) ; + f_get_Ext_EAP_Message(v_asp_udp_radius.data,pl_RADIUS_Mode,true); + } + else { // client mode + f_handle_incoming_server_message(v_asp_udp_radius,v_asp_udp.data); + f_get_Ext_EAP_Message(v_asp_udp_radius.data,pl_RADIUS_Mode,true); + } + + + } + } + } +} + + + +} // end of module diff --git a/demo/RadiusAndEAP_Demo.ttcn b/demo/RadiusAndEAP_Demo.ttcn new file mode 100644 index 0000000..f198de8 --- /dev/null +++ b/demo/RadiusAndEAP_Demo.ttcn @@ -0,0 +1,821 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: RadiusAndEAP_Demo.ttcn +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + +module RadiusAndEAP_Demo { + +import from RADIUSandEAP_Mapping all; +import from UDPasp_PortType all; +import from UDPasp_Types all; +import from RADIUS_Types all; +import from EAP_Types all; + +modulepar charstring tsp_addressf := "159.107.193.33"; +modulepar integer tsp_portf := 1100; +modulepar integer tsp_portf2 := 1101; + +modulepar octetstring tsp_s_key := '01234567ABCD'O; +modulepar octetstring tsp_salt := 'ABCD'O + + +type component RADIUS_MTC +{ + +} + +type component RADIUSComponent_CT +{ + port UDPasp_RADIUS_PT RADIUS_PORT ; +} + + +type component SystemComponent +{ + port UDPasp_PT RADIUS_Port; + port UDPasp_PT RADIUS_ClientPort; + port UDPasp_PT RADIUS_ServerPort; +} + + +template ASP_UDP_RADIUS t_ASP_UDP_RADIUS(template Code pl_Code,template PDU_EAP pl_PDU_EAP,template PortType pl_port):= + + { data := { code := pl_Code , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Ext_EAP_Message, + attrib_length := 0, + attrib_data:={ext_eap_message := f_enc_PDU_EAP(valueof(pl_PDU_EAP))}}}}}, + addressf := tsp_addressf, + portf := pl_port }; + +template ASP_UDP_RADIUS tr_ASP_UDP_RADIUS(template Code pl_Code):= + + { data := { code := pl_Code , + identifier := 1, + message_length := ?, + authenticator := ?, + attributes := ?}, + addressf := tsp_addressf, + portf := ?}; + +template PDU_EAP t_PDU_EAP_success:={ + code := success_code, + identifier := 1, + packet_length := 0, + packet_data:= omit}; + +template PDU_EAP tr_PDU_EAP_success modifies t_PDU_EAP_success:={ + packet_length := ?}; + +template PDU_EAP t_PDU_EAP_id (template eap_packet_code_enum pl_code):={ + code := pl_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_identity, + eap_packet_type_data := { + f_eap_identity := '414243444546303132'O} + } }; + +template PDU_EAP tr_PDU_EAP_id (template eap_packet_code_enum pl_code) := { + code := pl_code, + identifier := 1, + packet_length := ?, + packet_data := { + eap_packet_type := eap_identity, + eap_packet_type_data := { + f_eap_identity := '414243444546303132'O} + } }; + +template PDU_EAP t_PDU_EAP_SIM_versionList:={ + code := request_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_start, + reserved := '0000'O, + attrib_list := { + { f_at_version_list := { + attrib := at_version_list, + attrib_length := 0, + actual_length:=0, + version_list := {'0001'O,'0002'O,'0003'O} } + }}}}} + } + +template PDU_EAP tr_PDU_EAP_SIM_versionList modifies t_PDU_EAP_SIM_versionList := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_version_list := { + attrib_length := ?, + actual_length:=? + }} + }}}}}; + + +template PDU_EAP t_PDU_EAP_SIM_nonceMT_selectedVersion:={ //02010020120A000007050000ABCDEFABCDEFABCDEFABCDEFABCDEFAB10010001 + code := response_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_start, + reserved := '0000'O, + attrib_list := { + { f_at_nonce_mt := { + attrib := at_nonce_mt, + attrib_length := 0, + reserved:='0000'O, + attrib_value := 'ABCDEFABCDEFABCDEFABCDEFABCDEFAB'O }}, + { f_at_selected_version := { + attrib := at_selected_version, + attrib_length := 0, + attrib_data := '0001'O }} + + }}}} + } + +template PDU_EAP tr_PDU_EAP_SIM_nonceMT_selectedVersion modifies t_PDU_EAP_SIM_nonceMT_selectedVersion := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_nonce_mt := { + attrib_length := ? + }}, + { f_at_selected_version := { + attrib_length := ? + }} + }}}}}; + +template PDU_EAP t_PDU_EAP_SIM_randIvCounterMac:={ + code := response_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_challenge, + reserved := '0000'O, + attrib_list := { + { f_at_rand := { + attrib := at_rand, + attrib_length := 0, + reserved := '0000'O, + attrib_value := { '01234567890123456789012345678901'O, '01234567890123456789012345678901'O, '01234567890123456789012345678901'O } + } }, + { f_at_iv := { + attrib := at_iv, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00112233445566778899AABBCCDDEEFF'O + } }, + { f_at_encr_data := { + attrib := at_encr_data, + attrib_length := 0, + reserved := '0000'O, + attrib_value := { decrypted_attrib_value:= + {{ f_at_counter := { + attrib := at_counter, + attrib_length := 0, + attrib_data := '0001'O }}} + }} }, + { f_at_mac := { + attrib := at_mac, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O}} + }}}}} + +template PDU_EAP tr_PDU_EAP_SIM_randIvCounterMac modifies t_PDU_EAP_SIM_randIvCounterMac := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_rand := { + attrib_length := ? + } }, + { f_at_iv := { + attrib := at_iv, + attrib_length := ? + } }, + { f_at_encr_data := ?}, + { f_at_mac := { + attrib_length := ?, + attrib_value := ?}} + }}}}}; + +template PDU_EAP t_PDU_EAP_SIM_mac:={ + code := response_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_challenge, + reserved := '0000'O, + attrib_list := { + { f_at_mac := { + attrib := at_mac, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + }}}}}}; + +template PDU_EAP tr_PDU_EAP_SIM_mac modifies t_PDU_EAP_SIM_mac := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_mac := { + attrib_length := ?, + attrib_value := ? }}}}}} +}; + +template PDU_EAP t_PDU_EAP_SIM_reauth_ivEncrMac:={ + code := response_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_re_authentication, + reserved := '0000'O, + attrib_list := { + { f_at_iv := { + attrib := at_iv, + attrib_length := 5, + reserved := '0000'O, + attrib_value := '00112233445566778899AABBCCDDEEFF'O + } }, + { f_at_encr_data := { + attrib := at_encr_data, + attrib_length :=0, + reserved := '0000'O, + attrib_value := { decrypted_attrib_value:={ + { f_at_counter := { + attrib := at_counter, + attrib_length := 0, + attrib_data := '0001'O } }, + { f_at_nonce_s := { + attrib := at_nonce_s, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '0123456789abcdef0123456789abcdef'O } }, + { f_at_next_reauth_id := { + attrib := at_next_reauth_id, + attrib_length := 0, + actual_length := 0, + attrib_value := '1234567890'O } } + }} }}, + { f_at_mac := { + attrib := at_mac, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + }}}}}}; + +template PDU_EAP tr_PDU_EAP_SIM_reauth_ivEncrMac modifies t_PDU_EAP_SIM_reauth_ivEncrMac := { + packet_length := ?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_iv := { + attrib_length := ? + } }, + { f_at_encr_data := { + attrib_length :=?, + reserved := '0000'O, + attrib_value := ? + }}, + { f_at_mac := { + attrib_length := ?, + attrib_value := ? } + }}}}}}; + +template PDU_EAP t_PDU_EAP_SIM_reauth_ivEncrMac2:={ + code := request_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_sim, + eap_packet_type_data := { + f_eap_sim := { + subtype := eap_sim_re_authentication, + reserved := '0000'O, + attrib_list := { + { f_at_iv := { + attrib := at_iv, + attrib_length := 5, + reserved := '0000'O, + attrib_value := 'ABCDEFABCDEFABCDEFABCDEFABCDEFAB'O + } }, + { f_at_encr_data := { + attrib := at_encr_data, + attrib_length :=0, + reserved := '0000'O, + attrib_value := { decrypted_attrib_value:={ + { f_at_counter := { + attrib := at_counter, + attrib_length := 0, + attrib_data := '0001'O } } + }} }}, + { f_at_mac := { + attrib := at_mac, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + }}}}}}; + +template PDU_EAP tr_PDU_EAP_SIM_reauth_ivEncrMac2 modifies t_PDU_EAP_SIM_reauth_ivEncrMac2 := { + packet_length := ?, + packet_data := { + eap_packet_type_data := { + f_eap_sim := { + attrib_list := { + { f_at_iv := { + attrib_length := ? + } }, + { f_at_encr_data := { + attrib_length :=?, + reserved := '0000'O, + attrib_value := ? + }}, + { f_at_mac := { + attrib_length := ?, + attrib_value := ? } + }}}}}}; + +template PDU_EAP t_PDU_EAP_AKA_randAutnIvEncrMac:={ + code := request_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_aka, + eap_packet_type_data := { + f_eap_aka := { + subtype := eap_aka_challenge, + reserved := '0000'O, + attrib_list := { + { f_at_rand := { + attrib := at_rand, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '11223344556677889900AABBCCDDEEFF'O } + }, + { f_at_autn := { + attrib := at_autn, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + }, + { f_at_iv := { + attrib := at_iv, + attrib_length := 5, + reserved := '0000'O, + attrib_value := '00112233445566778899AABBCCDDEEFF'O + } }, + { f_at_encr_data := { + attrib := at_encr_data, + attrib_length :=0, + reserved := '0000'O, + attrib_value := { decrypted_attrib_value:= + {{ f_at_counter := { + attrib := at_counter, + attrib_length := 0, + attrib_value := '0001'O } } + }} }}, + { f_at_mac := { + attrib := at_mac, + attrib_length :=0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + } } } } } + } + +template PDU_EAP tr_PDU_EAP_AKA_randAutnIvEncrMac modifies t_PDU_EAP_AKA_randAutnIvEncrMac := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_aka := { + attrib_list := { + { f_at_rand := { + attrib_length := ? + }}, + { f_at_autn := { + attrib_length := ? , + attrib_value := ? + }}, + { f_at_iv := { + attrib_length := ? + }}, + { f_at_encr_data := { + attrib_length := ? , + attrib_value := ? }}, + { f_at_mac := { + attrib_length := ? , + attrib_value := ? + }} + }} + }}}; + +template PDU_EAP t_PDU_EAP_AKA_mac:={ + code := response_code, + identifier := 1, + packet_length := 0, + packet_data := { + eap_packet_type := eap_aka, + eap_packet_type_data := { + f_eap_aka := { + subtype := eap_aka_challenge, + reserved := '0000'O, + attrib_list := { + { f_at_mac := { + attrib := at_mac, + attrib_length := 0, + reserved := '0000'O, + attrib_value := '00000000000000000000000000000000'O } + }}}}}}; + +template PDU_EAP tr_PDU_EAP_AKA_mac modifies t_PDU_EAP_AKA_mac := { + packet_length:=?, + packet_data := { + eap_packet_type_data := { + f_eap_aka := { + attrib_list := { + { f_at_mac := { + attrib_length := ?, + attrib_value := ? }}}}}} +}; + +function f_EAP_SIM_full_auth_server() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS,v_ASP_UDP_RADIUS1,v_ASP_UDP_RADIUS2; + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Request)) -> value v_ASP_UDP_RADIUS{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS); + if (match(vl_PDU_EAP,tr_PDU_EAP_id(response_code))){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_versionList,tsp_portf2))); + alt{ + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP2:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP2,tr_PDU_EAP_SIM_nonceMT_selectedVersion)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_randIvCounterMac,tsp_portf2))); + alt{ + []RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS2{ + var PDU_EAP vl_PDU_EAP3:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS2.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS2); + if (match(vl_PDU_EAP3,tr_PDU_EAP_SIM_mac)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Accept,t_PDU_EAP_success,tsp_portf2))); + setverdict (pass)} + else {setverdict (fail); repeat;}} + [] t1.timeout {setverdict (fail)} + }}} + [] t1.timeout {setverdict (fail)} + } + }} + [] t1.timeout {setverdict (fail)} + } +} + + +function f_EAP_SIM_full_auth_client() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1,v_ASP_UDP_RADIUS2; + + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Request,t_PDU_EAP_id(response_code),tsp_portf))); + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP,tr_PDU_EAP_SIM_versionList)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_nonceMT_selectedVersion,tsp_portf))); + alt{ + []RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS2{ + var PDU_EAP vl_PDU_EAP2:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS2.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS2); + if (match(vl_PDU_EAP2,tr_PDU_EAP_SIM_randIvCounterMac)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_mac,tsp_portf))); + alt{ + []RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Accept)) { + setverdict (pass)} + [] t1.timeout {setverdict (fail)} + }}} + [] t1.timeout {setverdict (fail)} + }}} + [] t1.timeout {setverdict (fail)} + } + +} + + +function f_EAP_SIM_reauth_server() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS,v_ASP_UDP_RADIUS1,v_ASP_UDP_RADIUS2; + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Request)) -> value v_ASP_UDP_RADIUS{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS); + if (match(vl_PDU_EAP,tr_PDU_EAP_id(response_code))){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_reauth_ivEncrMac,tsp_portf2))); + alt{ + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP2:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP2,tr_PDU_EAP_SIM_reauth_ivEncrMac2)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Accept,t_PDU_EAP_success,tsp_portf2))); + setverdict (pass)} + else {setverdict (fail); }} + [] t1.timeout {setverdict (fail)} + } + }} + [] t1.timeout {setverdict (fail)} + } +} + + +function f_EAP_SIM_reauth_client() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1,v_ASP_UDP_RADIUS2; + + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Request,t_PDU_EAP_id(response_code),tsp_portf))); + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP,tr_PDU_EAP_SIM_reauth_ivEncrMac)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_SIM_reauth_ivEncrMac2,tsp_portf))); + alt{ + []RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Accept)) { + setverdict (pass)} + [] t1.timeout {setverdict (fail)} + }}} + [] t1.timeout {setverdict (fail)} + } + +} + + +function f_EAP_AKA_full_auth_server() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1,v_ASP_UDP_RADIUS2; + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Request)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP,tr_PDU_EAP_id(response_code))){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_AKA_randAutnIvEncrMac,tsp_portf2))); + alt{ + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS2{ + var PDU_EAP vl_PDU_EAP2:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS2.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + if (match(vl_PDU_EAP2,tr_PDU_EAP_AKA_mac)){ + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Accept,t_PDU_EAP_success,tsp_portf2))); + setverdict (pass); + }} + [] t1.timeout {setverdict (fail)} + } + } + } + [] t1.timeout {setverdict (fail)} + } + +} + +function f_EAP_AKA_full_auth_client() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1; + + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Request,t_PDU_EAP_id(response_code),tsp_portf))); + timer t1 := 15.0; + t1.start; + alt { + [] RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Challenge)) -> value v_ASP_UDP_RADIUS1{ + var PDU_EAP vl_PDU_EAP:=f_dec_PDU_EAP(v_ASP_UDP_RADIUS1.data.attributes[0].genericAttrib.attrib_data.ext_eap_message); + log(v_ASP_UDP_RADIUS1); + if (match(vl_PDU_EAP,tr_PDU_EAP_AKA_randAutnIvEncrMac)) + { + RADIUS_PORT.send(valueof(t_ASP_UDP_RADIUS(Access_Challenge,t_PDU_EAP_AKA_mac,tsp_portf))); + alt{ + []RADIUS_PORT.receive(tr_ASP_UDP_RADIUS(Access_Accept)) { + setverdict (pass) + } + [] t1.timeout {setverdict (fail)} + }} + } + [] t1.timeout {setverdict (fail)} + } + +} + +///////////////////////// +testcase tc_RADIUS_EAP_AKA_full_authentication() runs on RADIUS_MTC system SystemComponent { + + var RADIUSComponent_CT client := RADIUSComponent_CT.create; + var RADIUSComponent_CT server := RADIUSComponent_CT.create; + + var RADIUS_mapping_CT mappingServer := RADIUS_mapping_CT.create; + var RADIUS_mapping_CT mappingClient := RADIUS_mapping_CT.create; + + connect(client: RADIUS_PORT , mappingClient:UDP_RADIUS_PCO); + map(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + + connect(server: RADIUS_PORT , mappingServer:UDP_RADIUS_PCO); + map(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + + var EAP_port_descriptor v_EAP_port_descriptor_Server,v_EAP_port_descriptor_Client; + f_initEAPPortDescriptor(v_EAP_port_descriptor_Server); +// f_set_K(1,tsp_AKA_K,v_EAP_port_descriptor_Server); + f_initEAPPortDescriptor(v_EAP_port_descriptor_Client); +// f_set_K(1,tsp_AKA_K,v_EAP_port_descriptor_Client); +// f_set_SQN(1,tsp_AKA_SQN,v_EAP_port_descriptor_Server); +// f_set_SQN_MS(1,tsp_AKA_SQN_MS,v_EAP_port_descriptor_Server); +// f_set_AMF(1,tsp_AKA_AMF,v_EAP_port_descriptor_Server); + + mappingServer.start(f_RADIUS_EncDec_Start(server,v_EAP_port_descriptor_Server)) + server.start(f_EAP_AKA_full_auth_server()); + mappingClient.start(f_RADIUS_EncDec_Start(client,v_EAP_port_descriptor_Client)) + client.start(f_EAP_AKA_full_auth_client()); + + timer t1 := 15.0; + t1.start; + + alt { + [] server.done { + alt { + [] client.done { + setverdict (pass); + } + [] t1.timeout { + setverdict (fail); + } + } + } + [] t1.timeout { + setverdict(fail); + } + } + unmap(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + unmap(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + +} + + + +///////////////////////// +testcase tc_RADIUS_EAP_SIM_full_authentication() runs on RADIUS_MTC system SystemComponent { + + var RADIUSComponent_CT client := RADIUSComponent_CT.create; + var RADIUSComponent_CT server := RADIUSComponent_CT.create; + + var RADIUS_mapping_CT mappingServer := RADIUS_mapping_CT.create; + var RADIUS_mapping_CT mappingClient := RADIUS_mapping_CT.create; + + var EAP_port_descriptor v_EAP_port_descriptor_Server,v_EAP_port_descriptor_Client; + f_initEAPPortDescriptor(v_EAP_port_descriptor_Server); + f_initEAPPortDescriptor(v_EAP_port_descriptor_Client); + f_set_Ki(1,tsp_SIM_Ki,v_EAP_port_descriptor_Server); + f_set_Ki(1,tsp_SIM_Ki,v_EAP_port_descriptor_Client); + + connect(client: RADIUS_PORT , mappingClient:UDP_RADIUS_PCO); + map(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + + connect(server: RADIUS_PORT , mappingServer:UDP_RADIUS_PCO); + map(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + + mappingServer.start(f_RADIUS_EncDec_Start(server,v_EAP_port_descriptor_Server)); + server.start(f_EAP_SIM_full_auth_server()); + mappingClient.start(f_RADIUS_EncDec_Start(client,v_EAP_port_descriptor_Client)); + client.start(f_EAP_SIM_full_auth_client()); + + timer t1 := 15.0; + t1.start; + + alt { + [] server.done { + alt { + [] client.done { + setverdict (pass); + } + [] t1.timeout { + setverdict (fail); + } + } + } + [] t1.timeout { + setverdict(fail); + } + } + unmap(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + unmap(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + +} + +///////////////////////// +testcase tc_RADIUS_EAP_SIM_reauthentication() runs on RADIUS_MTC system SystemComponent { + + var RADIUSComponent_CT client := RADIUSComponent_CT.create; + var RADIUSComponent_CT server := RADIUSComponent_CT.create; + + var RADIUS_mapping_CT mappingServer := RADIUS_mapping_CT.create; + var RADIUS_mapping_CT mappingClient := RADIUS_mapping_CT.create; + + var EAP_port_descriptor v_EAP_port_descriptor_Server,v_EAP_port_descriptor_Client; + f_initEAPPortDescriptor(v_EAP_port_descriptor_Server); + f_initEAPPortDescriptor(v_EAP_port_descriptor_Client); + f_set_Ki(1,tsp_SIM_Ki,v_EAP_port_descriptor_Server); + f_set_Ki(1,tsp_SIM_Ki,v_EAP_port_descriptor_Client); + + connect(client: RADIUS_PORT , mappingClient:UDP_RADIUS_PCO); + map(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + + connect(server: RADIUS_PORT , mappingServer:UDP_RADIUS_PCO); + map(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + + mappingServer.start(f_RADIUS_EncDec_Start(server,v_EAP_port_descriptor_Server)) + server.start(f_EAP_SIM_reauth_server()); + mappingClient.start(f_RADIUS_EncDec_Start(client,v_EAP_port_descriptor_Client)) + client.start(f_EAP_SIM_reauth_client()); + + timer t1 := 15.0; + t1.start; + + alt { + [] server.done { + alt { + [] client.done { + setverdict (pass); + } + [] t1.timeout { + setverdict (fail); + } + } + } + [] t1.timeout { + setverdict(fail); + } + } + unmap(mappingClient:UDP_PCO, system: RADIUS_ClientPort); + unmap(mappingServer:UDP_PCO, system: RADIUS_ServerPort); + +} + +control +{ + execute(tc_RADIUS_EAP_SIM_full_authentication()); + execute(tc_RADIUS_EAP_SIM_reauthentication()); + execute(tc_RADIUS_EAP_AKA_full_authentication()); +} + +} diff --git a/demo/Radius_Test_new.ttcn b/demo/Radius_Test_new.ttcn new file mode 100644 index 0000000..33c0cd8 --- /dev/null +++ b/demo/Radius_Test_new.ttcn @@ -0,0 +1,606 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: Radius_Test_new.ttcn +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + +module Radius_Test_new { + +import from RADIUS_Mapping_new all; +import from UDPasp_PortType all; +import from UDPasp_Types all; +import from RADIUS_Types all; + +modulepar charstring tsp_addressf := "159.107.193.33"; +modulepar integer tsp_portf := 1100; + + +type component RADIUS_MTC +{ + +} + +type component RADIUSComponent_CT +{ + port UDPasp_RADIUS_PT RADIUS_PORT ; +} + + +type component SystemComponent +{ + port UDPasp_PT RADIUS_Port; +} + + + + +// receive Access Req, send Access Accept + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_correct_auth() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept_with_correct_auth()) + + v_server.done + + v_mapping.kill + +} + + + +function f_receiveAccessRequest_sendAccessAccept_with_correct_auth() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive (ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)}} + [] t1.timeout {setverdict (fail)} + } + + +} + + +// receive Access Req, send Access Accept with incorrect Auth Resp + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_incorrect_auth() runs on RADIUSComponent_CT system SystemComponent + { + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept_with_incorrect_auth()) + + v_server.done + + v_mapping.kill + +} + + +function f_receiveAccessRequest_sendAccessAccept_with_incorrect_auth() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000001'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive (ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)}} + [] t1.timeout {setverdict (fail)} + } + +} + + + testcase tc_RADIUS_client_sendAccessRequest() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessRequest()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessRequest() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Request , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + + +} + +//////////////////////////////////////////////////////// +//send Access Req, receive Access Accept + testcase tc_RADIUS_client_sendAccessRequest_receiveAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessRequest_receiveAccessAccept()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessRequest_receiveAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Request , + identifier := 1, + message_length := 56, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Base_User_Name, + attrib_length := 6, + attrib_data := {base_user_name:=char2oct("nemo")} } }, + { genericAttrib:={ + attrib_type := Base_User_Password, + attrib_length := 18, + attrib_data := {base_user_password:=char2oct("nemo21") }}}, + { genericAttrib:={ + attrib_type := Base_NAS_IP_Address, + attrib_length := 6, + attrib_data := {base_nas_ip_address:='C0A80110'O } } }, + { genericAttrib:={ + attrib_type := Base_NAS_Port, + attrib_length := 6, + attrib_data := {base_nas_port:=3} }} + + } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + template ASP_UDP_RADIUS v_ASP_UDP_RADIUS2:= + { data := { code := Access_Accept , + identifier := 1, + message_length := ?, + authenticator := ?, + attributes := ? + }, + addressf := ?, + portf := ? } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive(v_ASP_UDP_RADIUS2) {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + +} + +//send Access Accept?! + testcase tc_RADIUS_client_sendAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessAccept()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 56, + authenticator := '00000000000000000000000000000000'O, + attributes := {} + }, + addressf := tsp_addressf, + portf := tsp_portf } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + +} + + +//send Accounting Req, receive Accounting Response + testcase tc_RADIUS_client_sendAccountingRequest_receiveAccountingResponse() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccountingRequest_receiveAccountingResponse()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccountingRequest_receiveAccountingResponse() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Accounting_Request , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Acc_Acct_Status_Type, + attrib_length := 0, + attrib_data:={acc_acct_status_type := Stop }}} , + { genericAttrib:={ + attrib_type := Acc_Acct_Input_Packets, + attrib_length := 0, + attrib_data:={acc_acct_input_packets := 5 }}} + }}, + addressf := tsp_addressf, + portf := tsp_portf } + +template ASP_UDP_RADIUS v_ASP_UDP_RADIUS2:= + { data := { code := Accounting_Response , + identifier := 1, + message_length := ?, + authenticator := ?, + attributes := ? + }, + addressf := ?, + portf := ? } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(v_ASP_UDP_RADIUS2) {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + + + +} + + +// receive Access Req, send Access Accept + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccessRequest_sendAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Base_Service_Type, + attrib_length := 6, + attrib_data:={base_service_type := Framed }} }, + { genericAttrib:={ + attrib_type := Base_Framed_Protocol, + attrib_length := 6, + attrib_data:={base_framed_protocol := PPP} }}, + { genericAttrib:={ + attrib_type := Base_Framed_IP_Address, + attrib_length := 6, + attrib_data:={base_framed_ip_address := 'FFFFFFFE'O } }}, + {genericAttrib:={ + attrib_type := Base_Framed_Routing, + attrib_length := 6, + attrib_data:={base_framed_routing := None } }}, + { genericAttrib:={ + attrib_type := Base_Framed_Compression, + attrib_length := 6, + attrib_data:={base_framed_compression := VJ_TCP_IP_header_compression }} }, + { genericAttrib:={ + attrib_type := Base_Framed_MTU, + attrib_length := 6, + attrib_data:={base_framed_mtu := 1500 } }} + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)} + else {setverdict(fail); repeat;}} + [] t1.timeout {setverdict (fail)} + } + + +} + + +// receive Access Req, send Access Challenge + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessChallenge() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessChallenge()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccessRequest_sendAccessChallenge() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Challenge , + identifier := 1, + message_length := 78, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Base_Reply_Message, + attrib_length := 48, + attrib_data:={base_reply_message := "Challenge 32769430. Enter response at prompt." }}}, + {genericAttrib:={ + attrib_type := Base_State, + attrib_length := 10, + attrib_data:={base_state := '3332373639343330'O } }} + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS2 + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS3:= + { data := { code := Access_Reject , + identifier := 1, + message_length := 20, + authenticator := '00000000000000000000000000000000'O, + attributes := {}}, + addressf := tsp_addressf, + portf := tsp_portf } + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request){ + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS2 + if (v_ASP_UDP_RADIUS2.data.code==Access_Request){ + v_ASP_UDP_RADIUS3.data.identifier := v_ASP_UDP_RADIUS2.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS3); + setverdict(pass)} + else {setverdict (fail)}} + else {setverdict (fail)} + } + [] t1.timeout {setverdict (fail)} + } + + +} + + + + +// receive Accounting Req, send Accounting Response + testcase tc_RADIUS_server_receiveAccountingRequest_sendAccountingResponse() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccountingRequest_sendAccountingResponse()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccountingRequest_sendAccountingResponse() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Accounting_Response , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Base_Proxy_State, + attrib_length := 10, + attrib_data:={base_proxy_state := '3332373639343330'O }}} + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1; + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Accounting_Request){ + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict (pass)} + else {setverdict (fail); repeat;}} + [] t1.timeout {setverdict (fail)} + } + +} + + testcase tc_RADIUS_encdec() runs on RADIUSComponent_CT +{ + var PDU_RADIUS v_PDU_RADIUS:= + { code := Accounting_Response , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { genericAttrib:={ + attrib_type := Base_Vendor_Specific, + attrib_length := 0, + attrib_data:= + {base_vendor_specific :={ + vendor_id:=scap, + attrib_value:= {f_scap_subattr_list:={{ + scap_type:=suggested_secondary_rulespace, + scap_length:=0, + scap_val:={charstring_val:="Na"}}}} + }}}}, + { genericAttrib:={ + attrib_type := IPv6_Framed_IPv6_Prefix, + attrib_length := 0, + attrib_data:= + {ipv6_framed_ipv6_prefix :={ + reserved:='00'O, + prefix_length:=0, + prefixValue:= '00100000000000000011111111111110000000000000000100000000000001'B,//oct2bit('20003ffe00010001'O), + prefixPadding := '00'B + }}}} + + }}; + log(v_PDU_RADIUS); + var octetstring v_oct1:=f_RADIUS_Enc(v_PDU_RADIUS); + log(v_oct1); + v_PDU_RADIUS:=f_RADIUS_Dec(v_oct1); + log(v_PDU_RADIUS); + var octetstring v_oct2:=f_RADIUS_Enc(v_PDU_RADIUS); + if (v_oct1 == v_oct2){setverdict (pass)} + else {setverdict (fail)} + + +} + + +} diff --git a/demo/Radius_Test_orig.ttcn b/demo/Radius_Test_orig.ttcn new file mode 100644 index 0000000..2eae197 --- /dev/null +++ b/demo/Radius_Test_orig.ttcn @@ -0,0 +1,604 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ +// +// File: Radius_Test_orig.ttcn +// Rev: R12A +// Prodnr: CNL 113 600 +// Remark: This file is not a part of the product. +// +// +// + + +module Radius_Test_orig { + +import from RADIUS_Mapping_orig all; +import from UDPasp_PortType all; +import from UDPasp_Types all; +import from RADIUS_Types all; + +modulepar charstring tsp_addressf := "159.107.193.33"; +modulepar integer tsp_portf := 1100; + + +type component RADIUS_MTC +{ + +} + +type component RADIUSComponent_CT +{ + port UDPasp_RADIUS_PT RADIUS_PORT ; +} + + +type component SystemComponent +{ + port UDPasp_PT RADIUS_Port; +} + + + + +// receive Access Req, send Access Accept + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_correct_auth() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept_with_correct_auth()) + + v_server.done + + v_mapping.kill + +} + + + +function f_receiveAccessRequest_sendAccessAccept_with_correct_auth() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive (ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)}} + [] t1.timeout {setverdict (fail)} + } + + +} + + +// receive Access Req, send Access Accept with incorrect Auth Resp + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_incorrect_auth() runs on RADIUSComponent_CT system SystemComponent + { + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept_with_incorrect_auth()) + + v_server.done + + v_mapping.kill + +} + + +function f_receiveAccessRequest_sendAccessAccept_with_incorrect_auth() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000001'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive (ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)}} + [] t1.timeout {setverdict (fail)} + } + +} + + + testcase tc_RADIUS_client_sendAccessRequest() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessRequest()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessRequest() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Request , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + + +} + +//////////////////////////////////////////////////////// +//send Access Req, receive Access Accept + testcase tc_RADIUS_client_sendAccessRequest_receiveAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessRequest_receiveAccessAccept()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessRequest_receiveAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Request , + identifier := 1, + message_length := 56, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Base_User_Name := { + attrib_type := Base_User_Name, + attrib_length := 6, + base_user_name := char2oct("nemo") } }, + { attrib_Base_User_Password := { + attrib_type := Base_User_Password, + attrib_length := 18, + base_user_password := char2oct("nemo21")} }, + { attrib_Base_NAS_IP_Address := { + attrib_type := Base_NAS_IP_Address, + attrib_length := 6, + base_nas_ip_address := 'C0A80110'O } }, + { attrib_Base_NAS_Port := { + attrib_type := Base_NAS_Port, + attrib_length := 6, + base_nas_port := 3 } } + + } + }, + addressf := tsp_addressf, + portf := tsp_portf } + + template ASP_UDP_RADIUS v_ASP_UDP_RADIUS2:= + { data := { code := Access_Accept , + identifier := 1, + message_length := ?, + authenticator := ?, + attributes := ? + }, + addressf := ?, + portf := ? } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 5.0; + t1.start; + alt { + [] RADIUS_PORT.receive(v_ASP_UDP_RADIUS2) {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + +} + +//send Access Accept?! + testcase tc_RADIUS_client_sendAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccessAccept()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 56, + authenticator := '00000000000000000000000000000000'O, + attributes := {} + }, + addressf := tsp_addressf, + portf := tsp_portf } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + +} + + +//send Accounting Req, receive Accounting Response + testcase tc_RADIUS_client_sendAccountingRequest_receiveAccountingResponse() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_client := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_client: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(client)) + + v_client.start(f_sendAccountingRequest_receiveAccountingResponse()) + + v_client.done + + v_mapping.kill + + } + +function f_sendAccountingRequest_receiveAccountingResponse() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Accounting_Request , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Acc_Acct_Status_Type := { + attrib_type := Acc_Acct_Status_Type, + attrib_length := 0, + acc_acct_status_type := Stop } }, + { attrib_Acc_Acct_Input_Packets := { + attrib_type := Acc_Acct_Input_Packets, + attrib_length := 0, + acc_acct_input_packets := 5 } } + }}, + addressf := tsp_addressf, + portf := tsp_portf } + +template ASP_UDP_RADIUS v_ASP_UDP_RADIUS2:= + { data := { code := Accounting_Response , + identifier := 1, + message_length := ?, + authenticator := ?, + attributes := ? + }, + addressf := ?, + portf := ? } + + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(v_ASP_UDP_RADIUS2) {setverdict(pass)} + [] t1.timeout {setverdict (fail)} + } + + + +} + + +// receive Access Req, send Access Accept + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessAccept() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessAccept()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccessRequest_sendAccessAccept() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Accept , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Base_Service_Type := { + attrib_type := Base_Service_Type, + attrib_length := 6, + base_service_type := Framed } }, + { attrib_Base_Framed_Protocol := { + attrib_type := Base_Framed_Protocol, + attrib_length := 6, + base_framed_protocol := PPP} }, + { attrib_Base_Framed_IP_Address := { + attrib_type := Base_Framed_IP_Address, + attrib_length := 6, + base_framed_ip_address := 'FFFFFFFE'O } }, + { attrib_Base_Framed_Routing := { + attrib_type := Base_Framed_Routing, + attrib_length := 6, + base_framed_routing := None } }, + { attrib_Base_Framed_Compression := { + attrib_type := Base_Framed_Compression, + attrib_length := 6, + base_framed_compression := VJ_TCP_IP_header_compression } }, + { attrib_Base_Framed_MTU := { + attrib_type := Base_Framed_MTU, + attrib_length := 6, + base_framed_mtu := 1500 } } + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request) { + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict(pass)} + else {setverdict(fail); repeat;}} + [] t1.timeout {setverdict (fail)} + } + + +} + + +// receive Access Req, send Access Challenge + testcase tc_RADIUS_server_receiveAccessRequest_sendAccessChallenge() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccessRequest_sendAccessChallenge()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccessRequest_sendAccessChallenge() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Access_Challenge , + identifier := 1, + message_length := 78, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Base_Reply_Message := { + attrib_type := Base_Reply_Message, + attrib_length := 48, + base_reply_message := "Challenge 32769430. Enter response at prompt." } }, + { attrib_Base_State := { + attrib_type := Base_State, + attrib_length := 10, + base_state := '3332373639343330'O } } + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1 + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS2 + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS3:= + { data := { code := Access_Reject , + identifier := 1, + message_length := 20, + authenticator := '00000000000000000000000000000000'O, + attributes := {}}, + addressf := tsp_addressf, + portf := tsp_portf } + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Access_Request){ + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS2 + if (v_ASP_UDP_RADIUS2.data.code==Access_Request){ + v_ASP_UDP_RADIUS3.data.identifier := v_ASP_UDP_RADIUS2.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS3); + setverdict(pass)} + else {setverdict (fail)}} + else {setverdict (fail)} + } + [] t1.timeout {setverdict (fail)} + } + + +} + + + + +// receive Accounting Req, send Accounting Response + testcase tc_RADIUS_server_receiveAccountingRequest_sendAccountingResponse() runs on RADIUSComponent_CT system SystemComponent +{ + var RADIUSComponent_CT v_server := RADIUSComponent_CT.create; + var RADIUS_mapping_CT v_mapping := RADIUS_mapping_CT.create; + + connect(v_server: RADIUS_PORT , v_mapping:UDP_RADIUS_PCO); + map(v_mapping:UDP_PCO, system: RADIUS_Port) + + v_mapping.start(f_RADIUS_EncDec_Start(server)) + + v_server.start(f_receiveAccountingRequest_sendAccountingResponse()) + + v_server.done + + v_mapping.kill + +} + +function f_receiveAccountingRequest_sendAccountingResponse() runs on RADIUSComponent_CT +{ + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS:= + + { data := { code := Accounting_Response , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Base_Proxy_State := { + attrib_type := Base_Proxy_State, + attrib_length := 10, + base_proxy_state := '3332373639343330'O }} + }}, + addressf := tsp_addressf, + portf := tsp_portf } + var ASP_UDP_RADIUS v_ASP_UDP_RADIUS1; + timer t1 := 10.0; + t1.start; + alt { + [] RADIUS_PORT.receive(ASP_UDP_RADIUS:?) -> value v_ASP_UDP_RADIUS1{ + if (v_ASP_UDP_RADIUS1.data.code==Accounting_Request){ + v_ASP_UDP_RADIUS.data.identifier := v_ASP_UDP_RADIUS1.data.identifier; + RADIUS_PORT.send(v_ASP_UDP_RADIUS); + setverdict (pass)} + else {setverdict (fail); repeat;}} + [] t1.timeout {setverdict (fail)} + } + +} + + testcase tc_RADIUS_encdec() runs on RADIUSComponent_CT +{ + var PDU_RADIUS v_PDU_RADIUS:= + { code := Accounting_Response , + identifier := 1, + message_length := 0, + authenticator := '00000000000000000000000000000000'O, + attributes := { + { attrib_Base_Vendor_Specific:={ + attrib_type := Base_Vendor_Specific, + attrib_length := 0, + base_vendor_specific :={ + vendor_id:=scap, + attrib_value:= {f_scap_subattr_list:={{ + scap_type:=suggested_secondary_rulespace, + scap_length:=0, + scap_val:={charstring_val:="Na"}}}} + }}}, + { attrib_IPv6_Framed_IPv6_Prefix:={ + attrib_type := IPv6_Framed_IPv6_Prefix, + attrib_length := 0, + ipv6_framed_ipv6_prefix :={ + reserved:='00'O, + prefix_length:=0, + prefixValue:= '00100000000000000011111111111110000000000000000100000000000001'B,//oct2bit('20003ffe00010001'O), + prefixPadding := '00'B + }}} + + }}; + log(v_PDU_RADIUS); + var octetstring v_oct1:=f_RADIUS_Enc(v_PDU_RADIUS); + log(v_oct1); + v_PDU_RADIUS:=f_RADIUS_Dec(v_oct1); + log(v_PDU_RADIUS); + var octetstring v_oct2:=f_RADIUS_Enc(v_PDU_RADIUS); + if (v_oct1 == v_oct2){setverdict (pass)} + else {setverdict (fail)} + + +} + + +} diff --git a/demo/gui_make_RPMG_new.sh b/demo/gui_make_RPMG_new.sh new file mode 100644 index 0000000..df8cb34 --- /dev/null +++ b/demo/gui_make_RPMG_new.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +sed -e ' +s/OPENSSL_DIR = $(TTCN3_DIR)/\OPENSSL_DIR = \/mnt\/TTCN\/Tools\/openssl-0.9.8e/g +s/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(OPENSSL_DIR)\/include -I$(TTCN3_DIR)\/include/g + +' \ +-e 's/^TTCN3_MODULES =/TTCN3_MODULES = RADIUS_Types.ttcn/g +s/^GENERATED_SOURCES =/GENERATED_SOURCES = RADIUS_Types.cc/g +s/^GENERATED_HEADERS =/GENERATED_HEADERS = RADIUS_Types.hh/g +s/^OBJECTS =/OBJECTS = RADIUS_Types.o/g +/# Add your rules here if necessary./ { +a\ +# +a\ + +a\ +AWK=/usr/local/bin/gawk +a\ + +a\ +RADIUS_Types.ttcn: BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf ATTR.awk +a\ + $(AWK) -f ATTR.awk BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf > $@ +a\ + +a\ +# +a\ +# End of additional rules for RPMG +} +' \ +<$1 >$2 diff --git a/demo/gui_make_RPMG_orig.sh b/demo/gui_make_RPMG_orig.sh new file mode 100644 index 0000000..092ccbc --- /dev/null +++ b/demo/gui_make_RPMG_orig.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +sed -e ' +s/OPENSSL_DIR = $(TTCN3_DIR)/\OPENSSL_DIR = \/mnt\/TTCN\/Tools\/openssl-0.9.8e/g +s/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(OPENSSL_DIR)\/include -I$(TTCN3_DIR)\/include/g + +' \ +-e 's/^TTCN3_MODULES =/TTCN3_MODULES = RADIUS_Types.ttcn/g +s/^GENERATED_SOURCES =/GENERATED_SOURCES = RADIUS_Types.cc/g +s/^GENERATED_HEADERS =/GENERATED_HEADERS = RADIUS_Types.hh/g +s/^OBJECTS =/OBJECTS = RADIUS_Types.o/g +/# Add your rules here if necessary./ { +a\ +# +a\ + +a\ +AWK=/usr/local/bin/gawk +a\ + +a\ +RADIUS_Types.ttcn: BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf ATTR.awk +a\ + $(AWK) -f ATTR.awk -v old_structured_code=1 BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf > $@ +a\ + +a\ +# +a\ +# End of additional rules for RPMG +} +' \ +<$1 >$2 diff --git a/demo/gui_make_RPMGandEAP.sh b/demo/gui_make_RPMGandEAP.sh new file mode 100644 index 0000000..6db8381 --- /dev/null +++ b/demo/gui_make_RPMGandEAP.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +sed -e ' +s/OPENSSL_DIR = $(TTCN3_DIR)/\OPENSSL_DIR = \/mnt\/TTCN\/Tools\/openssl-0.9.8e/g +s/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(OPENSSL_DIR)\/include -I$(TTCN3_DIR)\/include/g + +' \ +-e 's/^TTCN3_MODULES =/TTCN3_MODULES = RADIUS_Types.ttcn/g +s/^GENERATED_SOURCES =/GENERATED_SOURCES = RADIUS_Types.cc/g +s/^GENERATED_HEADERS =/GENERATED_HEADERS = RADIUS_Types.hh/g +s/^OBJECTS =/OBJECTS = RADIUS_Types.o/g +/# Add your rules here if necessary./ { +a\ +# +a\ + +a\ +AWK=/usr/local/bin/gawk +a\ + +a\ +RADIUS_Types.ttcn: BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf DynamicAuthorizationExtensions_IETF_RFC5176.rdf ATTR.awk +a\ + $(AWK) -f ATTR.awk BaseTypes_IETF_RFC2865.rdf Base_IETF_RFC2865.rdf Accounting_IETF_RFC2866_RFC2867.rdf IPv6_IETF_RFC3162.rdf Extensions_IETF_RFC2869.rdf TunnelAuthentication_IETF_RFC2868.rdf DynamicAuthorizationExtensions_IETF_RFC5176.rdf > $@ +a\ + +a\ +# +a\ +# End of additional rules for RPMG +} +' \ +<$1 >$2 + diff --git a/demo/radius.cfg b/demo/radius.cfg new file mode 100644 index 0000000..ba8c55d --- /dev/null +++ b/demo/radius.cfg @@ -0,0 +1,28 @@ +[MODULE_PARAMETERS] +tsp_addressf := "159.107.193.33" +tsp_portf := 1100 + + +[TESTPORT_PARAMETERS] +system.RADIUS_Port.localPort := "50000" +#system.RADIUS_Port.localPort := "10002" + + +[LOGGING] +/*LogFile := "UDPtest.log" */ +FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING +ConsoleMask := TTCN_ERROR | TTCN_WARNING | TTCN_TESTCASE | TTCN_STATISTICS | TTCN_PORTEVENT +LogSourceInfo := Yes + + +[EXECUTE] +#Radius_Test.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_correct_auth +#Radius_Test.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept_with_incorrect_auth +#Radius_Test.tc_RADIUS_client_sendAccessRequest + +#Radius_Test.tc_RADIUS_client_sendAccessRequest_receiveAccessAccept +#Radius_Test.tc_RADIUS_client_sendAccessAccept +#Radius_Test.tc_RADIUS_client_sendAccountingRequest_receiveAccountingResponse +Radius_Test.tc_RADIUS_server_receiveAccessRequest_sendAccessAccept +#Radius_Test.tc_RADIUS_server_receiveAccessRequest_sendAccessChallenge +#Radius_Test.tc_RADIUS_server_receiveAccountingRequest_sendAccountingResponse diff --git a/doc/RADIUS_ProtocolModule_Generator_CNL113600_1551.doc b/doc/RADIUS_ProtocolModule_Generator_CNL113600_1551.doc new file mode 100644 index 0000000000000000000000000000000000000000..a6984a5da04f6a9eda6b09770a81225f31f5c568 GIT binary patch literal 355328 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	dNU^jpEG4 zdZbooQqmWn<Fu%QKKfY3*Clx&9$YgKM(LtxN`Wj_WZSYlj1xMTqyjxEm|%Y8$*&v5 z63NjEQ;I+&vnpfr&QS<k_~BmBjJ)sUQ3m@Gx-fozVX2>Xc!f&2c~=B7Uv3C<QMt=I zbR2hAU5H1UYBBi3DH_vcTD<9GZ@Cx8(RvM|!|}QCf+M@qAkuVc9-e#3wPbGmSK2e@ z7nvrb@JKG1<r#$yx4X1E5$DRbX1E(YSVTrx#W%>{Hl`DUqK~F~S*CLZ5(C3Hhy!c1 zzcLzbgu+8a>am!aB`z~sXxi_@u-CY1sdZhv_5A}q{nodn>GiYHM_n6hyyb8^Y<vv~ zyNB|$y>{^|BegT0L4x{dwQTdANsXm@lGF$<MMs59)80e*@OCx)7V;GAOB#a9j4{TG zOEx^Xq1;;{eYP@b$ioCB%fZwzg-aQ^A)4=-w{&P^oJ7bLx5W&aORglDS}&9rj;GS% zkl}{OSUu)S$&x%S*@K<IeaI;l<<>BwBx!1!Q!vRca3O5QkunX9!GCCwp>@j01c-*X zPW5rwX)vQj3xU9N)HZsvE6QujM+WE5p}=1MK%evwkP?aLN`)42)t;IjPT!dLhM8p8 zVXvsDuBcfsUuJ-~rnaJneuCFNm=rG&{YzR;*ZD}cqm)%er>t&z15^v9D<Nu{9Q}Yq znphpgrJpR7i1?-1Nk;U8h64?71|n0YeU|0T)y&jL_N-<44>M^}hOLRAq}Mi*9PaE~ z<~g$Zgb`0v<qSqEfybrP;T3g9(t`-ig1~ok^B3Zfm?3rY9b`TXLWP+kn4HnMG5LID zjLmAOiaTut&_1KAZO4TS^`uPuRV7_1$Czs2i*^(x4-LQR+#d0K6CR`ct0@cI85|fI z7*&>M8shPwEmAQyj(o_64W_&>?3_@C7FVWsuBfQ`^CG%_3CpbQ7$RC^3`EkobOg22 zh~0|h`tZzx;UuY`N=SC1mlVrvhsF#Pn@&wHovz_A#CC%bhm3Kkr7nTRlh}`Xj%p-@ z#kmwFoejvE&VkW5e(*Z7B>}Wdx!3F)(I82A4;w5p<|WJf%DoiQJ_waWuYC%t*}?=t zWr(6ydo+!E(vx?%-jPadn^-L&fyVtIh%p%HvEjL+1JopgsvyRh@_5{JjHDlz2_y>& zx^@T`b4bQ0dW};nWOMx@XNB^cXjen`lwU8?M1*D<2#JO5J^d-V?cv4-`e}>i8VSbw zqc%90ZDzz{h@QX12>e-Y+N+ktE&KfUA$>wLXo$xD1JG!FVuL8TD=l`7i4jbpawgpv zH9rVptg=-Qh>}__AsCsS0Sl!*qBAPuv;Fa&Ii`L0JD+}HAwN=s50x^s>4Fau(vUW_ zCq)ObM>>ewpC=#FNtX<5wKJ#-1T<}j)<jBSo3fy8%n?OM!tF|Oc-=rcH7v9Cj86Du zvVj>)SjN-$KA8#P1d>I<O?=6O&52f{wu-Kus|GzgHCUDp;g|$vrjf>4jb${vqLy6k zfEH9qIcg`RYJ(gP&%sgw$s?WcG`kjLksvZOgiI4AOQ(j=l%y!wPzv8nd((zW_z`B> z%IvK6tFoecL3Ks74O=df!KI{EF@25*f=%H(YqKO$A^s#$qk&#WZ9~qCcb?M@cOy%O zRBS^UgGA-pAGD*5@{2#Ud}U{sC*cNXR<uUi>`4_v2H0Z?R`@*QEpI$bJprODL@kEV z{g6|Lk=Vg&S$<$kv$qOIrMw;UL!Ha(Ja5{h>2XVe9lXw#gFSn~+~dZM#sgcMylEBF zT|_IGGpGCtCZZ|TZ3NP|ENTn(ZCk^<NFsQ18-wuATqepT7Y1bM_Vx|mJ;cmFT?q5~ znUrXF5;Pb-jj)XBTkhjYw?YID#Yzn!{j?b6@m6Dv!ZcIySF4)vWT1gYcx?4t>wRTX zVpH?m3#6DCu^J3Y^z<Z0MqT_+ZH0!;aC?FpISa8SO-<LQ(rcY<9HyNMmq;883DzPQ zO!6EY)1e#e5HtOTlMFCq5=`j|rE5*BE2h!%9H9$)6i#_E$Q0wf8`PczhE%%9Sut%B zn=?}6jjm@7Ht{KqQpv=_WC?>=I&a){gZ*AMo$nz$Kd&(o@}cRZW70b8tt7<Z$ynw9 zW+G%Ov-{k18!<9Ce>#yPyK>=N1H!ziSqI7H%%&?TX-kKi7bzm9SyUH|qsN)(Nj6NC zxI{Lod?NY59T(PnQ;S}hYEpoIZr<aPP3&q`ES%<!;FknhvFGVNT|Qu}w^}cZH?m5P zAdlr`d{(+E)|hs8NxWCRo8+3r*x;yjH_S9bwM^>J8wD^u3~86F^^#T@DN8Z2V}vd) z!ix1>CsA<v*LVZchO8zt>G|Vs@W1Kmsg}8FW%^xPgW*Nz==V#nFS7ynkmUeU-VNIR z({2&#w-<t{Rrx()p_Fa5YzH@`3pO+b6XM6skwqQiBI+$Mk(fVoA_+;f!+26QC4b(g zv8L`x={;hO=wCUD<ugL&ZquGnNi#AaGOc~@a<5elAxtvWw51V>p100hGnl}efTT)t zX*mZl$-RugCZRy6X|T`kBke3&G=l2TVlf6{Tr@T3#wU-I8EHuluJL<l>(c|HSR>^M zEhM%U)2}3S@pVU*0c==mu(#XyDSNx6w_^LLmLjqwWDt3j$`JJJ8(<kn;Du%hT;R?c ze;~>RD$qNio{;HOSka7|XS)Y_qdA9z8Hi9~5Obo%z@<lCWQw=65<#BU@e8tM6bi8$ zOp-KXfzpUb_bIAAL1N``TEp&8Th#43Hqmm0DH3`b`)mgip{KSfL2pfmZPIwr$4MV9 zC~=TEE|2hNy!0TSbPZjHl7xgOMx~nrSquw)A&Sc!_U_8=l|;+>hLgRm!)_SPse#`u zwc0{v=_Hf8M1>(^&K&rJ?<~9SnzWf~WOafFqHlLxC{7BGiE;&~s+^dl;3f%WX>Xl1 z%IZah2&xW-nn5YbY8NjEO(_toB>h7zqVbaubTK3pS!k<<l7k@>Y@Ku~8v~b3EHoi9 zYyu@38_4vNOwbdt%Mv19ocef<Ja7h&U8yf-nxQ=-0J(3N{sXB)vk@yp5;`RQvOWnf z`0YtDTuPZy35L7FG_Vy3B+fY7wtX<#Aqg{@Bo2RMHAQZLybdek3#Cx%HX4CZON{m? zB~2kAmr8V=3W+TYUk)WJG>wK$k_ker&eVn|97F*z$V?F-L^E%m*Vx{^thK4JtF>*# z+!c+>TN>2$%D&Ula!6|@k2H8@FtIM~x6~pN1j=PekvCgI7~<hc?6@~MM_Ha6mWIGo zwQ29Yv4tCGlCAi7SjhfJD-ooe<+l~Di|SN^7wR!MEi?TEZ+5<0O_X%u951ffbs;I; zon|cu=F;^&y8Tjhi&T1Ns2Yh?h5oK8to5+LM`LFUoh3e}9S-%lMY-i}MpDriW)G*# z0kez}Yi-A!jzUIyVKgI5l%hQuV4kHumYHK3C)a5g$qphYwsjPp*WqS3qfMraVnoY{ zJgUEm@Ck2F3VZ>-mZ2oeyaCe<Qu+kCLd;8JM_QeNbhW;L6v)=xQOh_6rZV|nSM66f zAm3eOnr)*<5z{H1c%iI>eAmfb2t>8alM!&QIh|O;V1NssMFKh2(X-?Xsuu)n^JQ-e zr~b*>WO76^_8WT?K<b-3PP%y}5Th|PmfI2lKu^^5%E^&<ihVOp6P%$Fuw=ssy++}T zM4xC&GQQJd8yEEpd^eZIgN`rZp=7)(&3LDjVy4g2nO^6Tww248rA<!}sa2I+V@51O z(?%!*uS3Xu^)_VJdXq}u0IiCMj!04;>SAKSnLXkYSZt<w1V+hN(qa0m9?mkJ%RqwI z2=yTk8=|pskD~p)^9+^xan&@?l#i*>QZ>ZGM%9`KRaL3mU~09o(z;--fe{4kYS`Tf zlJ&VF8b3CuolYGSkjW#a%Rfj|5s}ig%Dt&m?TpKaSvMufG<XL#cD9sxj19;0@xaO+ zkz;X<DXK}eL7eJ-3Mdkz^HzL2<BNcHDgE{_Y>H40PJ^&@-WZceh4pX5QA*n87!%b) z8{m3H1B{V`roMzCDq_rhb#VcRkkJv*GpXP*VuM*~!-$&Ercj5fJTF;{Xck}}O_S9| z<E#V~bxx=s9#+d7;`1JJq!)=Fr#f7BpcrL4=E1B2oo;G7N<Nv(-Hbr|g$XWzjN2ZO zKa-1^TOUK%81Xa2QOj{C18Fq&BK!dAG-SOCcNv{hd+wK6LSNcf(nzS@3z`-2=Yy4$ z?%m)%{MRuIF*s6O(<ya%NedV%LQqomI711`gPOD7_b4d;<(?OBj5^k0hKvWwtVJzG zU|kZ<5r8;jqbZpoYx~pAr&M|uT&TKNnBZcX)r21(m-%1P*34Yg+On*9S<8yWT}x&k zI%j5Z<G{nZTG~3ATRLVBCNiVpJ56oN+h<o|u8FB}{X{j0p>%?PI;w_N_lgIp^%_hL z_tAN`kvw%`jqezycvf>=Kq}Nj(^|-MMhIxq-beBwtmiDf2~w)JDwfmara7q2TK1bx zuPvRmE&&g)fDKxFS4!kaI@>1fs(qzU96%l_)0R&JDo>5&HP>~gdAD8N$ZPm!t^znW z+B&Ms#TxrGhSSX1ljP+sQx=Wn<Yeed>;x3)Gs96q?UH6Kj7*_r0EmCYb{Vp1BjoNU zyt=uo2S(>IVE`9_d}TGP(<omXt#ke+IJA;QcU>VzHhz2@U-m?%h*nkR7RyzaSeZ_f za8jV7kn0CBxcM2`C1C@uxe4(IKWQrcYT;ek$<f9X_FxeG+kWy^Z}(?Ek$ksp?i#<h zozJ|@lMZ3ph#*|W9dz@T@lS|{xM*OOaWgHB>Ba;)mnomxg&YJO!2(4OjjX?+p0ZZ` z4fdsi?sOoR;m)2}zdE;zK0~;dBw6Qnko2njvv7`^vuFE7Jpq->z%piEjThdaEQKd{ z<kZN_yYt)DY|2{;X5Vvud5}E5U{vy~Q86~i6)UnHzCb~27HX}6S?*4tb8MARO(rqW zLq0?+1-;Bcw<NKUo}@XQYbfN!twTrC5PApiRk!zG%1nLLoOt0S_F2xb(1}5Ke>T1= zC&iL*oFQ`_a#3O>u^o?!6uDdPL@zORB`ssObkO(l?90|-M4yzGyXDUD@$&L=EQZNQ zoI5Od?z3W8@?6#=FrJ~mHQl*ym+|t-))ifhEf)MUO?tO!8M=iS@|H_W&b7u1^Cn;- zj@|ev@e_^yOL<*uK07z<Io?dux_7nB&Rb$Dw2|^i*caW9Y-r#;&ouFQifE)9?xlK0 zlcO1VDQ>u|6(e-pBZ-V*aGfY1vV{kP;%1%*R+;fh8_X~cU%b-{XZz87mAptG*q`?& z-kbz4{T{VSkQP9<p1{wi4Gt`1)U(RdA;)u&*d2yg3n5;FG~xs5$7wuG`z-`Sw5zO( zOoTMjsR^~%)>P+f1GF}ysgb$F0Pwu+Bkj#Ar8Q<sN$)%)Hc6LKN}e#CGVXSp2g~E* z?<64u!sAWQnXP>XzY(VvE(T@-yS-x?=VpLHXP038#E^+kWc<1wB0%B`n9@XJj!Grz z@QJ_3+`v8Jt@0ApkcEawpLMNtAXt2we2K{QplL|zl3+Jcrk{TNYP*O5YRf#pcuPk| zTStQvZ8MHF!lWZYeRI4$_A?<Mk#MUpA|P_lxW|$k7Q@aCBP=7cO4Li2JFC;Wn*u@N zF5U_UVU>xtpJ}&43Uv}y2!lR^riTp@|Bp6)U5eJn`lLi#bmErrRzqEhASi8{JteM- z6;rlCVZV^_!MSqJ8U1*`^DG^)eG=0w5Rvj^%vQsz*0)=Uj%q1rBjy;RY7*=2G@~N& zfCe4+QM%~lpUg;V*euZ$(ghkRxe09poiq{aH;}y!`ub(?jMPO&wut8D7ungyAIURf z<_6Sk`yVWBk`*^HJ6gipK_#NpHN6jUI91x@Q5_@H$qy6-8ps?84KwF07<`jhPNDSG zG+^|!Wus>!6Qr#NlV%R9cDD%92%VMLA=#I}hu>MT*KOCuc|>N&LA#IgtXg&H$@z7} zW%k7?(#V=8x}yxycGlc+YAS^a8qi27<Z|?V9p~wmhC&^iaBJu{hcnwdS~^=+G_`oH zVU#TPizcKEod1e@&{RI$c-r!4Azg{hQ)O9Yu}!9_oObrjp{@%T(<+RD*}h*NbUTzW z<(8&-`WwViW#WJg5!n@verpxVBhV|~fko@hh@7-z!oOg0JK06!5gPLdx7R_?DHL8( zQJ3b9a96lMA}_9ci(!+z0)Y+Nb~8C%#?_fTtz$7%81iWA9SVDhR>?$IF_T(yy=O$& zR>n5VAwSS|PAw0_M~ZS?j8<8^lrChh7Zr(#)G0TegEccJDiSzfGjrl1CU@P;NK7CV zf$^b>rViHh6;pk6IaF^+B-?KIA^h=-2Svz}JMKh?LB#7^EGrZm6KBeoFD*3_%iWN# z@I>4J=fj&MLe)govxvW1Cgk|KTNXc~%sP;!<wz)pyH~DQx}t5>3Vim(vWn4d;Pn5) zlACQsU5=Jd|0GI9D(4+<o8<1?5Px^b6L9)r{eZY7*=u<T@#oL-$<o>xwt)0eUKpR( zN``8q_+rD!6bnX8O0wcZr|`<0LfkxD@%4C5m;{L%Sw~VtMrX3iZQGUxubVl?RxNzV zcI}X_Cn2d-f0eo5svfohj8;sW8`CqhHBv*4U5H$?2A#{MLlcolZSukf;|;bNwji3U zZ8KVp8|2q9uN&Yg;iF>X3`63d*8W?1%Fb-655!80nhLvU`y<4U6z;V*_2IlixxD$b zm$K(~0Q8PGv#F!4v$Lyl@$7h(&9cQ3x@S2Q`^3-K$LXWhqcX3pYe`GTs@BdHM9U*b zwP~iBLDK-$%%y)p!;qc#M2wxNai1~GcAkMBKeObq^>?aing%~B6%5V-+wPJxWDu{< z9J#i@$y{Kc%>9hDn)p>xaGk&x_D$*A+0arXJAXNYZ)L`5Kl5kdSH^W=#@F3)6Dp4E z$X6hGOic<pd(NE`<C)hxV@$qDJk7ur{Lgp%v_fj=vfRFW8xgAC9n@YOVMjIMKW0Iv z>w*zZl(kOcVVZusI=5L~EL%9sc8B?0Se;Bj2QR)dSbrlM7i!lxd-AV8E}#n}?by-c z6)V*#&zdDr&psZ(iZ)gns*1^2t}TxnI41DHoF4VXb<|*HPC;kx5!%_qh1bk(7w>HH z(WxDTcQ*N8^;FAi*<%s`$50X3l-1ruCYe6s530KE+&tgc^H-zd!VvjmVx&w))X)%b zyXVEKMc0GLUN~l^lv(*D&Y*kCPdw)>8#2|oM*1G}w`Jcyv$eaQU7q4K#8)s{V)o4? zSsjZSl>Jz^%7|^ozr!T7vGlNshD=>!!?E2^&?}YA8G;b4H_|&cr?fQWR_+t`pKng~ z=;NWg5`s@AhIl1NW1o1ui!~{Bra0q~tRzj#EbV}-V$l-om_ntibY$2CqNX=6RUS`U z+UpT$u7lS~!o*;YO#5*+L#tO(>DNmG&92+eC#PcVWnPpHQ%j*#xav&k=q4uLUzT$x z!`yIlbv3K$l7!gdzEsa#l<{#hbODhFN{`Ng#>|)K>1N$?PC<08@|>)~$P1ESccy!7 zazoBLBZKBfS(uYK#pEeh2fde5F1?yn1ud&)J*vCM_$16%2uI#=ixDY9n7~5DaSC=| zl(uu?ZAeaNJ5g;N11S?ZZ*T8zTCt2xR;ugk10%XzC*@1Cs;Z4>qPMEANw1}`-CJ(f zy2{*9*<Zo6i^FW0!de6!QXp}joNJ#9buwpn;d(cCwe@p?jTGF9`_LB<-r1FiFE$)r z@y@P93o66=v*g*_=AB)Mbc>pIb|um!YO(^(^eyx3m1MUUdK>Rb6xdv2<1=x$)pl^l z4B^owcRrUoAa2-}cG`T!#{~f0`b~UEvquf4|KD(bgWMe(WnX}hL&~f&=g0=0Wz?O0 zgWDUt3Cr1YwjVIPMRDZA8w5qS71R+MVkY6a6X9(O{IMw6!-N4FzrSt9Sj7G8XJ>L@ zIG$TD0_DvPcY0-if@-%{boTxPrlUdH*#%`Z;WcgVpxgLVhPUxymp3!v(I13z&WgCl z!eG10gHDW}@J0`<p)KPz8c=A*BkTQ85i|SWZigzFyEQX8dtoGo8O@^`;L-VKdPA@& z6E2tRIHMYeyT8`#50TUz38XLOHf5Td9G0E}gKI%5!e9xa+wBD0>L|&g%sY-XygjVt z@jC6?ayMZk;0Uj4C1h!izlWvE&}=KB8+yo~vu35!w=MTvUAv^N{_agI76|qu3a!jF zCdN6Ac7}<W#b<O(YUYMYb?n+qFrp{thQ^_hPgb+Dk#0QUPXII#d7C?3C5Fe4U(1nb zDP^Y(5psXt5uFhCLP)|3>>w3{iey1Gio)t!Gv|qIZwU7=Z;HLZSgF-1_gn}|iLF}! zh5CIwD?@fGSF|2VEEF*i5n$bdF6%DWIq_LBDVH2-C0j4pg#m#At9{d1K4z|TesjSL zEHmxVC%)3$g|?h~&R3nvYh+oIxcKSp{Sa~^Uc?kwjpEOU_Pe(-QVF@u=3o+8^*^M* zt{!v*y$z``rc|g5uur0{oHYEg8y@-fV+>qpV#^Et31(TzWBy$i(Qw`5tgxb%fmuQt zd$WWI4U`jYlw^f6eReliO&(IS$}LYk(F!#|&H>^hF4JK8lV~RVup8_mEM}8I8Doul zEapZ+Zb)ZIcYO4;FV`5%B+{$#R65=#vsvacp~G$4`^J;?yoI^-Ge*!zwiTDq+S14> zf8CeF+|<c42)jKqEB(z>2CF6h%s?aH{)2DLh5lw5zuou?2{+Y6V%}NlADWW)&Pso$ zG3pK&+imp)7vbMwrGFQec37MbYt{&SvJTXg)Y(ga^Qo}qm7rmsZ7QtwJoK>ltIx)M zbHf>FXK+Tcra9?QQo_xoAV*nhVXZPPu355gSBSDBfS5&$Eqiz5nHacVh1@WCvkAq1 zl06r6N_u4bg*U@kw+_>qFpp50mG!cUOG@60rvoWR6B*rc$&${xD>-99wy1bjyh}Q1 z|8o|mwX#$A*%(w3_1hli_%Pt9ldJTGwCwIX80tK0Qpw}YW(m$q66Zk{(CZ#5>}P0J zH0G2E8dHg!%Sf)->rkpGrE#OXa%}xDvrDSXs<Y1olH-bJQjgTe)Ah=dY=i<0Q>W55 z*>B!hCOvQU!0<e27^hCnDHnSR<nFX=uXW~WjQ4HTPx~!uUDm?f=V0BT-)4sfYcmV| zW_W7ptl1Q2PJyO5XxL3@-h`YNdb19gs*8vQQ)YP3b<w5EmbIkMZ*|?~u)=JivTT^4 zU&}-U%j2tLs<_B2Jp*s?%2pK?|AQ^YU6hVUnJyJfX&;eI%GlaaG*Sm=b&|Qrvm|5X zb5!~`Ju>KlPafedk}A^VJ2TekN$JE61iqc5=6pm|A|qr&Z0K!gOj<9VS&G3HuVlvf zRj4FR;Mjq3%_xiY*bu>rqSg{}$l$DerBYpD_8F1BfgO}F8~aMx%ysV*zLs^m<UYxe z*zlN{o9SzWEMeE~s7wfSMWBX}rJ{DU9IE3Zs}GNz3mO58mVC}es28N*v_|GlK;glJ z@GaDbVdJv;+KLK)EB0x89j$zU?LeCqh4c}ZAp=ToNjwk9v-f)BsURv~6gF=;{nF6} zNYYM3jPaH&J#-H|VUM$qfmg4)J)1QO!4%YBiYYJgH47tizUR&qU)gg|`v?dLe2bV# zEE@aQnO=kN(hOA^#%nVbndRS`8k04vsh%GFU;-<&Z8coAScaYT0XOxTeJfmi;1AK0 zVJ{s+Q3`diMq0YLjluqO^uNrUZjn3P6WBf}ll0+so=5j_qlwzI+MzeY0e@K0Z%@&{ zoB>KN7>?7u>vh$TnPg{2<LrQHXtYX}58(K_G0vc3#z&AHjadTH564v#h&I}9ia-Pz z>BVG7q(QbcFg7Aj#U$h*aT#8jZ|1_A0jprpD@&)GrbvjxOojJn#=8)g5lj{%%Xh^6 z;xiR0FI9Bl&yDJ3)26*lq$orzH?o&~UB^dxHfv~69?KbnoP+zPgV&*iWrTSm#1@GS z+O3tc6r|lrfDAe_H>EEn)=gwfKjAGWeh`$6Bw6{Q){iX~?c$O$uhWK0#FmUlCLNm1 zrjb7~n?<V7SZrQ0$i*yjy-~{a^bRE|=g*%nTWmW2l6BfzY;E|)C(pQb&l(%froz9u zq?qrbykS|X3uL9LyqXy+j3qn!KnJ*sCLu7E{*5<n*xD>dexsw-i`>^aRU~o;$Z-+z zzKG9?`H&hi5kw~0=QAI?-7WJ(cud#Cidcltb@oYKeb1K~hCL^>kdbgxQ(SuCj4&X@ z>Xl54bhG;2Exl83Ud)7CPpnOZud6AhDOx+An@Gq`?XslF1sToE7N{fEsH>ZmJ{{f7 zja`l75GhaQLaRKN3y~~81B7IG63JFiJE_M}F3%hJlNbKV!&&rkMbEnY`ih>F$OMX> z^+w!y`DXE)2&`}Kr783mjL8YyTHeSvuAH;rSZdqg4<yqm=4y#^N5iarUEEw<?8r!f z@7ZKIx^8#QkraEQh=)aME;BaS>OVCsN!l_PSDaxw+glXpLiW=uoTE-ZlLj8cO_Rpf z_xjaB-^EXx&41bao&8tE`Y<0xe8|X9nvK=TZq-eG9dJ$xNUKg;TEes0j9^+4>zAYc zfI3fl)y6BN1-47N3$$iVP1X9a>AQSuj&0=4R}z91v(Sv4VuYGfFaJ3+5CY|h=|f28 za~a=B`U*0}M_<vn?|1}$GLDQ{Nr_IYN9^h9-pn3*>`{O)@*>hDpMPlf(}zgH8?k@l z{_));Kj+|Z4%R7{pPSo4h>u4<)qMg^ofkAuTr=r+LU`9hl2a<r^JYt)0!3wwo|@!f z;-D>O*qY*?V1!k@t-|1v6siml2lWZNF3!p7wrR|X$Ab~Nr2|@cghte|vvs*vZE5&o z<I+ZYYIgRf_S+=}m-3bh0i=^D%d9y^|3pdsq26Hd41phj(L5vT)y28v%uK<Q6LOv_ zIr~N-90Ca$@BF(Z+P1O)ohecG(g9HvC;q`Y>%zKHh{ged5tw}Kqh|L{$t`}M*>%`a z5IfnpvTH@iP}=Ukzd^c^d(`VZc!f8cF*WHUc(O$gTUgSjHZEV}&901GRy&O7a@P)| zMl<W2P-flBJB>9p_Abz+9D0#eWKOCrFp7qi@Ed?aj*XC-y8Tm#ol{hLr#3&T_y09Z z`1DW7FCOaaip^3#E5AiUMSV{hH4{}8gXbDsZKxt`hJS}Qhu_!9QtO7i+M*4a+?E=K z4WBe*S(gab_s+@JEgdK4rNrrE4^51mihLKduvavXQ<lc6#=3t>S(efsXc@$41|~A% z$ZJb&9g*3s_N#{{48Lz_&j~BqSgPK=yz2z}6$lNVozUq<mhII!<J3$FkX<w58kiO( zN`2&@fNvm;K@Rh!{SWlq$%-!^cF1O_%-k;Xma<_^4_iSlHB~kC#xPbkPGJ+cLz~-H zc9rv>5RJAJr-79)5+)7{miS7>VwpYFG+o*w`+RtUyA^L6l@e*k2MKozLe|D4M(M%{ zh4U3j!nGkVDs7i<hQ*|+Nw(IHIAdX%hl<@xlN&PG9FYbeU*0rPqq)u;_x07BmWvyr zAaY&Wt}r+CodP#RDy&P9^@=v``DB3QoKE9prFUc%fsn=#8QM5+LS!aP?E+1;^{43N ziG-xHX_Ln$I025-mz{8W!tRePP`<k0^yRbkW|n_qv~ysng@QD*5_C4}4KYX*P5P%& zylz<r>IuW#iL6P?GFth{T%dSyYumE3C{jjfn_EWdefh=u=aey$1!Xi_hxtp#0)_Io zQ;W1Al$kY%W)h_A9L>J|blF^=uYiEaV`k4NWJAO}?|xF!#m&(VKPoC5%87UC<Aox9 z_BwTJk}c=?vK$VIHPd!z$uBsm<HYEMIU>rgw^^V%7=KAlKD~e?=^jmW%ZtUT=F72P zu9YKvqr-$ulgy{p0c|yzc67%KPnx-G(gV^Um~Jen!`#7aTeDmgt#<oP%h#1mc-$IQ zh$oe|DO!I$NI7d5sIscIHW&svJox5bkBk|~E`vR5*UM+fw1+Z6$8j|qJnOdWHX}E? zkts@{Ay7L)t^OsO;WH<oED$bjW&N*`@mBcD@vpn!{x~3=oUsv9U&J*Wsur@iuD_KE zrEV}S!F*EDY-%OWQ}C5eZS;g83{*%PhxaQ>h0U%!?2#Z&vTk#t(&Z1K%S23whY7|t zHCu0(PPV)pP{59d+CG)=kMwQY`eI7A&JOZ6i}<xyXKJL|tg|>yzf~d?UC%z$NQRX* zDS^zI)PYua%}vR(Dd?aZQ?_kqO?$|EGKy#n?F85LqXjBz(wTJG>IMHD8H#lsO`iw2 z3`}{HVKJyAqk2MEzElT${Mi8JGxU}_4K!d~)WJ>$vHNQITm3p^iAtP&b;E8YX3Hj& zW@n4gFt3|2V^SE(^aUT_F_-K)qHTgAl#ji^g=(fOqGLji0!1*}%4>N=z!(TO8^RG| z^$Dh$Yjg9pGZk8EXcEcVRmkYL6%bikZay<8@~f-n`E)yr8|{we_O97_5o0GyuY*l( z<w31dC=1;uS-W~H-r}Qo`bolx6r|C$2S&I>Xd*>1W>-r>bH^|W#WC+pxIh}L%cIKF zLs+3ETE_`hxDlJ|(48IaLj}Ua;Z@~T_L~Mizj&9BCHiV)9Tp;}K@F`kXHB69za2aq z{yZ8nZ{d@fp6oW{jc!Qcd$OVTY@37sY#0&R+{cQKAufaD2!#Dmv_w(aU<m7?<$@iH z!#gxEQ#N|R>{THtV7S~@k<?|BUHazg2Rwz!BV%crO8Hobq%To6beX;MhGpTOnGHiN zA)sB?OMDim4!OhSb|S)5S~Gb_5|n3UYiil|n?(5#w7=s_Ukdq*>^P%I@s_cjrrQ3d z61Eh!FW{y^b1Et*Hp1}D5Ycc}Xk+eEiV$5Rv{H4Ti^oR`%qUJyV?r`n5|}GsjZ9b3 zQuuiW^e_rHarw?oeFYVfdOB5>ev`2Y+69umJ57fTi#CybQ3@HoZP6_n9rNSOW&=rK z87`~c;|udG7aVJ(6bWY+ee=WvL8sGf{Fv#%R1s_R2ZH=yA9JFSgPcSXY55p~?RO>+ zFs5qAgqgL&sr59_X6}nM$XTi{HpWDxeT#`)xY2*QV)R&%W2wj3ut`soH=`Y9|4%x< zqu#!HWnqK2Dv_2ita8vVGetTYSIzY)plsgj0IQr`Vw%fkbj@7Yi!UV%lMEY0sv$Ia z*o3v0mi1~A72V5y3{p-4vm^z!HTFqugS*Tpq>9YLmYiNg{U=s$kBZB_sX~7VJjy_Y zoiyiDSY0Je&Q%WK>*VW+$@IJ?zJ^T+u~xE^XmMs6D?kr89N1UNz3EkJ@K!RBRX+b9 zeq){-Z8V&_)W?xMx3a!}XqpcvSHAYC02@OVT!UrKT&e@f3@_O~m-%xEwVuAQQ~PD2 zwkmF7<8;c0`J|NF$E%ywBf9;XJSuZ%kYZ~Goq-Hl?O=b&$X1Jx*ko?^)pDmw|2eou z%-)mHIi2Sh)I~`W3RTS2g4(3?T?~wwWR_7k?^C@Dz<oM2$4)CHrezStPwViNUs~IK zvL%qyGbToL%T!{W4pwIMqFdJXbkh#Ht2)`Uaky8;n3~B?ubVJ?I%$`KIUmm@y&MaG zvgb+N-3eu&6VtG|l7YQ#^N{A$bRFz<>r9$Xo|(`Ve#5Vt%O$sV?#_hrH`Nli$b4m6 ztOxYuGp#x>7XBiEH7Z$V)b!VQYh`o0H=CUTE@Z2K3#%5?uy3kNOOqa}I0nr1MS4L- zpA7Oa0Yq&(l9_o%(lc2WOm^fYiy=dE3dpGBuow$}<h92b4{6z$vV>%)9bxT+%xI?N zGr5Ra(k&Kc`)YT6wb&`Cw=ARbr<<BjGiZ!ZY8Ec9ga|^Vp)Z_v1vI-NU?D=^^N>gm z<BY}yS{a#8WdxsP$ZYD=X(r35hA{KZ(2RXB<UP~t3~fg0rjrF`-|CRePVSaWy8T&O zekNj@BD1R1+=PbzxZl>))za13)zP|Qv9vpUl|*B@LLwO*mnnI+J`j~J+{>47{qoVb zN>`%Y?8NN%`hq+mp~OoJ9sCNI4>s{sV`o!qt8@WEMToN9%Bl<I((DTxCN%%iJz97I zWO+QO3$dSKDPuHs-T}{<n2M84TS%SJ;FmNQPG*L(aY{mzq}9+#nwha7<vMA*(38;P z4NP>9TKHOMW?5*<tj&U&+X#1U7h5uwH^Xxu!Y!8@kmdnPPut=dDrZr`RLv4}9Quo& zFCu0<L2dL#O@r&xm|&BB!rnEopLkPR<xkqp+;#6T=kkr~^2mb3;WhGob+sXCn*vwX znbd^cQpoSW=^#9kp5InA#M}Kh#C0zbC$Xg2&UQfCN=imEBi)_oShAP-l*F4$MBz+V zu*6(p_PpGVd`Tvhop9BfabqP_-hz)h_{!MBe0T=@iDx>A#LCHnTYm`0?D!H)E)ID` zG->LJl$3OlUtz*vlX0*$VI3WksWr5a>Z9tk6WQ>6Vnk_O&MbivEJsC+W-3D#GH@<K zU2bxb1k0k9S#7NnRo|Cc#C8x~U07rK?9ee|kj|!+8&2p*&g;)pUmriqd^u7p$@6tp zQ?eAQj8{*&pQoZ+X5{>h<}7myiexU2<jJ35bjiH(^>A0JEz>2&%USMcWt&+$z_dJ^ zeI1J_vGMwnR_j$0GDS;el{2==24X+O&KJo~+ek#Tn;@P^&~o~D(GwfpApK(mUnkMX zb8<|fC1IJyjpC)&tg%vOJ_0B^SmAxX)<T)4DrgbVJ-WR5SwT@130SC3<SC5JzBjpg ztd9>!2U&MX7b75s#Ba^qb2BG_l56-z##~nuC1MJTzE66g4qvdx$Q#%JqjI_zO450Y z+HwV5OVbcV9P93;E?gs-CI@9go}Oz5nKi_E9yRrRMGK$S#CgS-;u?0hH?>(Wx0At& zH2pHj%J(RS_#C2j8(m7SX$&0L?ENunD(2UDNA$C^lieSqayqMR#EzOog}mB?2f+i^ z-$YoVj;WuE>()6-Xq;_&vdEgdMxx>cr&D8n{Ys-~)uaTurI#-!lC69;Lu6PeBE|Ig zH?zG$**RMB%F{;3Yv%L7$`V%>Q)P`8ip!v*W4OYMrI<#8VoFzBMxb1+?TS%dc_oD~ zzGGrFUq>MfBXb7jbN5cijou--{uVaeq;2+h;Byc9p+MWETyFXx+I_QqwFY*U(|B02 zn_}teh;Gy9x+!~ne#C#oc~7~IbOs%l_#04zs_8bOV!A+<YoZ2F#qSvjucB2FHJ}S5 z9=c4%PO7UVQ!hk{)!TtY(w!?H|3;h=vVp1eYF#~@4oD}g+-n=g|CMn`VG+0dj+}nl z{k5wLdw)gLr7Em0q4b^J_#fM`ZjkS}&Ti~%?-rRiH*EO-UnM?<Q{#$H&Lg=#sdQWe zWA6{?1>8j7MGgWNO+JVim$jjT?ZRmIVY=+{l(Ihfc#d2$Ww4tFMsxF91plL95*L)= zR~*SuXG_QKb<7k?ph=K!Ab-RRlIb<_&3adS<D&*9I4Es_0<d*&qd&~x%#`7>jPkX2 zY0cD$7ojw<=c1Chj*kJmaI{Uvg@$Ml=GYd&G>(>(>zFZ=MQ>mH#5@M2#O?KC!}6h1 zaRg+vBEpZT1k)MgYe8bgO+y81O<zAA73^?wI`OwZi10PUWm1fMwb$lHzCl4$zx@)p zy2}G`hPTN(vnKj#qq!>m7_sLhW=2^2G(?0#olLK_T?Wb}rSiB)TUL4^k`qrXB(CLg ziR$^0H3>_J#AU=LN*N@^7z#0RiGGRnO;mYIe@=pm8YeW-LqF`Mw$8RaZ0n;RlBY{% zHb9e+cNty{zv;qq`XVR!-%(<l*BY|}liE1qNm)8FaF&pL*tE1-FXO~fje)eP8+Yu) z5?oUzam%Mb^>d)q-M^*LB|J?&SZkVMmAGL31Fb?TwN@j$5?^P}Eb~E8Z8G!%+N0!j zeu5#KmNsN!gr=sHLUy*$l8=oR=o1I=yN38^kK2RSwyoj@@j+^&#fE@rWz{t@7d;mk z;w$BAlcN)OpPgOxLu}@K`FDg+);MWut?f(lZET97KYU`nc&2{(qb#!!uE>zdYf6OA zw1~H3>lrG&f5U`ZLUpirvS^cCkKidAugR&6ZG0jGbL9y5;#V<?Mp4da?h~o~#4>FX zPlB%zC#m*p%h!L?a?cCNOitcDjdk@kv&&T&{i}}hQ>TW?5YW{u**0X2)IWG6Li%xw z5@>)c23HL2yQMqVZO7fUGy9sUViIyB(e9y5FYM3b-Hk`BqD2&MF%79k-?T#dDP|Y5 zORb(WLbQ|l&8)Tx&OAw2Dm)$5MIhZUczLMuJgc*O*NhDgYHetf?Px>RQ>55Ev8UME zArelA1|Vry2Wicy7;P5KtZNWxAc82RJ|tZn+J)>Ek0~B94NC$S1pLKUwvL*awrw`? zkm!KC>r&UoQ7w5xJgrS*dC!`@xM@9TAfSU@XtCpY+Ti&cgGfpYCCUCD@kMkOWakj$ zesRY(zjpHsze2&lp0wv?=xro@%*2{t)8*F}r3rTL6={L>EmIjYG{}2&$eU9-%uPQ> zKkT0J=M98536V~a)Y8;K$CLE@6U$`-l10L@Ph$1WKwEhFMr1RNn)<rR>MHl0h@8!h ztIO%`NlxLd4e7jenqAmvS7?Q06A-rpMNyx}u{XR=A%yQ68|WTlPnPbE_QlH$>De+# zaxUilMBfzJ+ZV?tedx92i>)|i`WaR9t0ctr=W7t1Seq15JMYM>67*-1NVmgH2+{pg z+&FV~)l30di?Qb(x<^o^KaLB~>&;Di-d^#{ytek16`h^Sx|>@&y#2gcv&GA<lCwGU zj)>knV&2g3=n?be0sdv@^~@3T7?2#!WCrKXFRw4JOU~;f!KU{1Mavo&caqxN=2^4b zmo;`RYU^0ewm_}n)Q^~lMU%Zq#(yDHggO2z1(WKF$M^D%h*P({GV_iyRaxHFymDC! z#nF;ib^GToULZbrMgt&P{-YMRtZ3<I>}qN5?rdAx(WI~DxfXrBrziX6B`uB3Egh0? z@Unj``f`82dAaStgIb!p<Q4xY`e2IZ=I!ax6OpN&ELt2x>)7p8?Bp7z!ime4NN*^g z$Jf~sN5uD(e+2$6QQEuo_lk12jg1TKG&A0gQF%6uvMml1kc|r$^!#L_?w~<xZC_Ut zy3)c|A=tf40x9yC*>a&V(lBJD<Tgo?g1@%irv8<smTjsWsg)&rdM!A|1PJIJ>UW+A zvKm&30h0L>e0EC&dEZ$T-ojax@vdZ=>31n&%^TwEPE=~UG|gBD3G~W*05QOHhEdMB zRi<|x?(5iyp|pAS-GH((u_?pMG}ob&{9O+1ZfW>(GZjE*4JOzficPCluTCck8))|N zuBN8aF6oIj5d&iwVVDp{6P`jc9k*rD+fo4OY}rR;9_FBox|>cu(LDVkb(L*(z0wXE zM!Hi`q41hzwh*1&mAJ7Q931FL#u<Sw^_GhQ^d;vu5A;c48VCC@=cD~YUbVyxN*h;8 z|BMf~bP_t`B|ZQ#Fa!bDCF2vTHKw+-ba6T{!e<~TgBGCG#dIXfQR-8ySr+81ggx=j zm0ezG=LTYsLtKy@mZbV|iSLwZ3i2q6CWid)QN%lvYfx&4n2EFN%!Tqv<Eay;g_~6~ zC(h)DRu2nSIlscItF4+_;jNQdj}@%7oj<>J?)=I*x_z3IXM(I@b1|7*U(o=kF+0l= z!+m2=JYF%s-m9#b%ZwS188cqZ{P}Y$D(qf#e!aYGG13;-3Wzo-3~H)R-qqUGxS~v6 z)X(*FAZaQZt;47Y(>TOIub5X+U*}cS&TZ<@OfRHP^A>n3lfzSaPYB9q$(V}LmF(#s zR(|<p)qJJF)qI@Vs8qHbCm*{)!lO01u&SbBZbh}E?zw8|^Ag5+L)GY_7`pK=yV{C4 z?8QXpG4!#F^(#vbYj5dT*1BS;H?x0qbfjV4y!GqXm-h{imE)?-lO5ccL_oXC#((q7 zUTb<>-ak4tIFnJA*Zk6SkvI8-c8#kf9VTnm-K{$RRuG32!(|M3!0gVk5s6y4*XrGC zf!)_zRTVXr?v~gFX(jYVbwzDZ3YrB}`2)sKWTmj6s<v_}-Cev_ok3^R(k@wzFQ}PU zQC+Qa(%GoOSygSsgt);v@4%^x7k94k7TL8RXmzK|M|3l)XbRP7cD1N=MGfd8Qtdx) zMhgm&qNQc|yso(wl@0SN7Sw6>?TyvW+WCgW3r&+y(Q4tFvY8AbzalxRo21L52)GOy ztr}P~;LUDX(Yk65-umE}szzsHdy_ZU+*{0J1j0pKs;kh@9A#+@ZTxOTZ$j!}b<Zk1 zQ{+_h#Hw|sBt)fF&YOsOtXv##!;!=d#T`x!t{oViT1fP*!ztpQCEuYt)8hyOArrcX zfwkzUX^gY&PFDx}U12wB>Vrizp+U3qct?F>ypdonGF8VH?fjKC(T6JLH)@Ez@sM^n zE-TayX=-m#KSov<(6GZAeEZHJtYxydFDbX;9TgRgjD=-sbq2MTbz?jvAD9$ImuHgm zGHd4brRMSanyR|GimLfiUoDuPO)pTg$?^D<c-;IOkC*J=HMcdjci={MbRFi+44KcF zUUu(mdPzyir0h4Ch{Kfl(G5+kV93nOer1}IOqyfbdOq<ro%%(xY)<va{GZ%cn_D`Y zI$GPiTH97kFNyDPM0?}n7Q)nt)zd1b^Pz<!R;*kumpZ*^Rr9CMDJf}ZNC0Ek%fwyT z{=<C=(aze^eRObwb=&+oB`Z>l$Y+(rC6HT`maZl94t>A3?4isD1~++&66v*x%=GNn zr6MV)HdETXCIaEP>0oCfO`vE5RBap?VM1!Mx1^~*iDvYc(BLOaFh0Px^Erie?;N-x zHyc~r!z1NAGN-^cx4iE!ZtQ%2&I?kk+^6v!7R<$2sHn|(!8OadFSX=()>bv=VJH+2 z{l)$*|F(?9HUpEv=3oo(KCm}f2iAk*zz4x8;8buP_$>Gw_&m54TnDZP-v-|S-vvJd zKL>Y#$HD)C{{v5ezkt7jC&5$TY4GA-U)=cO#y@U+@!q@dyzS2GzxKzkees+##?Ba7 zGjiCPku}$kUH>(q;7*%udCKHt?&D~SEhlZa<ta1z-`iLjTe;<=*!Gi;kq08zO8v9< zOz$t<`N)`gyn4%1+76l=I~W{wP%M@>Xhv*@>HW2({r3L+gX&`aTgG-XDQ4dxvk$#* zQtUlilJ}dE<auV>>}#=|3#PZljQ%^1zakdf#ynxp$Y-k={ofeAoI-9Ei;>>Z9Tk+& zzrtHm`Pg)qZg8J>r-h#%T2eYC17cf;ug;7?_esFXz!Z)}4ut2zZ{g3urLovm;1zK6 zR<YQv;5}1gu}_0%h2rina`JU|RerAypIjL}`BM1gyzt4n;gd59o<tryJ^a`NPs}Tu z&xplu-#j+ylx-luj-lh}=D2+8Sn0bt+%mS=()g|KjcqmU(x+luPm68!-q_Sd@a^;$ zN{<44y?36tGbAOIN&L3NVrzRPgBi0X?Ko>v>zYX%Z+6~bY|DG+$6)E~X%Flbd++RN zrVOEfx43SH(3u`idybcPxfh1SUKQ*b9PSnzzB@QvaPJneNn1@Gj3u7qpRIPLkXjH^ zilc-)+lb!9;p@A=Heg#Y9n1jpz<f{vmV#wqIamSOKsylG=m4D{1xCQJAPv@o<G`8V zEO0jX3iv9x3|tPb09OK$udBh=z>mRCz)!)?z|X<Un>OCF>4%$czV7DBue<rW3x0UP zrk6LJZLgf{UrF7wNlE4YF&esLvf7GlZA3$iE%^zI$hIZs%@yWOo;M3?vPtt7@G3ja z@$J)YVf&PAoF-(6x=fyVN}FqmtmT*^w7m=b9{d430A2tuf|tPG!OP$uK=l7r5JUfW z1MddAgZF@$U{A0R><<nA?+1s2Bfyd1D9{bWh9tmha1uBfd=Q)hP6uazi@?R;5^w`} z^3jLxd+5jaJ#^m<Pu}q8cOJd`3y+>9S5A^EXUUaed&RMyU&F(FHy@w-H%-aq)Eno; zfhN^Fyl^(Vm<0XMNUh&~A+AMQxLht5Yx81rgtj+=o50QB2jCVUHvTs7L+}uI7;FTO zfIoxBz(2q%;8n0QZNV;JSFjs+H`pCWJK=#nz<yvM*dH7Knm{v1gA5o29|z}vbHOLT zC&8zHv^Adr=YdU+Kl1o}ciwl?_inoKf}8HV>5<1DImf?pvb~bFS413)MqXW#%V#4Y z^Ua++yfSZobBo+JC*m2@nD_Fe>trC8W8+I+VVMd1oP1Ws)Z;rw6T%WzCiMIt@J;Y7 za4q;Y_zw6b_!YPZ{1rS2o&ryUzkyBQ8SpH44s5@5EVcuf2Bw3Zz|NowECAJ@4YY%U zK?mprU0@|R1gruXFbc-NI<NtJ0DKHgxE=VRv;>B~yCa|2;yipXbh!wdmTjxeo3qTF zJZ~1}gh}(Ow5!=^=HpDjxA8eY5qT58J%2rO<;+Up-lA8+L!tlIK`ah$z@^|HVBlTo zJy?Z9b2E7Nw%BU$8*spOvDg>D|APIuM>oOapaIwAJn#%yifeN@*m^ql9lR(C>HZ3z z2=n~E!jDDn{KbEPgTf~hd}o4>70%}k--(o9f&>YZpnw+}3wye|icWnToC7WgSAZ+Q zRp4syH6U_v4fqE58TdK43)~HU0e%S{0DlAzf|tPG!OP$u;1%#H5ZRgpHUqnZ_W%#< z0cL^!0`tIpPyv>Lm!5iQ<5Mp^b?+Vb-uT@cuQ>n4vu@<dNpj^ZxiWnIjd#eEaJ~Iw zqr+mA@@s|BRB2VRHMLl~IT3B#$)uadcD(u4-_+!MW9P#5y@<yU+e>J?3@isLKpSWW zVgourCrE)2a4blJF|ZDt3Qhy3gD-+FfeXP!;9_tI5Igc^@D*?ixE0(6ehBUaKLWo4 zzXyK+&x04hi{K^jcknV0Tl5Ne6}-Oo|1_*v4xhCLzlFJzhf{{GA0^N1Hzy(iTbuXt zr2FPeK+ullYh_G5M8~u0Q6}`<mHO`n-VJsKdxBYDF<1gxK@aE!Nw5a=fqo$E!!ckj z_%Qeg_$W9NoCD4UKLEFYTfrZ|1K^L~LGTcG7;FTOfIk80JZ}ajgDIdCYz3;p>uLX= zp{=6cdH7)HvfkW}=#8-*FOg&ZH;c9ZCz>}SY3Achz_&Nv{>KWIws89|G_3)(;9$@J zIzbm$2@V0$_8$rk17lzvSPzZ^$Ac5V7r~dnh2Xp3d*J)v25=*|35fsj18@s?0Q?a= z2p$5Df<J@5gO|ZSz>e@`C$KZv1?&oT1KDkYwg4aZTZxlwn{cdLao&FtUnEQRt#|ks z9!q{68|heU?ngK|5$*pgUQzyZ-+b*iB|X;U7%A!aG8ZcodWuiCJ9rP+2kZ;>0}DYD zXa+}tZg4dC05~3;08Ruafs=vwg{Od1!56`oz=hx<a4GmQxE5Rot_QyWzXZPmzXtb$ z`+)eC_k-Vp=fLye1@Izx`jOw=_q#j3{kx}s_sz?{dBNr1y!;Wpa<;v4vVSG@ZTtYE z#rNWO=I4Z=+hOK@gl^`|-{ZNC_hz@bA9-_picdsx9yYR?$6ghdoWk~KT)VQj(DW7X zDtI^YvpaYXs0R&TAFv--2=)i!^EZM6!BL<a91Rj+4d?^w!Es;%_!Rgw_zd_g_#F5= zkbcAY-~#Y%@E!17@I7!d_yM>B+zEaJHiAdMpTP5vJ-_k(jX%AA<NY^1cGL6Ud;ZD` z%$0NeD<|74>HEbQG+bW1lkzgcE5qd<?>Ih}mz(>MHz&f!yJr+i*YUA1*G!o^O$w2m zi^$iwQN)~fpiJobXYd$!97td8|G*PqODtb0*a}Pq+k)-DZs6TucTflFK?B$q><1PC z=?@+N8o`m^D9{a#21&36WWXpG1LuHq!6(3{z^B1yfb=Op3qA+F1+E1zJ+<+kjX$~L zC)Z#0lY4$bV{kr(-ds7$UXc!hx#D*Q@*Ef%@3TuGxwvuXLi{stHk$hp?o323ZZnej zn)G{IEgolFX?$skl?gqs1J{G^gB!r@;0|ynco=L1kAO$PpMkWP($D{2@PD8Ld$lDf z1zUk_z_wsVuoKuBRDlJc8q|V1P!A+lun*W5910Et?+1s2qd@{>z$h34Pd-TG@7C|! zdewJs{mz%}{L+2r-*=Y1a*}^#*j%yJ|Ek@_=i)qbKf*<07yf70LT^q~f2&Ojk+jF> z$oPED(ccM;3w+y1cpiC+?JYDt2b>E&0X_vj4L$=ThVxnQIq)rTEs$ZU>%sTI4d55x zm*7|6FW|4>N$@oI8`uP%0ndWx!1lD5JAi3mI@k&93}gsw4tO7E1}$I_SOQwXK|o?j z%fL&2+4#~%KO%tlxACQq`&W$jxACQ8%@t?;-~FCKT7Kc~g}7|Ad{1*f!o!JZ`B&au zC|xH#dAK>Q^)B36<dZ2=`Z=Z)k<tf!j#!z{b2%6Q$AGn95DbA~@FDPF@DXq^xCC4Z zz5>1qE&~$Zy8>JZ?f`d!AAui(pMjr)$HD)C{{x$gzXeJ_DcA~31rj5SgLi@VfxW@= zo1Wiz&-1rEf77)$U3TqF*Pegd`CK{cp65@HD=E2hf?UaC-Q|*@!FGG(@_u|hGy4B& zuMh_dbHe1fqj@tz^?W=EIPqpgoW5XWJdd6il(@Zw#${kGm=7wzQJ@<f4L$&l2Pc4& zz{%i)Kw`P4g44j4z=hx<a54BY_zJiM+zM_34}d>{2f@Q&BX|V-2|Nn^3?}34OaTNa zV_Sd{FhP4S%+C2UTs(EpLR>Vw+T7fa@XEaTk(q_wbo4AH2UAT7k+jE`gYo4ukHwgL zjMO_1&x08%A2;%!=b6}E!bjo3KG6Cs@JCRIzk4Q#;iq(gi@^)vVEmo0fR{iUZOUa} zIxSp3_&(T~mh^P+XHbXT`51Tr)M7zT122X-v?+WNxii6&NCJgVBB}i)oavv#C$HyD zB<V<M6FiBOI+9xCPUIx=Shxmy9EthwWM-~hMJNT6tFv2}#UkqE&ve;EbZkqo6WAH- z0v3R3Py^~fJ!k+TBm08=z+vG1;BasR=mtlFelP%z0jGmAz=yy`z(>KEK;-Of@G)>X zxB^@Wt^!{N*MRSX8^Dd=H{kV;|F8S6LRxI}|HWB)Kcb`KYvDv%{}W8Ad30`~w&T@2 zc4>Uuk!u}_wJNbWLfiYnZ^7@uAHV}Z?7)NIA@C3I3V0R7unUvH6tE507HkLh24!F_ zm<Q&A3Lv(m3M>Ha;9$@JI>8}e73c%~U;vy3P6uaz4}*_@j{>nrXMwZ9>x=*Yd9PeP z8#{lDxs!)iMneAb-rP4QA_F7ly*%kU8OY_>_>xz+y$L*td@^F{vB_vcSklXco|l2k z!4=?2a22>3`~f@w{s>+KFM+><e}GrOt3cX_NnkUuJ9rQ9z#d>G*b`KMN>BxsgB73+ z91J=@Cy;h#B{&46K?aP1F|ZD-2PXrK|KGMLa0i(OcGf+c^vX%bLFCG?T(SMXL*F;P z{{L=HE_aPw9A)n0;a_1s7)n1hJ2%aId<nQ#Oj9Q!Z@nhhJmt-mGb@363r#-=P66kG z3&4MaFM$ieML^pBOTeYzX7B@W3%C{B4(<TI2KR#dz|-JwU=w&2JO`c!;zPU$UIH_A z#*~1az|Oz}dw_B<56lM#0T=7P{oWhCbHn9dV6GQe?D#KNhV7M{hEOgTE-ot@pZ|C5 zoy)87wQwT5=rF0~;YDHHFD3)Ur0&;7(!=^)bo^Inyc8@0D?l4)2jc5>fKHGCBj8w& z2J69b;52YLI0JkMTnH`#mw-#bmx1_;Uj>(e+rSUO?cfgZb8r{95Bvt)4>o~kz_Z|a z@B(-dh|l?V@G^LP_Wy?RTs|8KIl$b>!z-iBx6aLdb0RXZ$h?;)-NG_3zT_2_fWVUE zvooe1KQfvSmX9)_=T7+XJA+-ouD}C(fHE)_l!GOp6&wVXf#qNYkbXcrI2a6pVUPkN zU_CevoB=)rJ`64b7lTW{m%&%SSAp~;E(ceD+rb^+PVgh}b8r`U2)v&0-|~v_Ex<SC z=knJ`#sYIE4+jf#!qEEqdAVuk<4nM}@i{*cd229v<|%Dq`!6*83-}w@1fBu!qA#}% z*cNOLb^z0W^z~+d9YGaX03^a$1L{EoXaS4BVvqo<K@UiRHJ}eje{ldD13m;k3_b!r z3O)|b0iOq70Ox~i!PAeqA)jk*dhDvlF8J7E*T|I*%8-v<8L?NgS^~qznN{OUz?Um? zxit}r&o=Mnp}5oV@wr+|imo)08`jt&7Co2KlpwmUrR|_8EPR>5nvyB8IYQg(!1dre z;Je^^K>G7HfE&SY!SBHD!5_fGU?X@AJP%#~+tcUY0Zaokz>Z)iATfbmz^<Sc)PZ`? z0QLt5fCN|#dccX`Bych~1)K^_0}@v_1AGX)KKuWv>RcWh>6l^eWYfuCAMp7Fxo=KH zI(9Sf<w@5`M_z6PtCVt90Th;(z>egzGR7u-$!I}Xn#zQp7lTW{rQplp3UDR34g3(? z4ju##frr5(;7{ODAhDjuz~f+Zi8X@~uq9x<Ol&JK9n1hbf(lRxsz5cU0kuHlMfIQo z90FE>0=E7HSp|}kH6JI)Dv&INkDQu%f4DZ6f5m()BN<znH}i0?Fegl&AFIjDGaqLH zzKw4wCL(X!nmqHAHdoH91in}3d?+{!90865$AGn95PS%H7<>er3C;p%1BvZ@9GnBL z1XqEp!Pmew;2Yq3;QQbPa3A;$xF7ru{2u%PNPO^*;6d;*_y@=v^F3Zh{f1?X?|2#Y zi?F%CiQ&ZY^|_pw824YP(>L?b)9G(9DLBQX5Z1UN_IrFO$mQci<YG#}dc<Z4y<Y*Z zf=R?^Hv`kabT9+V2Nj?aECAJ@21rb|4%CB{;1IA1914yAM}nh40;~onfD^$<;Dg{4 za4L|v@af<Ta1po|!2dh$yXD)rT>0%=zWv2JzIfjk?mP3r`;M0@!*b<#xl(}Tk;{hv zseN+!KR%U>?*FafjdFj?r0^QJUra7vAOBx48jwehW3z<bmw-#bW#Dpf6}TFF4crNS z1bz&D3VsHD4(<YXgI|EZfWLw#!BgNF@GN){yafIZrZYA*1MCQP2D^Y=!EQjtW_Je- zU>~qA*bg*<1HmG&7%TyKZG+ATC^Y{6;C_YpXyl{E+>da{NWi1}7J74{`afV&h@|~S zT7lQc|0j$F<m3O|qJP3m;llt}3r+@~2bXyGhTy*#KRORw3T_5}0J}4?l>`@nIwIBA zfS-XE!x~ul<eBhePlit(4xjuXd~$dA<R=ABZV%u2PWa?o;ghdV>?HC|<Rp@GII-~Y zl)Ykoy-T_Y1T&G@9&NoD<1eL~;U8~4>5o%lJFt$}Ju``;zaKx@KE1INCTu-9&(oi2 zI@vyR*o+ejJoD)tuH_j?vE|tH9Bt2$E-?>}|Lh<-wHow*Ua$uAfqo$Ja102`#Hk)O z8=Ma=0RIgx1Q&rzfXK`9;03TPaw22z+k@#~23Q7`gEgQJ^n<lv5I7mTb|!Yi%<;J4 zx^G;4`9+tXcM<=5^6XR39y^tPPCdI{{^>nBhJMcISMu_!gxgtX^xwU|YVM4FAt8Re zET1=bR_3|0gBe4OJk7d$c~{rnleQ9kx~Bcxg*I&=J!$(Z_U$=OD^vJY7L?BD7Y4AK z04wi>0d}RopQ~K6WgNd<D(r3Kvnj^99cfA%u|R>(8T&7x^>yGba5wk`xCi_iOkxZx z4&DX!2M2(|!27{5U@aI1DR3<KH24fS4}2Y51HJ*i1+D{kfxE#kz^}o*;5XnE@G6Kg zKCv^{1?&oT2k!xUfPKM!U?Erq4h4sSBfycM8;pW6AR~U~faf<o#?+8a4{iG8^PBGA z;Q39z{Py#ku9ky~-Pvc|!P)MBa`0z({kLYzYmqT{WUfBel<(>T2j;t)$hr!LpZ>rJ z$bh8SbkMX|xHoQdUDX&(iFdwMe{-RCwl-<8qs0+ho?=s2en2z@WKp%mmsMMzSdG|h z;d2Rayq?3c@OuPA4E4iG8v9S=WGH;+h=M0=;X4yJj&GB@XF*@@md(#%T(-e3PMO47 z^_*P|>=UC%Xzz~?!0u%2y|DScJ7E{aHs(OLWjMRE{5{^x*cLLECF^gCzipOvCAP!8 z1PNoWN@^4Ro%Y=1Pw%wjbJ+Qv<ey!FEgN3bo(?aRZWvWsY`0Bp@~lZ)%$k%#io~o* zmKrRe+2-_TOQ&6WT<j=*ZHrSPJQm#*y}b{dskN~GoLKNAeB(d#cpTYM$+-tDe9KGD zWZ}8kV6nd*HuD|+V_TH}hhyd6`urE3OZzHq>rwCU-?S~t|77#qf&apD@twqP`s_RW z5Ai?M@^;|A_{ryjPk_&W^T6l8o#02{VXzU%+@WW{3*bfYcd#ej+F4*fun?>OZJ-l$ zfkVJ?U<3Fh_!PJVTna7&mxHUoo#02{=ipc1*WmZyLGTdR2>uM705TWrN$>)A8T<oG zX8u+wh=X^5ZNW27Jodz6_doI2&-u}VTiwC8_23(iefd28|8NAc@xAl${qPwDeENL; z`7W(d|J?K|wq26%>K2QmS1H9V&HpIW8z|)In;c$liKZ2+7M*weeu?9E+JD#nZ&>tp z(0}2%)8&=u(mVWj{67u7d+Ymu!gFV*uXu<5q4xh{SmU=o|ApsQ0%?bD0n!#nY{1Fk z?tLW86FCV#^>1?g`lBN1|9_S?`Yq4@DbDv2zw4fC-fswVaxi@IZ+|>abZ3H*!&wKt z4fsD<crO07_}LF<^Z#uf|NF+<g8#yE>0e2|>aXwcKh*v&T>5s<f8n|Gr==gg8U5x+ z+yA!K|DU`q_%A${_=&_#wt0vDA^kse+1o+?h3674+X?La4*x^^|I^!o|Bm;&!24QI z4;nxx=mJU54~9V+oCHn*r-Jjr1>h=hHMj<R1AG(w4E!A21%3&B1)czZ0e=NggTH}i z!1k<L+yP7jJA$1+1*im7pa#@}de90E0!zUP&<6U!05}E=fnhKLP64Na)4&DbnWr9k z@TvQsdgjOS-z`sF|I{t~XO6E54lfE0&ohU&JY~8&CWczu5sjgmt8)*|cXiM9d{=j7 z8U(w_nRsz{29ceWF@6*}8c!zPd-K>wuvF$ZXGV#O2N#G=H;B$V-q&&bPW$iTf9d6K z2m3EPcRIhEW6}GF47_dQKd-(W_&>$jd9m?g*Z(J*|AqSikvsqP0im1%juRo$_}|$p z-Uj+VMfff4wY1TjCeHgDYX0Y4D8~QuXr<rs@!!e9bMe8%@2Ue4+aJ;J$jN^myK_oh zjQ<znyS?@KFFY5&T72o$JNysz|E|EJf9vyKcrJY<=_g(K4*x^^{}%ncw?6-+U;N+T zi{N5#3HUO&5!?iR1MUaE1rLBf0@>Z@DeyGdianC1f?dIGzyo`LJ;7>lF8BoaB={7# z8axdC0bT{M_tEbMXMnT7ufQW<1$&jWfy=<<;1+NzxDDI^?gX-*i9gRPGR^Cz?_K}R ztG;*HMc=#VzaRVTV;_6$Bh2|a@rezOJwb-_i1#mL6_Dw-cOMe%i?dosdf}|5*xnqu z^%?Ss&={+N<gQy4v}Dyv*|oHP+Tqigk0t*~>d$VywO)OtcTcX$zjD?6elU5up1Y@i zv!2y=rYtK-EgTmxSC@80ufCD_UyYs7v|{r_=N-Qv<oL{RI~i&6BPZdf{zH$8wf{Fl ztGB-X3(uWC&qN>J;lGRj+=<@3_4zM67h7Eq#9oW7c6NFr$FBfqqYKN%abX*f37-sy zPX@v#z2TF>cUFZTi{)QCD`r^N*Q!ySvKcE~&5^9RRl}>-)b#3eYIO6arFXRd|4R~m z%kzILX?y<xq^(^rm-Zg~2|NWp#lC2t22Jx=htDFnCh#a&#jZy$fs!iL@Gc;}4qghg zDRL57Cm1>TL-?J$!zYmhB1^rm4?h+;`D*yi`QejDYLSz|nSLgmfF5tLO^g+GX5HM@ zvtv2meHO=H+tBrasoR}?&MQZqJ}~uYe$9J~aOiteSi8u#ru(OEu?_cgpEIkqCB*^~ zFL!ip_qHdlkL|RLNmW)vmTvY!>9*TUnzuEp{pM}G-RY0KVpjak+xlpZ-8yrBE&6ui zL!Ab%F9p|vUx8nP`+$>$Mr7bXa5y*u90`sF3E*VoN9<JfW3UlC0{#RZ1CN7qk(Ez? zE5McDD)4o14d_RP2EfVSgWweK5%5uPCJ_1R2PcCMf>XfD&%XTZ)6f3zqc1=3@~<A? zpPzys$iV|IUuS-<eBkAaA9(q5pFDAdHPd$=ii6d^_rgEeIrHrYZ7yqh=S)84^sha- zbSpOyV}?%H$?hO_G}&^}AzMxwUNU9NQDD73c`xR#+7{;6l(sWo;n0%UlwmOD)(Ll# zajrjiFBUEL>S0+|@hS(K25gC~fB5?>Up0F*FJ7jIgLtGH_gm!Nb^b0_k69%isfra> z<+n`ec`7&)oCPid7lTW{rQoYI><b2-1<!$PY8fvE+kt6dIv4@Rf-}Kc;B0UXI2Zg9 zJOcg%UIlxz7fl&x0gJ$5a1dAu)_~)|SHWfA2jCWPE4Urp0e;-T*dllyya?8^x5Y`| zN$>(VjvY771&RGA^V5&(e-HETedh3|^7HW1Kjh!<%Ap*5T@Ehhzt25=7XOK|?-X8f z?Ro&RUs^0*uYjlbFPm#A>z>yBg7M&Y9?Zw_t=C4c!k@=tcRBu;Hydadb7f_2fAnf} zL@<w3D97_jZmdRZ_w`^^HS2ibukiaCAUyvr_%WCV-<}WK!@o`J<e~6mkrSHM;4g9~ zauPfvM`y`;?*6_BwaQyef<(Zs=iX}CcC%w!oU~OmLC&@)nU;O6^xi44NwG=W-z#@s zee}^s%>(vmf~&nHZ+TsQr#;6%(`zQ}^17FKkK`|lUH#2`R=f0jhf9?>t!pIrqv&Va zwco+sBPDyvO7Vni$6}?z+xegcTn#?1<+lGs#{MEF;ivwCkGC=V3lyN+u_AC+pllOx z1BKCo*CBBK5|Og9Gg)~4H6V8ScR*})L<T+*X7BofC*d3a#>Yi<CG6!X|F6dczjgUP z#kI{b+SVk<gqgRx;7Rz#zy7!=S54co_?Xwj%HbJr;kIM4@Lc?^6Tl-NqWck(A36Eg z^ZZRI!36C8M{(0$yZ*lxq4}5Ef8qI`z{+}jd;IARd}#5h#h(^mTKwpp*+Z%fd>+&s zkR>A@4KpHga!UBl8$KBgrxwWvt&aXNCZWCTUD;dh_xM2S{^pJL=$#VTJ!f)a*5vHo zvD*LhaNgg#{NGymn*lq)TjBG;2QbeQ{H2+BnxLcwp9YkItw9{z1%3s74SoZDNsswg zVAo}g{eS~O6WDVF`vZUlpc@<wKE|wyuYgTYKE{6!KKbhh`R6D6ciWTSee#=6p8vt* z2cJAY%FYR%EtuZ_x5UM^|I~EQwz{)c`$1dydtE2EHngOaKKhg`GyF=|KE_)|H~jsz zzEy5|&lAptzTK+2-@3lt_S5?pt-8^k*?qfs;_gMi_n(NSFS~Wy7{GgnqJ6*Y-X7^Z zx!a2_9ox$<+@F27=yNS_eBZ2*^#Gs+WWbZ)`v<bW1H0ke2ewBh4hEk9*Md6ue?NFB z%%#F7PZfOZ&*3|flgK-TPktLt;D_OpZ-!4I34A4d=c4e*XTvA{v9l~Q!<HrJUFF@Y zQEkk2?<F=@Lcnj*HCq$&yN1Zzxx@yqAu4ySi^@%VZ)|hj#jDtp@j3RvTr0QbEaHB@ zDLo1pYvxKEv4vA+Ijgvx@b0Na@N+S77Vz8>^uLuoJHRKwRp2&oI~ZGvo`ZY94D`DJ z><jh>jo<=sC%ARF(fwzAx^WOWc`STqW5JUL!gpTJN#Ue_9ZtIN$pkZv<WsnEKMH4B z=y+?}deI)A{sNqQ!R^(S!`oQE#|g-wlZ1%u&TuwbZ1ZX0d9XG1`A~2eI1Px+{wlZy zY}L+qKUfTwfFW=!$beDsDexKa*KqYBCl7`1{62hgSNJ4y=l1ZO$Vud}$d;_HC$&h@ zZ|;d-gSasEH>I_+Vs*1(OJ)(Lak?7I<#1t(65@EF{baY3oc1c&?)1Ai3+1*~$<bV} zzRq-Mi-ots(;dMq@IFurT7ctmnq%SdmIosPU|+BpTn+97_khR2b70#J(g1sdRb9vu z_yo9gCHwe*JrBXh1pf`L0Vl2^<_|ve|JXYd0IQ}yj^FoYnr2$3Rj5p9Lz4DvO-T}x z3R&CJv`s2YNJA?^_Uuv#DcO=GsYFO+O_mh0h7l$7H~-J~+;`r)_x0X1Q9bhR%;(;- z-E+?Uo#mc$?!CVU(_q8;56$1o^~=^Tnm3ER`*;7i^&9xRY<=$fzF~2O4N)tzX0<l- z)q`D=m77_YjS6er7zwOS9}v287WvLzG5RcxG8|m%H@_|v*WmWmQip?FKWctqv@3V) zNLa1iN5VwMQ-OFYq$<qE-E2<vZi%_YkpIJqoxGFzucfy7cBoucrpLhyco<Z!uYt<8 zT&O&c;#i^!-{C-i*bLq>evxwC5-t-Af7|ktH@1yl%cn)NyzLF<i_K^84H<ksKFf37 z*k*ezzF>@$<G1sWE>0~wdUSEdZ|m{rE~O5miTB_M;uJ;`J$TYM#f~P7zGqW0B0a_S z{Yyoa*GjmOcB%F`7hVI~P7kAfwg<J>m9)(dU=92M|APwMXzS1c^t@|4d;lNA=dj5u zq3`2b)_Hy6TYM4359agno%5bIo#kGO@0>kl@kz&<8z+M<*xn&ReRa%QQ%Eg~lzaS| zwU7GS2jNYyWvj9~<t%>J3)Vuhv$;P&88`?IhC^T_q@Ck9b)hNT3ctbr=kl9j&>l{J zPS6{!fUDp>`1PmnSHJN6>Z#w~Y5uOhjKi?+hYf<BbTPh-H{QPJR3@rt)11imwSHgY z8hU1H%xKMzgfK4qZ9l(q?+x_bS(W<NY<owH)WRX?e?L6=^-u`SAb+f8XLCiqZ*W$( zvoDTHWrwrXgKfTDz0uzA+s$n4eZl+AB9e%ts<#-csg2sQKA*DAfzfakTni7vV)z(T z7ruoRp|byy<JVA}GA{wO!PbSXm{k{k_m-ruDJI0S&YK-y-qv`1;#*dDgT=S_B8Z=8 z%n3ncR8Na9H+BhgP1a60hWY^>QOG4^i`%w~)HCd(GO9>>R6AAsydNHbj^|M?U;qq) zD`5&e2`@mY?u_%`4Ok9e!q@O8RO-PqV`u?B8T;;#zG>2@j%V|o^P$JXc_$H;H@%6z z>b30J>=1KWEj`M0OV;}&%JG+ZxMz=XmoWGEDP_+aJEd%>hTu|eZ2LeD2)RUR*goou zZJE!-tTI=*?gRTla~K5^;Z~Ri55g>%2Mb^syauWV@AY7O06)VP_yel<WL^Pvp$!}h zZQ)zldB!vb#==CH46|SnyaAiwXQ;r4f5XRbuUIf|#k>`dtay9sUDxxsV)StSaM9m_ z6@zpb#GiQwX7*@%&(PP=8VcFoIehQn&T?(npQC!=urKd*M0~w-2;Y0)+x4k7HSZZ_ zhT*?&aGyD)LxUJ;hwn4C2alSq$luxip2i&|a+kAL>b*ng&KG@`I9P3T0?dN<!Is@` zm{oSgD5GyeWmUj2Kv`r#HmK}6z-&+%rS;~Wo<6)M25-Yw$Fun?@%#SIJf{>Afo~kQ zs%Yo<a!^D|{B(SY#t#<X$D8Rw%;B~k`<GzM2;bZ%CIsC3#01;QjqCW3>v-$x?@21F zoIZo0w6CjS1}uh@ev~a-3DwT0?ZXndvp;=2G|WLq1KbO}cmm@a$@+?So%iD62m8ny zEWX7Twa?<a887z6_N3P`t!S2;y}_8t>D|f-shMT7_w81F=z%GtD!#J6e(H+5@I{S} z-`>A{dB1-donI~`v#dEg%D0p}O9kZ>oV)*RL>r1V=Dg3O7x`VGQUOkm{cA$uw>)FU zV`@%0^{W-(P-p;$K_h4kcT)Cu!Bg-w%!6m)IZ%C2UAPzSgZc0*ya_8n_2ZsU{dj=m zG<X3Pz+3P(sNRf$v2Zio%cIu&;6a!PwFj{t0qx*+2>qVRuRnjH-)dR&uK9cI`H*4G z)Jaq4Ts7yaOV{N7YzwbqrT!9EWwY0K*Yv|>qU`jq3Ux|{;yf!V?uMynS7oe^+mjYI zznZF8?8~8gw&Jee*pT5k@Hw(%t5E8`*qMJQwBoe63dcvDw?E6_yCj`)%)tTf3NnSB z2W1VR-?gu>^4hBV-r%&seph=ZiGEt-9IP^s?8}5?E?M^u$@?CT(_lLMXho`H5iP#H ze6=@%rEx8tygo9I&`VhNaFs=P2y1`Q<-hhTF7ey<j{2<(wJTf3?_qvlWexe@P>TYP z3dNu}91Mp*eK-!<!ST=mPJ+JB56*{yFbIagEpRK`29Lp9cpRRBr{NiR8{UC;;d}T2 zeuPc%Gi-(u)P#~y3Ti_gs0)WceP{r`ZT@oY=65!)<?qXv*KU4RhB?+Y%^Idy!*w!5 zS3BFjRu1>KB)5Gn9Tv;=`3qvXK0Y*-Ym+EfMxs0XU8sX|{V_$iX5uL1ccN?`;CoxR ziQ4u;P}!#;UzM@ScQE|m6^hTY-s_{965f11K1(>ro-vqyV<r;Y+xv||zGLLQxE=gP zR+`FL?Ne=Y9$e!sol$WuUXOpNxe&RTy3>HxytmgKCq-qhzE}P3FUj)veE;8qK7Q{n zf0eoJtGcHi3d#1*P{6eRHr)C5{_<CuYs_>WOiq@+r~RKqE!g|Z-<ExM%Kj1<30JEg z!1Ztg+z8LYbMOwl3tzwn_y)d(jZlWsR#~VA2SH0X0*--J&<4(f?$8HvU?2>Gi{N4y z38UaD7z5+rdbkO0hCARsm<H3~L6`$`;Z6AIn++ds_=Z0WE3M&WV_2}^@dx<7+0TXv zp7BdOEt-Xo&I=!Rhu5B?e(TjY4iC-dzrV;o!gpsIpI;cubq)2?JM*{W`xvu=_`es` zSZ&^x?{}D!{lD%1Pe<x|fBRRN+qRoc`$?9+E&m?0#l64$RpzZheRDTZ|Lm&+qdncD z7K9?3&k}L|$C&=+@Ba+A_&-qosrG)Xd+~tivLER!OW!h&*W({)E@XDU<5dwe{{QvA zQ2r?@bB)0?_PQjx{QuMIKVvWX548UjmAS^;8f%YDmcM8ISB~Cq@4x@6%r(c-+-gd) z{5|D=?|-8FRpy#gYc4$_S^l2#KjhN?Li<;l+clKOlI8Cy|M~xk@>iMLwX+q;^7oYg zahLrU+P}(tC9Hza;TuTK|Mkw%+y8~~Pt}^aEq|5$x9|u238}oJk`5JNAE*L{LnCMd z$3i<e9!`MX&<FZLf5?HWU<{0f2`~|^frsE>cm!s{9C#I$!E3M_-h`F#DXfF_@C9su zKcN5|p3<j4s@}bUeV_{L3yq*LG=Ub-61HvqY3qjf^|xZ{lC3NFbItQ3#@P|$1Fmt! z*4r_Vn7bZd@k;;7yX#saFP5vr`k8l?-VM8jnf3Or8!z{}##qTO<Q<`+J!h~_2{`I^ z!;Z9NuJTqHw+CPQkG}@s^Z7?E0u`F6LRN^(`cHRCW3Qk8rK-HucKgHCMKAk8CHwF2 z+)?@GP`~&3@=q~kPPwZOUXd(+&-icn75|0uSDEV`tNUs(?vF+6`~MwHywF_ksQr)P z&b{}yf0en$O&T*Dkt}~t`=5~aUnqZ-`H|2SE=rcar~GeZl)v}4f6a+(`JaY)2;{<0 z7y%c;#V{Tw!2K{49)~Aj9y|lj!gKICya5mM_Ut3D7?!}x@Cv*N%b*!=S2l-^a0+yS zQ{hZF3x>i4Fbsx6I%Dz-*!KN~Z69vfwn4|095!rw`K1@;&z(PG?o{@--*|cM?HtV? zy+7LjXOCst*8lqBPvJYP3mWHIo&9M4Z_(u&SNp%53)TK_&x>gPw=R5f#Z0PEy#{t} z*ofrJ%uXTj4bS01c0$V}tv!zqdDtA!)$eEV)z|D(r7=j~cG+*jLi5dfV?uH2lfCda zUe&MiyM|K=h2pKW`0srweT6$jZQhpee9X!FzkUDbF66uSw||wnZM$l>?}FN9XBZEk z)8_KQS1))oDzb4xWaCTX$c8$A$aZGLNK5xxe8GGXxS>2c>(zA9LchaenvwZB+L&T~ z1LuYb@ICFaQTw7qAl_HJWofmpzI^j(CD%K!&kS1KUSIwh>QfJZET{qX;2<~{a$zW3 z4cEZ6a6Q}rsuOSUhU9Yimiq7=r1Hj0F-U_9C;=s*G!)})iZnO?vY-YW2(_R#9K+Mr z;czufg4f|w_ywNiNz6Q02cN;VpT60)?wf7jY<o|;mD^S>T{(a06YR0g{AL>a+b52? zed6ughHe`g{%sCb1*?(4d<9I8dsq3pLw5yr|LS#}s&4<>Ed5HWLP6>v&P~74XkB29 zP4RfWjJy9H@bxXBo>^h(uhGDxJA{dU-(dQcDFX&Zg^*YH_c=mm$&E8*GiSOhhd<ox zkDK3~Q3%g(&xG#-p?KW$E{HlWbRVj(a#Z=8Oc|URDhFEzo00udtb(5gYoHe^VkfdH zlETb*7Bpjq^aMN!W%KxE5WZp5bPhe|x$wKUmHRB;$Mx|AE23qCH@3fGDPlV7yy+}2 zn#C8jF9PrR+nb|)DJmz{FGZ<<-Cv3_rs5Gj*2Z2)k0{LmCQN0uCzWsiP#J#~D(6c> zWqmH?9i*&nnXknB0jz^fkVV-yg(-RH1EB2Z&}%*h%iuM59ah3Bs4|Ye1)4!OI1A2( z92g5%!(DI>JO*>&ad;M9hmYVBSPP%RwoPULxPjk&dV2|fPi=d9+oRj2KFaP+{arI= zoBl4paNC93uDKKKE46a&4YhaaQ2gKN8$GrUyUnn+>b8|v@_eCRDe}cX=Z@->XG6Q~ ztM9G;b{X9Y3-4DLs~z3r%TSEl^)B&x9rEGodNxH#Pv?I9E1T`<Oz(t#1FxIu{X*@( zf!gT>ludQ+fM<g(BP-)N<LMjV7uXCp@wvp!u>VB*N_Z4z!#-DYF1!E>;CKcM-+8Nb z5iM)I=dAHs-t}5u^;&$ve3tm<#P{(<?X&FKbG%nz&86u`x7Q78ir46Da!ujZ8@Gkq z-lI0(|MEL?@q3TTYDX&LCU7F01S;<fVIru^i&NeiV9Wk?%u`_&JPN7@4WJ=3gCpTY z=mNc=9}I)bVHAu3TW=o2{5U)hOW_rGAJ)RB@Fi5HKH2(pFy{Ku2wH-zZwoOmf;Zqj z*s%6P^S5E~hUaCPi6Qd$yz!eknZLCYjk|H77|;zOAxlq^bi_OL{VmhqBSdRca_YqH zIkpQ&%k5gHjqO3uCa*MYyWf${Ce7VUMez4SO}udyHLj+T)%&3K`Vnk{#@A9G;2n4u zI!tn$)1e!j2~WY(P~ke}t&j^tVFhf3KcV;yyjKdB!YnvoGWQA?3KzgIcpct=vu|X~ z0R5mpjDp`be6r?~6${ope)HpN7KHw8UbA4_;5GdgjO#v_-I|-%s24wNK)}io+nk!S ztt~9oO7w;qrYAp@<9X1tL#6FBVL9kz@s@&yed;}pzQ`jg^*>>7*-*@8Y^X@nLy@Mt z<HPjW@rHVDjp5YuhHDo3zaFbTBowDDFJG!*O)$!rJwIIfp_&?Y--)^xxqH=Cxt|_Y z?pJxrz9?nBlJZWYj8*0;@5@5v{e$h+bo6!XKFe}%u!a8_i!QWu{QjP=S7K|Na&<qN z4xkY2F7hV|v<b$J#g6}MyNqs=YLDkaqnqdt-~q^F4p9zD-9pY`6y!q>#y&ma4!9E@ zgH>?QZM1868k*gX?iaWnHhIf9Y1yp;*+DI<s=oFLcmQTXamu*@*m5sRd8^#Bpe~#M zCqWPB4cEafFb`gUCGax51wVtWE2<-^AIo3`tOV7OdejZolQz%}PJ)im1<r!A!PcP_ znBRug@DUWiXKVGh`jz?S=-M7%`^eg9uUw1E*s%N9S4;qJ&GVVLceEH@?XTWDIQy7m zo7%InMS57>qi(BpuJtSIF0<o10&$H$^+_9-9S8i4yVGHkVR71II+TLaPzfqSO*jx5 zLsPJA_-)LqVGXQ>b?_Pd0nQZWi%=YDKrJ{NnnO<*3?t!ExB~KECd`2+;W=0WFGKY^ z7&kyOXbz`9C+G*`V8ffCzt<K&{@Tq^f0IJ?agSf@{;9YNlfGZJ*zT^n%1ZigNLc!$ zcW|F4El=IErMk1@mnQD`W#>jG4b&e$3RdQKBG<d%6IcuV?nIXtOopf6Cn#|j>w3@x zy1}h52Ofh@U@iO!1#r{d%opKJSOEv$vs=5n<lQ7nysGtuj54aK9jVM$!bcEY?zXH| zzA9U9xq8d=Y07mTtb|qY7Q6%R!h0~}Ugilf5w3=7U=myh*Tb{-vt9&mz#91RyEngk z<;R8m&HV2E8}vWnyUQnB!hXVcgUzvT_rAXM(a?C<u6%@^opq;w^FEKGb$OoFea0Qg z>l?jlL)$&FUa?Rw5Oa*~Z@W9&W_MSgWBZUD_C2-L9?ym?l)<q3C_6X|`JWBvK!vHa zaaa#a9^f0{X|(g{^y@Qtw-?sH*U<Sv-u<14o{xvPcRU<b3BPwd+h4JK?K$6h*K2uk z4_SO2i|-QVd2<loLa6kzj`_u|x_0%oQay)X{4#E-J6Nf)D?0ieu|ijL%<q1f*@5TT zSS%f}CQK!@HI?xZZ~~kNr^6JO0W;xIm<@B_K<YpfXa+~az3?I&MZM?%=RtoM3FBb~ zJOT4y0W5(!)SrfMF^qz7FcW6OTd)=i-~j5?xiAWzfp<Xl?Puy*Z|a)r+ca1Ni{U%S zqW=B9<%i$hzYXU2>F;mzx0Jv6bAIP<KD!@&|J3|#nKSeDEi<=_W3*%E|J(nzLRdFz z5mtsDJ>eZYYKU5QHEXe~(q1~cLnwsptE^A`V5vAhpS6D?mXG(z5*ooz&gvWrWu6#C z_lUMv@H|y&B6-z=V?b^9Zny_tft662wp<C+ru)D!xCQQlyI}@A2v<BpIlvmIJq!Kr za0Z+SGoaO@=nI9PU^DyyN6n@VL09MpL*Z(;2kwPuU@;UxyE&{;K@M#Bg0-PFTfW%B zZq4$ATjq1vvStoEv}UUQzTj`o)X5VjPq^6II2lpeGWM_Ih07Nio-^>MkPOW_IX!5^ zC8oY!`f$&41&?f<sPZ@Q5jql|bO&eWwvSb^_(a0_>WM8yV)E3rqSW4~{HWH|SGgWR znH>v<Q%>2?DO669_Y<({G1}x@^u$2p$C<0a@z4c+^$Pe~uVsVR@`2al^ZDDB*S%5u zmXFAGWQ%W!gxTe$Og)kd=<NdDBsig8fCTiKK~Me0LweiI45jr0^qVs(PQN7dOHk^S z%jjlMDp;l1uNlElQ@3W&Lr>4Q_l&q}{!S74`|a*PW!0X>!qsp$+zWHzad;l`;ZI0G zeyMN@bb_hy0IUSnkKZAK`cW0CLm!w0Pr}FW38?O<&UA%7Fcear;F}ZZ4>>R#E`^U_ zEqo0>K*uLZ8#=)`&=Z!zEAT434<EsCPtjMv@z4dj!Ec-Ox4}Jx_aDgg*5-xJZeTzC z*~wyqZ>Q=|C(>iYT15``9Ow)Gx%9G7OLku-OARd#yX(l|klr4mD6JMfVX73N--)GP zh&-wE^$R=d+dTb7B!(8YJo<*pBNbWuI?VyzMiJlQ4V7qfA#Zk1(3?FUGbh-oH+$MS zDU&izuh6E7ehL0{+GEs~wlOuzg=xjgve9lu{Go4YF=s2#vEmkX`)o<!;i`7~y<bW` zmi_(Ks(x!VzqQHxX-=R-${?rbmXxg-BS)D2CspNL4AchCfO9}?(N_lsDL-~Q#~O5u zZ}EoO4d%brvpS~yFTOol{-N?OX8YX{l)3udPom2{ev|k4?1m!#%TeyA{g-ELG1>mz z_OJ5x-e+}>^|gIpDaW_`<-*zxC+?{HXD7=)-2X?9sWhJ2+snT_>zv8<@3#Nw@w3Lx zdwcnRo-F@x`;VS0E%*<V{}nvLO16Ku{cC>w0;t?ygtuS~bbgxoGjxT1Fa+L$x8WUF z58pryR=jIM3up<Q;8f@gUEpju2Zq6L7y%c;)o>5YfiK~EsP_!-0zfOshSty?Hh%oU zk_Eoqle4E>`{V~>%-`&b`FnEqfG5LiOzu1OwONq}Kilclp_typ550?}d9z&X+g48W zb05AN8^=SDO8uWNbAM<~AButR#-3RG<F5E_%)1Uy^wk49i{H^~zliG=^`gsNWqz@D zOcsC0=kxKNl4$de#((?r95dPe-S!{d#?`*}_VRx!S^nYse{_GYzI<;l|5NTxwtu_+ zr}91!4g=l8yTUavW<K|1h+h|cOMhLweg27FOS`xhuZL@nJi&<i<}<@QN8x2w^W<d5 z&qz{ufD-+isOEXMS^xVsS^l>D7uWde1n2-gU;r$FW$+f||3#=ClzEm{l_3)vK`Y3H zGoTxs31>ks=nW&`Qn(B*hsiJ<o`x^sdpP4c&V?b63q#>zxCBPR<FF7ipQnyOeK;99 z!YOb8JP%7@%f>H1G=Ixpd~Vru8^4?}W#e;`&7X1I_~n?5&xOL65We?D9CyTc(1Ptp zj4?)rdh8W@WVq$@B54$`W4IX4V~g|_LcCFIXhf-zs{d=!(AahRZ$+KM)y7q(jX`C4 zHrxn{k-OwAIS+$8kgPYt0Wa|07Ca8Ekl8gb4}SHwXrJX<ug`j~WsTSJZd{8mHlO8{ zxaV+Xk<Dk}eS*m5%bPC;Ga`X_iNR}$Wwy^&>)9u@p=Y}l{Lgkn?*JXlbKj+<T)(BI z+_&)yeeSyxePirj3RnMU^LUWWV|lfm??UC8LwOE@To?xT!7TU^Ho?zO04nn~a0008 zr+~`;Id~qH!Q1dXY=#sXTN&6N4uo3J3bNri=mKX$e;5iEz;$pvyaT`IZ~Qd>(~a+J z%;)drCpNykarzyYZrGSVaU*|MOuWDxH^wRz9-N_BqrsK2-mxg}_2Io)zVg=F+L6!> zAvPTNbm-hr2)@d>;p|EwxA50D`*~g6kYT@?mHMC2zkKKnp5q?dp-T7z&2vIumWRF% zjpG~s0yJ`>eP?KNTK!npR#+e7nR(Vzxv88~7Lxa!Fau6~34K6tBfJi2i+FbzPK4{> zT`0YnIsoHfDRf%GdqLo9pYbiehWCl%**@@?o!7k<-}@a2@nLNwviWl0vqZv#Or|%8 zZt?E>AIn1hz%ttpg!+g>V)PN-w>;vGa^k)tV%mS8WV>)5RZ;EhYuEzYpd=Em0j;1d zoCD9pB2b+e4x>Qz;#K$wicuF-KkC9k&;e9Wu7&I19Z-Gw9ZFJ9N<n*2-MI?J!popK zRE+vl96G`&pgJ`L?tnYtXE^L--c^F5;TUKIcfg%66CQ!ZkPnrXGS-JJ-+%QzZ2A1F z&);48EdNWxJR7k*^6Vqn-2Kw2Uv2s7CT@ieUuRc4ac+!OX5Q%How10odGC(!N1Sm- zyzrj8w_SfS@o?5D{VT>h3*Yg4GvU4q;(hPKoNHUVr)4|j>$pm9gw8PeiW+a|%$91e zl4&-wlKdny$?GWS4#VLG_zg;MudNTGUq#+9bs6sf!D3hrZ^CN$1(}7nFT*AbKA-ho zA78Ne7T^8Z7XkT-Y(7i;b9_GB*dp6g5hLF{crCuMLwpOTpr|JDtsX6p=}W{;cYs~* zew_!Q`+un2*N@fiOT}&N;gLa^!uk!<|3vpRPDPdVkzmVP<(z@|RL<FOEVPG{pevjK z17ReLhU;M(EP_|yBlsAOq<$O)r@`sa56*}FFaQRE>d>?BCai)D@Fn~Vzd<^6sS4~5 z)!_g*3R=S%&<#dG9!!9V@Y9B$)_=JE9rO3ff@c=MBkSL}@0}apx$nC5_sRX0F>)TG z13vswR8cL%+*@f=U5>w-)Q!fL2f0VGnp~;>Gy7RR5z@q!GC*}B%9RmE<XtdtTlIaf zuzmaFyx47AqmoFvvPI$#e-B(pzY^)6ytz^PZ!DSJ53}G|cmWo|B2c@&VmWK|a1DG1 z<=#YEZ~$aME?fi`!&G<xX26562x_h1ePB2WIzty20=X~}E`=H^`MwOAL36kTZiVSE z10I6kHh;bL>&?Ht`O4xK=Rfw)^!fL^=>E-r@!I*<UiHf2D=xh#_lkl1sXQc;i<(yD zPE)D>s?4?Yfu}Y4%D8ShX`(r<X*bXujXNb#E~hS`4k_`Dt80h%^5nAp8-JC3T0ruS z>&{sUsT5b$<Xs9<?9usfT-Tp<B{Qo^{Uc#aA50Ie@W#wJ_S`B1kahT6W8=-^3tFB} zOd7by{PrYPt&LxYNX;yPkV>R39i;xc-fPGh9){WQHPmJ_(+jSFC*Wy#2A+fG;YD~K z*1(7G3Ec1o-+Mu8>PcHT4%$NpI2ne*FxYC!D6~sjcB??VqBdsVUCF7c^0)}p&ZFD7 z+V_#5Hm-KP7}i5^+N^EUYR_uRYRAuj+Opd3&k(<8fA(f;UC}Hb6)jl&*r=J2?QdIr zm%t4#vK7%1IU#IH-H&;>x+LCiEd5GqfLFiEj;&s{+}IC)KaXP%j_3C=T}En<kfy^a zub>&htr?kR1J(65dF=4gfoHlEfB9Ed-}*?Xyh^QNo(|RFY`73Ef~R2~JOf|DH}EqQ zdyDX}KO6~1!EtZ~^nhF#3YWl0m;!geRCoZMgXiHR_!t6jGe3ZKa6Fs_XTmvfE{ul> zFb5uk#jph4f^A!W_+sn2tsiWC^MhAE*!t4eXG4EaY>oWQ+B*II>056df9n;uUZJ|l z_c0Q7SR)5x?DpNd(&NfiJ+$tSVPEF`5#O*Yy{fsV(5ps#)swrrH_iP8n{)6Zp?Kxj zb>JY6?TS-dSsQl;ozbvE3kDTt+@bXn^Aua|j5x}=BMvtlcG7>n#{*^rqY%fU*~HCx zCF3SPpBv##o;X%Hq`7mr+NsL=+faF`3{`$AH<gvjCy0Di9x4OLU$U3n%fCZ8!(*@* zUV(4n2lzc)sWEI$xaA9P4#-|)^Z67pqx5r;jhkg;WA+r;m@@BZGwry{>F@Dzg|s@Y zP9KL!ZQC`e)h;--rc+LOLb6Mi8+%8fc`c_!EvJ1gz8A?Z*#if+$1ou>N|YPBD(DH3 zQKAP9ZU`sbySOG(Z7QklybbTc>QI?BMnEdpp>P4*3b(=SFdOE8EpwH3S>{pg;6ykH z#=&@)05`%-@DMx<kHDia8y<tX@B};wPs1~?ZR;;vzuo%jJ8!)3&SUR<I&0>%`|i5= zhOswacJo~$2K9IU`a}zs`h3kOdR~qh`<_dlY&(&Sc0#LLTI(^|nf4l&P496<$mVHn zk5go(waM3QT{1;ti@2M3NX?EUO(9}81;<gvrnN^m9owo0x37R+sS2r1HPgDc+SVP4 z*Lu@4$;DcoeeBglg`-cZ-&|UQ6@NH1<HGIw0&=AGF8SE@-xi$;wbWKseigx%p~`6% zsGR12%IR@XIXwj`r+J{Vnh#&XR}jC==X;CmJFn$Suf^9EccbOAxQTw?^`SXLHlHQp zyeCX)nR;Et{d}xMCbxS&0RFn<OJO%Bkjc%HoR~huR7}%{xF+>0rji;r*CaPnVawYx ze3tV20yc!o@@tOYz_;)n>_Zn-1rCCP;Si_~ouLby2i>6u^n_k82nNFt$b}1F7+emc zU^L{xQ}8s*gHK>BY=WQR7uXE7-{)H_I0BA@qu^-h3B8~<OoCrGZrHft<G0vte0}4F z1y3)Sz2IqC9+tcI_iwy;<9IOsA7kARE<##soz{(LP1;+Hs;0GuebmSJeCSEsbL4Yu zhf=16$;ByaePlZ_{mQUiA+cAnYX_0@ai!DI2*GtT@vz1aT%<LINH_vTrCZU=9wQ-~ z@XAEQjkA1tIEu#|jn!^d)+%R}sV%>&Fi#Il2E)BYv)t+p=CgP`{*C60Oupp|h8tba zT0w8SJX;@@-SkrQizUZ9>F@LPnB!EdIO4$1>N;urR^0B|)6OWnz1xt~XgBjI7+-;v z+!bGe9j~vzj;FG!oX5aiu<cN7PVI|fWn^O|EVB75r$pRYkM~*_#YS&lnK_y2%*qGX zWxiA+_2i7hOH?SirKC;>3;AS8wI)joxa?!Qz~F62v`L`&EvFZxzu(XaO1Kj3eihT` z1cf$pOnbS4wY#pNFX}>KOvkZ6?Eik)ST$m-7BPlCo@?idtzVNs+WwJTGTa#0XAa{) ze=d)Air=y>@DDG4+mE)RygNb{I0MwLK4E31<D-Aq;yr)wH+$=csl|`PtHtmB>8r)n zOb20Wt*ymYVAkDs2I+JL;i|jywb)6s_s<!W_xn(MHSdDJc`(wZs^jp#Yw@1Hr_J78 zXS`Z#HtRqB*6Qg~hB?I;c$BGDvE+U$tEp%CrHtfmW$%_r-D1|Ri*emHa$aO}-Cm~i zkJ{2Il#q+}d|RIC+*JWgujD=MAKSTVZ0BmRoww`7oHUJ@u7hbX9aIk<gyrxiybJGv z>c(pL9sYn~)Q>b!eMyJIpdlO%jX-s%37iAxg6dOu$bkVc5PtdovyVReXqDN2=G}j^ z?B$pA;B~Lu{4-JJV`jd}(ac|&`MD#>iq3KEw-rQ><67=_NoY138P`RJ(fN$^wi`uC znsyYavo+MLZp)<y<<S#*L2u{-eW4$m5B<TG-DTc#@pTeD%f;Sc7kVx6eS8rV@f=?; zZ!%G44GaRTlW4XyMx8(z*1Y|l!13<DLS3@26ZqbA0*X(KHr#O2>X-&!z!r8-`yt#3 zM8ZWnfrwkRa3^5hOeauy`&UxrBFtZE|DnMjqZp@@ZHvCSyDl`j?Y$C+tP=zpJ82CA zbvk7@hjq?!4wyTpLDt+?Ti2L7GqvX2=D`CeUsJ3W)Sk-%z}&8ZDsxu_OHE$Ih&#FM zB@*c7>j49|4RUH+<OKT%4!p<-)T?;lMS<YF3P+q?(h1^Y`lo%iaOF+kX9+5$UPX?9 zV9LA-E#FUZ0s%9;Q18dwa*#6$L)*V8rSw&=eLM2E=T?-Pbd~dnbK=7#RrNI9Ed$-1 zu1>Dg+iC2ygvL&Dr=c-5!|%VDc=JSFc|sG{N<+fRJfVrVOyrd(F!3g|_Joyrf)hVH zkyoD3#93EQR6B3tBsB5HiM;ZJCf+2GSDw(sn<nzg6PkDe$8b%YgeIQAVN?@_&<X5b z6F7`&;v_Wjgbt$;n0V7fj^PrVcmjt}O`U`$p1@&L(?pKpnzBZbu<kX%i6?Lv)znF7 z;t3o^HFXl2cmjt}O%pkWYnsSmRDu&v;4rFbBFAt|S$R%i-=4t4n<a7#m*B(`IE-qR z$T3{AL=K}8oOlAqaLp1qfNYk?VN`+>Pv9`BSt7@9%@R3`N^s%{TncNJ$N^-tL=K}8 zoOnWqQ3*_3Z%!m^^qSzr6F7$B^V>v<J%Q_R%@a9*Y@WzrRDu&v;8IxgL=GUECvq5- z;KUQS4%a-91IXry97ZKL@dU2JHBaOKvUwuc;S!p7i$sp$5}bGfhfysOIfiSI$YE51 z6HnkeT#G~wAX_AI7?t3}6Sxl7B9Q~g7Kt22B{=Z}uEVuR<N&foB8O24PCS82VJ#9l zfNYt_F<gQZPv97?Wg^FLEfYD0OK{=|9K-38!GtY&w@l<1F2RW>a17Tnkz=@)i5$Zv zIPnCI;aVng4A(M|W4Ht-p1?6&OEZR(mXh7}{ds93@9uPV`a1pSRP@s2;f&qXwQA*c zk0ss2Bz`#eGQHEkhZcR^tJd{4<a(QN)rWKad+5oMO}r6_>zW&L)$V)F*G6eF*qRa1 zWbi;GX)@Rpw3-Ympf?UJDygonxFQ`ZZb`YN3VP$L@`DE|xylbV1-)tywuXLKZx4Kn zo|J@D1K~=d5mm7<)v%FignR7W_vplxuzS1xZ&pZuF}RPxl9JG}f+ieENobitbAbQ4 zB=jkoZeB@AND_@`A4y5LlF-oPAJsaNnF*%E9_A$_la!29O7G0nAX#Vr6?G;#gWKbC zS^w1GzdWn=OCmXmva|Z+B+8XUauVgP^du)ycFpS_I(68CchSSmda%9})w1*+dYxeV zMcBrPT!`0wV-G!eu~!~>3ZPG0_RzNmHt|LXTl!t}B*4{tF$K-QZJj<$p|u$m>#mXg z>Uw9Czb$y%4%JtebyD+t5&ntP68Ta#9Mo^|5LIudWPUA-qn$kdQd=vcR?-LWEDV%# z4sZ%Er#r1uGM!9BQS+zr_%Fn*hqI8!26=&2#8Vu%%zO;m@)|kC^FQNRQc7yuvpzY$ zUytWMIpn2pYv1=&%hw8=7jf6~iHc_`XkDjAjs5fI;T9com7ctWw%5s0YfgITq`pqQ zQHMHX^_=R@OFsPMtWkr`ey>uiAAkF;@x0Hc-}A|w+Lu(yDS!I;cPIs22N`sfE2(cz z1LafKo&l1gewT+Iw{jGrlrQTii!z}c=sGJvMW_UoVIQah`@(*(Kk$RhPBo|w2S66o zfSPb1)PmYj2lz>4ryd*x2g4yy9}a~Ea2RNzMD1K3vT1Qug3!{UDxn@ZYjI7j;RrYq zj)J2>zfsf*vY|D!fn%X990%=y-$ruU!wJv<PK1--WatR`(W6dqDs+Y}&=pRD)8P#0 z1}eO>;A}Vt&V}=!JM@5_&<lD)ALtAH;C$#0IWPbQ!XOw7Lm(H1!UZr4hQkQB5H5m? z;Sv}Lmx3NiUJmMzuYl2z2Uo&XFb2lLI2aETU?N-%*TA(f39f_d;RcutH^NPDGu#5V z!fkLnOo2P#PPhy1hI`;%xDW1!sqg?ygXu5>9)y|j5IhWzz$|zaX2TqK4Ccb)@B};w zPr=hL51xVf@GLwB&%+C_0A7TJ@DeP7#jpfkhNbWdyb8<UHFzD~faUNetbmoU3f_XZ z;T?Dv-h=mHHGBYT;6wNbK88<VEqn^=U_E>WpTifh0ltK<;A{8>zJ>2#BYY1(z>km* zKfxyW8GeDyumygFt?(QC4u8Nl_#gZU1)%OF06|CrJq|4f`aO!`!0&@N8BhXBLMbQ> zWuPo%LOJ-8AEl_ku_9E0%CHYqfqh{=*dMAwHK+~;Ko-=1ns6Z0g4$3A>Ows@2o8or zpgtT54d5_n2!}%>Xbk+Gh0_$8L33yUE#U|_5{`nS;TZT4{ztwo$71ga$3Z(d9@@hR z&;d?_li+0N2&X_NI2CmLVix9HI33P_Zg3`?1!u!Ka4wt&3g3fcPv`}`p%3(hejxw; z9CKg*41_^27>0oSujY6G41?h?0xpD$;9|H0M#80V8C(vdK<DbZ^DuX&C&{Jf$fD;P z!f}}YSD#c%3f(GGV~EOZH3*rO5j5dna?fh#9^8Gy%3GQ~KXqlG3+cX;?z**gdXj2S zZ?K&*m!S6A^mQ!C$>mA^XEkQFGr0O;^t^33_NMn7Ob;wM6m{E=^s@+T^H9|Dn$~pX zbPB!y0MhJDnw?Bp3@U0ACR}A&a9vCXLdiI1c6#wEBX=u*Z?Nv%K^t+m)O<=WuxK3B z%o|__<|?FbuRV>h#bcDeP2V29Q6A1+vnMhbWbS-kpQ4$|{DtywOZh*spBsOGJAW>v zK9oDUN@8cX@}ysklT@9HTK|+ru6ArGp>$86*7Xa!x_(93D}5{fqNcB!r?S#EKA6e) zEx^5*QLpR7K4J<xB@Ial>_!P>GaUb^An0V9S%#ZX8Y6A>&V%V8)GMmqR^dl>t2o`; z2U2@-9Na#GpVQ7r9RbHUf$RWbj`75h!5F?TXZK+oJ%llJmYFY<p}wco3Z&HvWY=+e z)(WH&XH_>z&%UkGI(t*WRPGEK_qbbSY<lIdCwGcL^w?SS**(c&PvX{oC}Z|4<`22y zd&ucdPWI0QPckPcrEbD(r96FJR@60SIeJHJAH8ShzE@@qCHP4lepg3QP(NSK8JPV` z!6MC(!toY2ab+=2$zeXAdsr|eizA#i$Yv8Wp;B%Z*k>^B$we|F$#GY%>JoECI{g5$ zK`LoZ)ATFPNxxDj1VGZS4z=NEI1jo*59kTK;0DmFKqGdIz?D;-8`!RIRBV1%g>yIc zV~2#gAiryan68J#bgl1kMQl;2ssB>|e;$hCB60d%)we6W-_@V9hN0AKA6!`2LqlOR zh*K$UzbWpWmA7U_W=l6YOV|1Cyx#WbZbdOYf4WIG-3-Fgl@BMqg!b+jBHgVek<paO zlCb3!LRY91QnO?ZIN7H!k+azp&cBt$S_5jrLC_Fd!V%COdO|N445J|rG*{HsXr8Az z9D--<hPmgXTodMV$ncKLZ&2j>oyipwep{JH_;}__F5ku(&m8Yuulo-3#^tD0NWxy( zaCt^PhjH}E=y>d2IrYb$0~)Ce1oewv+1-KtPVma`DeRgTOO{i>B%otn2$|Wwo{WzY zXH)G#bfN9Tl*0Vf;_Z3SaTb<dVSY+4)sq)fM@?=%OeriqotO3(&MPc0h51G2(<`&W z@>y7%h50GHGM?*m+q4AZmeHQ{+g;a}?zuj%Jaz5y{B~DfY`u=;L$bcc*B+w%bhCIS zJ#=HnJO{Jv>UlXB!#oV?gUhmvbE$4mPFj8y_Ceg$_S6q3UeOd%(o5zuS#Yj&8nQ%i zl{1A!uQA3v)|kf;#$B~@*X`VuJ9nL{EF&1!hBCEw<78>|#>vXl-nmk92j?ox0cVUc zk2U6TCd~NO3NvAm_7mmeXvKl6H~VYNev;W=XZF{d{S9V6+3asL`<u-EX0yM=>~A&u z+syv<MT&EZG2dbKcbffOW`B2pi_TscsLI&mCF8P)eZX04a=Sz>SuY#+rL7guD~q&$ z)wnD(``66=b+dmX(6lz|c$m|jH;u~*vtPMLXRQuM@&$o1TH%(_2?X=<@|<AsjW^zK zQsk1A%0A!}3%2M@iJ5(I6VkoiYVsR!N*EXOTZK+3<5JqVlrj6VL4r7$#$3+qTd_}Z z@{IXP_LOf>?Rre`?!#G?HSXhr`M;$xTT`wk1X<n7oG5eFLKg4JIxiXbMP|P^*awd# z#{9C`FE#sD%>GrgUuO2Nnf>d*h8MEF8C+Gqg0no>@cWGgZw9lwUhS+1sxM#3zMw!q z`8l%StzaW!emj`ek@e1CrzNa-ni$>-X4YlZGdT1XWEh-#R6)T9#(j-(|IoM>1S_-V zpPC|Zw@!KJpn%hcf@R%3MTfR2m%kWrjx#Q!*_U<38kcd#WxO#@Fy<~iSJ5c+24kCS z3gt#)zR8$*(sGq^RYPaLpLB;^PVFvO4h74dY^VB9nYhW$-ciX)jwBY$e-L?RI_c(d zk8aORQk996{I<C3aZo+n0!~K0B8c9Cj{BHM<4F~p!e7eqfl{u!8Ok!e7{lWu^=x^N zViurF^LR)V+pThLHE;{m6_+cD3S6?f4lXUIYUw^ca&L&`%%dbzhn>=)$4V*N<-iPu zqjJDQE8_e+IpB1*SUE`BE(d1F8<hjn=KQ~t1Jjwt%t7hxa$u$oQ8`GB%0U_pf9FcU z45MS_Aa%POm}yE>4vIzPKwZzy<v=wfb}1CwE(d0k5|x9Je>(@N^RaVKGMs}p0k<t2 zP8-ql#A&pJqcFNPpe<8yhW}LKfO%k=>AV$Coh}Ger*-U{JQR~RH?}p}95mYPIWWDE zr%puYpfNef-mNk)y>B5oQ17;TOTq1tB7K8o(1t|Ihx$rW;M`@qP!H6dFXV(w=M8h3 zW|!&QD%8WZ;)Wr|NK9Cai>^_U)}^QhsvW2`s!!0Fnu@C5`$gS3Ta$fwAcVcEYr~XR znR38a$4v6#`lxhl*pCk+J|cB}RC8`A=f<LQB0j3s8$t0`spR!hi&Na<C@!=;Q)o9f z^#*cPEb>uKTp#sRcQY1zikwcY#sGlJbbZu|Dy+6;+>#>KW0y<hGl{wt@sW!}pvh(y z=nm8Z+CvY}<nao47#@ZBP@KQ2F~G~jWy4sz;;st^K?6`4?LcXq4@zSSXi};Nwf6jC zq!9~(_|j1g;L=UmZjfhat2gLZryx5ePyX&!ai88iy^PqcJFDF8rfQLg<ehA~7u7Vf za2l(110k2E=0l9DDv{mXPztR<p}QvHHLDUHUs>bbU@$GESZc9gO6r75oh+R5Y&<3* z9J(@h*Au4Ucz5J@F-JXt(+cMh{F@R_&?&}`Y6ps^1&dKN%w{t$OP+RJShXAM^x{m- z{~Omash3Pk4Qh*<dTZ7wb4W?&)I^{cq))2i<ZEo#pWO4T_@kxm{s5WHNW%z{+Qd-- zQk|4c9Yw^|oQg}06es5J2(RR}LkZN%n7`jsH2Ev9yrPLeup}-1&Zf??qAIErXguar zl~el1#u_Km_MPN$P<}yKO1>3uCeZqrDUObZ8lpDM5Bys}0X?2?E6o$P;nc!jki~m7 zxvZKGHT8caZLu$_&}t!raqr_hFKO8w5>V^a`v8JM4x82WSa;PvYgSj!U5kO8I#F)S zpc1YC6@j~-dH+k{t6<(2^r%&KJ!9d1W}YG(z%dKtUNdyWnB4ZT1Ok*m3I(iWqo3Vt zq;Yai?_s&abNh|RI;CH~oZfx2&d43sC#zFV?-3Uc>udU@le@^NZEkN<CuD9A@@~+= z`K9F(7Z6KfTMGA;zrH2&|M%p-3*LXB*LH{8szXI7$<yd`8iZ~O#Td)zts9Mi^zM;; z55j%wJA(0wo~6d$>V@8aP#;y)^t-Fm3yrCY@kH1E=FiUMr-d04DrI+zpVNrX`JVJ6 z@89V6>-0&utCKAfx^R=;zft><IMp{tw_%-a-@CC#x!G;wj783YJu-+Qzx+biv7tFI zpVFFj8K>8PUIPZt7(BzC5jke0RyO5Wb|v=%2+g!20Yau(p<_XT?i%hE&usmt8$-=d z*Px@<EYF&n@kJeV2eR8a_*X>IT|?Q5b<`SR5BzoB(9meR4HLzA*z-c??dZ5(w>-A! z<07Vr8h0(>sI4f+T7=t5`u#bv2e-}6*uUcZP!ftJyxHrw>4rT*hR3<6hFrh(k3K41 z?-ngzd)+pS?1wY6-o|-4bw=p?=%dm(34g^ml=N*pHow*``FJ-QkJqgzW_w*biqFP> z6RQQ2iP+|+C~3qBW8<^eGXnXjKCR1HwkhzE`|LsI*?M;<*Q-v)o+m$THs9qbcQrlL zKW#RgeN*jd&hLi1wOfA^co*z!yf!K;AEl#_o0YRY+Vrj69_{(@jy7EM(bh+MjCa0u zzcnOJYmaw~PRH7<oUJ|H(Z*~02k-F<CQ-J0z3w{4+O2;x^+&jO;HVLFH;(GwqTAh$ z?7Giz8huOTy(HO_TT%i$FM;&%R=RZQ&OQ6&TsXW<&*6Q$jvU%|c!Obm`jswSuXEdW z2bC_}AdA1!rCWFH+POi`iwEM~`iv8^hW8$pGjs&rkyBfb7%?oT*M%dZ&L{fPom;m( z;j}K@-N;9b=skp3x^_Lb<DreSh7QXek=r|WP}bnwJ{Jz^ON^zDYCUx5pq$=4N95!V zImVZl(i-U`w_PFudZ7}G^A3W;Kx4lAjh}DaC2=Ps*+UY@tlVEqaJ;a2Y=?%9UfN7^ zU7YGE1C$5Xc5H`=&S~j^!R?*YA#h<jQwPewBxPO-N<$5(3H89%iH4Y4!Vz#hw1=M1 z3;IJ241j?!2nNGw(DL^ka3|aavqA5|=o_T)7T>Zt90o&vTub~2d_M6b@cH=8*|j<F zMeVcrauDC*JI7~<pHU4l-1m7kO?OS__c80WjLjL?h00&=BmK`8r&r)f^WG<c)Kr!Z zf@+UX!PB5Rp#J|?@5TD6R(y;1l%)9|DFL<j=sqB|zH|8G{(%GLzSJ=bYRs*bQFHFn zss~P<zhAA%kJqR@moGWzt_oIxQj_(hFuCnr68Mw3WHGZ&<-aafmUZLq+w|Kh{WE9X znC=`>_sKO4anp*9p83dsGN?-E(Y~H0P6y3ssWj%5jAb0Ty_oN!wYatp=w8gdT(4*- z60KWm9;@}+`W&@_qVIM!!f(q_Gv!VkwQ{KMX)`(Y;Hc+KdTOoo^>k9tDwMXiXtT~a zc6iTTJ+n^C9Xhn<kdZOMc+XWHJLV1>+;fl{m+XB<4DQR+Bpi36P#k*374sPh?%Ci> z8h^YF+1jn0Hc=}>#ysHQRWeI%T!xXKJxUgGPi{#GBqflPKvDup2_z+ult5AfNeLt+ zkd#1D0!az%DhU)e{|~<R=6iQH*gx~;+nN8@|7}h~63qwA(KT1?51N+`1$}}s7Bt_V z1X?4w1@tn*-Jq9gri13<kAmj!PXQ0{jb1j*_g@CZ{T6uV^>RCISWfTZ!*k86V1><@ z%hoMv(&Ci3$LeH4`4>(pEJ{p^2FiTboDqZihNt5=B)6mlk`hQtASr>Q1d<X+N+2nL zqy&-@NJ=0nfuscf{Sruo{$0I8uvj03vh51}yILR6I)r^QUhx*TY5gEK6d)1$cePfc zr3P)g;`=+jBcXMbqF(=K<Zr*fOX~ksDI~W<OCXz9Wd3pbf1O>T|JT_~`hT5&uKr)G z>@EVW`f8QcuMHOmv*hY`RXBH3KV}u$_+69we|h^2A@zh_a05&R$@>{FTe^{%tB^4C z9+~@go9;WIJCC#u@iLy?Y;%gB|96psxi9OPyNpsu&C(qw;M4!BaQ;o}`Zb^?NIg(P zD2o1HUCn%045~u^7X803^YWh6BOKGr<)~F?%;J?zJ?xUtVc?aKULI@@JwYYjA96rn zbqs_-Fc?Nd9(eWtS{c5GyT0v~EcLFYNkGTE5E?unW$9P7enB}HXYE${^qofgsRr8f z!g0!tEoOSISD}8&OKknW7pD{!r_PJ5|F`h-3X8Kazvz5=WmedEf7MUv#n$m#+?3It z^xIwK9$Uw+TL<I$?XJAodL1cORo-i2*TJpwE1#ml{UW+c)8AsAk6Ct&`8gQFOBmD# zGjB=i|3wZ-{l9tYR-G%^C-wg(_5T`m$%X0vbw3dB>c!mC`hQJ*^=am`IoMPBf89<w zmJIfk{$Dj&zjjh9gFU7H*L+A5vlRA}{$F!Ti<yH&=>Ihn8&7VcweRkJ{lD(gUZhq= z=V15i|8*yN@pG{I_5ZpPPJa&C&{FoC{@+EUrsaaKc>_(;<9E?v<JY7s7j1q`y76@e zYe_;eY0G8~7tygRc}gR&Ty^{>X%kj%HR04`GYc9*3uq5LK$FKS;31d?i(yCle{C3o zhU2b_Srga>pfuWn(l{TKh9*4H|GNO}`LT5W%1xW{90})s+^3#qgFM+(!`?YR)440> zNT*nx(N3o(cRLpz^j(xb;4jM6VL8M<c-PrseZZ<Fd0IZtc2_fW@kxEa`m&N~%EqPR zh0H<ij3D)OVp1Ql5yx)a{k!!6t1)WRSF-*ssSnsMk3`$9q^0Zkf5w1*`$xb0Gae?u zM38>oM>y)&ekOr_=|{iwqhI-%4Elv1h0(A3=(m0J%Rc&DpW8umdi|o0{Pk--cf&n! zFWd+B!&G<xronWW0T04VcnBT_ozKt1I0w@S&E_}<9)r2?I6MJQ!c*`xDEu=V=fkt` z96S#%zygr}yBuGFMX(r_fPP14DZBy-vy7vDJxISDq@N~O4*Jy~{btZgSOssv+wczP zoP)^Y`<Pe52e1Y{gpc53_yiR0Q;zFkJ$weA!xyjt<o^}Nui+c`7QTax@IA<1zu%mX z`6t)}Kf^Du8MeT$uoZrT-{B9~2LFRUfrWe1sTZdIQ)^bcLjUK}p-LW4=cm`*wukA) z;MIlaHOtfLC-fdG+S57yRsElx88B)fl&29$5svZn2EN5WP<PFDIBF}(u@>RdtFX$? zi9<vBKY!)?N+t&X&R(}o-|tJyKo|`vW$Pb(RJ`6TTE6!BZ5Y|5|FabG(WzGdWAst! zoP@vP8%p{%9-CilmwddNjmPU&6tlgq9mQwk-`)B@dt9=*!L5tbcetC?{}@mIr_Faw z<f?(Q>Yp~7U;Czv)&FVj*53{N_xCnl8<Q<BrBfeAD`$JO>07%!+VkTbZMf*8t&jE? z?|ke2clCc-IY;Ls+HTXc`aHeIr2bDUo#gS~DS@#1&-8z`{?E8tMgN^*|L5eI)ye?l zyc9?UuP#uH|MJ(Zdg+BHU-;+b_g|S4^mA%T?AOm}Cdpy_oU(1NpEIJrQ)^p=`D+cV zFn_I;ZSP-P52g2%{!i%^)U$A(n#uSU^EBNScYI6y2z);ABk=k7&dIl_>*x#Sv-r;W zD;8gD@h$PAj-OGjrdq9^rou5Q59tHd2sNz#Q|}`r^?!QHdv7<p`ajhkUxbCAI-oxP zckiXguZ}(+?<q<1KUe~4^^raxssHmITvU4^YrE?Am!$85B}wzk6g$fIHL8P|Zm2~3 z{*w7U`cV4z_m`Tm_R`R4;v5dmc60$AfBpWFe&bHpuGPn#{r#mxe1CN(^4}<ZCv1i3 ze@W_p-39tzT`@b^I=<WW0Idvq&3cVX&B1$2>VHKb$t@{?qy&-@NJ=0nfusbI5=crQ zDS@N}k`hQtV3$guu=#&d|LZOlbuzM~1d<X+N+2nLqy&-@NJ=0nfusbI5=crQDS@N} z5+;G9{?CMoKAEsb0@-L!_{Zu0%-$vXKePY+`ah*SLT@=842M7yXb-1BFOW9n%V7+R zh1+2!=*<>))B92T@ZO;|ziZ`~t`$SBI?p}FnzoOje9Rci#&oS3({=xtu30f%4~Xen zJLGEL<0(wH>A|6}`oL6Qh;G0A6?xwoj>gD0(~VjAanjucU9~X0@XuzHY-IAXFPl*z zl&QClT(uicy0la3oi=k|r?TV>eylsgyy>PCQnM7oum4lw{F`)B?+>-1F0=sY|7-)N zLvPTJdJTn9FcGeS8{sB+2vlLt<`YD#S2LTeShK!ciDiB$<R0YQlejb+rWQi5<_Q#l zH5Vn$qJ-H8f$w)Fzo<^S=O9=c|6PdPn7JIuMC#A2T<Tz!Y?_0WPixGQky@DK)C;Vv z)Y>F3wKyxYt1(M%lflYvI_4Q58BPK7d8v+hA!KIzYkqmfl~&n?CW`Ij%r3-Fr^GzZ zjWf1iVfoA}9{(EtdYpw`Um@2JKQBAJhFvYse^Oo~&wonU#+1u^Wsr@wI+Ol`uELmS zV3u7yCkJDA5Ch#%T>YH~<3|@@P*qP!FPX2GJg;;b_C>#=Gvx{0EoB~S%;N}y)(x|t zX!dH+uHN3VPN~2zyfIx`5oVP!`#kNPD+9VcUWGY;1`nCX8uK_4W_)XfnXpLviE?qS zHhc5_wbAI|>hz#zGVapr;cE79b$htlJ?MvxyEJ^bIzC)2AFiGc?)8i0E?pn4whzbA z`^6}GGW)v&Ty*xrKvjNV@g?ITjT-@UZYa0Xy5VHKY}}W&)>*GC(*9NB;(kLf4IHix z4r$?NTHDpbk#00`xVkvd#$nD{9nd|mAW%j<tc*?|n3tF51cPt9@rIKkm#kFw0jF57 z1)XV{*%vn<U3J+R#<zrVDQWhlj7w=_E@Sp(gGAuCx7TvUr4{=WC(oFZ`a4~vm19#b zM`g=63Lkwk#yr88yErv}(yQk;7~5o1C^s7OO~$-1g~oAJLubFAGzM8t9Vu821<Rdm zr}|HsxXI4mQOW+Q?+D5|!Tg7~)n+>B`D&ihpKw^Jnr2FVJKUvzuO4mzCnH}GL~lW- zggH;2#i+?E{81dOuDWu#I}9NXbV}wcQ&$Gam$NXCX})2|%$K)2VDjs`JIfP?8H^G~ z7vj+6=Rq1bY`J^mlUf#CgBz;`h_SUxx*9gS;`=};H}_@`ObW-6LKWQepcpC0ofHtH zKgXt3dGsWrA<kTh&XNSYaht(-RNN`VE%#V)lQdgI8j-kDOsS~DvT4{-naeN2-c80O z9$`zR3TdcaA4tWKl--KsRv9ZNvgS)qakt0CmS82~2oflE36?drB07C<{uN(8PkfrP zC_Zm#29bx{W0j_xLKPIFq%!V1imS`2>d$dRLO~;$9(dc5)wD^ec}q4xYI65WKa!4g z8&0g|O455Jk#qv4BqoPSq8I7ys3i6!J(WZSYM5??6HT)%tXyb(Y>|2pT`v2Du54G8 zi>7hW<&uu1<o<WdC4IYc(Nr?JT#A#L-2ZyH6yND`sYZG`S1#&d3M-fDp)1=}<)SHb zbh(s3QgZ*h<x*n1a>)v%=4~$-q$c;jUM?9Xojl~$CgAqCMqv`|@=4l58{8K{X{T*~ zWSr5os{lQ&?n<iy98eUdeL<i)10i?7u#h=oS*Ku!nw~Yxj4rJ_Tx>oLRDydTA8PZ3 z<)aq)$le3_FvIewUL}v5+5XZj#gLDiDHnapC%=-Ezuet2a)+Y@fiwn+J69GGwO0m_ z{&ag?$MqDLd`u%B8c)QlAAh}O&>6G&`&aLM+blGZ18++xjU?pm)=mF-!*uAL_##*5 z>eE&&xA#<2%^7Fgd!QSi)a0p_YZQ~3qW-^CimNO%l1qh9Fy&q;N=zzK)i2d`^-emI zj8ksz*lH$6jW(oNHycN3^*x7GvaTj3jd3pFmlST{E7axOWpyuieN+bRS+<gkj?&I6 z39*!k&o*3iSDw#Zxd}14=ct|xVr`}>8JvCqpGsnPeN@ABPFJ$}XdO2vZft6U)<;L> z(e+U;aX*)*bNoK)w@cM9nQ>04?}q4Vq@p{mu1=fAL^{{?(P+qSCXKL<Mv@OPKzbPo zbz-e{9Yb9=*BZYntk9LZ(y_4+-01+y?L%O7|6()?RX1^*0@m*cQ%0_zmW1shR$a_$ zZCc#R2GteCsl}_F&>M!pP`C{2!qqjHZvdq;4cv6%X$Fqv&PgVxHir_CNQVueP4(>V z^2MCPbDna}ab9yqmv}u&Q*e)~2hl^TUi!DNreIY;GN05GjBqbVpH#)kUqu7yZzOi| z{;#y_1QK1)2pcamDe`Ly_PbhP*GO?<PRtZra@&yvhNgGg_bC*UUwP#*O}H8GoTd+_ zsA;MP3H2g7iX^VTO01$<j}vG-=2Vqa`p3o^=ZyB9<Z)1bL0L+^6*^66iLCUDj)xkh zwnk>}-6b^zd!@0v%)8?ESGl(uji8iqK~eI_Ju9KVzp5L9@}O;3{QfE<2(#!^)a!qg zj?e!7>aNnip(UT9raw;|FT(?OOEEV~Yunjl01Xl;jMS8NwC)Qnbe){jdsy!9+<qgn zPU+V#r+441GjfOZ$?BBTd&Gsq`kEo$$z9~sHn%sEA<6@DgOGQF7S1m%pSWNLS^9hV z*Y_`JnmtEt5>YJu7kLC_d}js<8W!oy`$2u;FQ9=(drnrbrhB96ne<R=U@QI4s(aGg ztO2gpq7|3ck~P?E$dNIca}-A{b+zZH{<|wj4bysXl#HYuSj9J#quSmj9QikWtz>=@ zbZ*`DgwwiYbsCmCBDZ($psbT~`&>AvZ`SdBhx8rRb42d2tbWk7>#>FDf7UaPozefS zJjU82Cv9Fm&+*J|NCw`<;MGa&HOtfLr}Z8y+S55&{m&I8Qnpw}NjVFDooDsBUe1Vi z9(E0vwe9HmKiz8CqK|(t)K;ndkE6Dt9BUD-5leR};X5hH&e&^^AN4TNo4szEZnXb! zx&%GxvHsCV#p~Uo<!i6ohLOE7)v+1pF^h8E30+t8QR!%PQ}IdvvyI2**V-i??`Gri zx)sH2uWLu~+4y&r{%0GXy`Cn>NA>BYoG)4rT<Si%QvPkd+n4K=T<m%B(`NI15^`;b zUG-0!4QDm=H0Av3akqBsZvyXvosHK<Wy?$H)Wgxr*&c2B)^3mX{CGzjF8XNeqdmqu z-?}d$U*VgWb&PS0PRH7<oUJ|H(MD<e2k&t@-M%efue;8%cI)4aTY>tS4jk1}cH^kK zMRdE{k=@?qgFF@H^yHS5z~7KSME^6U(xFj9_fE&2QaWVmer#7XL!Z{RQ+J=Iaq$Gp z>V9(1p+j?qoNvPWf?A7-$Xa}-8lMJP{E<}eK{<VgjL7PpJ7h@T-Xn5yhv4>iXR&`n zKzsYC^g`1ATv}s2s0)WcBWMmSp*5Ti=Rz;&4Fez-hQh^gIgEm_a5Y>5li?<q4)z_I z{B<9H@b0RQKlu0qcH#e5v46a`OS%Zxhn{FHi1_tHYrWD*tK45}mO5$;Q%AFO64oCr z+xGgMBl@Ft_V)h!Yl5P3-w*bO+E52n4^;jwz}A5_m`?-M1zQh>V7B$Z)`5w*dF#N9 z*uC}Oe_ly!^;&#BTf9C#i!WIG2#Of&uSD%T$7lH~iN=q>7u#R4cxC7Wm_0J&h}QqC z^4I%pN&U}0Y3=2f)KpZL2GuXC>^0YqU%&QpQT#VAPqT+$edqAW{R0QgeW_y>)R;Ro zz2@A_`yM#C)4sJPSFc`sE-RaJR|Ts;smXfYlic<$2^6OPC)WC>R&;pEZq`31b5xbk z`kvN5r-Np+R2sAXxr`&j3+G+X`sX^Jn{o0%>z|55>z|s(YW=f5N3Ec=;HVLQTaKD3 zcjBmZ&u$zuIriYFbx*CYDt$d;(z>V8))sBnImZs~*{f&PiMd0E_8c-YMi}q8%45ge zVS{@P+6DT5-#%d=(K*@LwaZ;LfR!O*uJUYStrAIYT!xXKu0?jqK*!{klt5AfNeLt+ zkd#1D0!axZC6JUrQUXZ{BqflPz^;-&B7T2Kp9<JV_xAUf8aqwVebAV{rr}S-i*k+p z{*rn3Oi#u2;zaa2Xo{oLi(fT;e(K7AJ$mC!#P2WZ>*gmyZw>8=_b+)7!l?%K%>eK9 z#WHK{B{$?z*!s`EN&mCfi?n7^wr)u$^x{_BV|5mUR0V}o3X2wAv}mNos;)UB2K6;j z8E;&YTT%i^2_z+ult5AfNeLt+kd#1D0!axZC6JUrQUd>a2_*GD|LcozuegA0UXe-a ze|DTK=ZMowI{R#4Evw1<X-=S+HIzsh<n)wt(5!3Ka|UMrQm{y0X1O2GQwxea9a-1Q z;``4WXSg#07rqfPwc`k<O?JT9<Qx&Q%P|8L9l7WV7|9u3oxaW`<_xL1a^DY5(`)GG zq+hA9`ff?9tEA=}1dZT0I2F!?^PoHQfFTe7chj0={m{!*e%C`{x>~)@dLN97B_{8x zray*Vr}x>W;ZIHPfhk45t5#37VCZ*MUhO+%7(Lt0$gX$zJoieKPUu~*!gV;OoA>F` zB{e5K@)f?yf~(LAa7K=bH8o4-fRlat5;>bq;ryHGO%~LJCeRd)0bAndV>WBZL@C8O zMz=B9{fgRXbsj&4-wTtG499F<0F=A*B71c(d(AtgkD2t9#{(b>>VWdv7;Juz#;iPd z0_FQ0P;FJ-`$G;40KK3$2y{JqmofYRA`i0&ZH4)LJ=tj(Xy^uXYll5+Wy)k3Lw+W{ zJnM%dBhE|loQIe~+s>UA?gX5bDbaDNZo1n_qqDiFd7-H6dFC48=_XcsB|X;=X$P<D z@Y=oSMbdN6i<h3tA)cS|Vy`a}pDyDXBbPntr{@X!KE{+y$gD>UavzMl%9{6D^Di|8 zlxEa+260#YQC(L4#i5YYADq-5oaT%-H-rg6>AjsObC#<_@FnBE$m|yf`{1#}m|r&g zrDp$%*}rP`%gp{YvwuC<@Io{z2UnG^;4BX|{C;D>o5Ad^S34_$>Z?|=FDTHP|04_D z3hKW9b}*|WU#AB<ar=1J#PD7)lj{0@aOf?LvpP8UsDgqIjQbkn{-JSq)f}dx436&! zQyw}f;IuKd{@4^9+8PbP#~GJ|=ntMqleGGSX_AhHEYcrb2X|>Lt%sY{kBZT^SxvRN z|EsAh{G}YNK0-76;m$k;J%H*Z^8nqD>`SACPl~a3ttLWgmGtMp47H+i5d7OYaBn$Y zy?$1Mu&cxND6Y_I3oMEbWixp3Xdl#7boInxbtrqa8K%Y5AL?pPHbWv$e8@Yb;n>xl zOf3$Vk=35um@?8Q33*T~N?WKKtEr<gV|Dc=dt<eFlfAK~#Eg|*pDmUwU5&|;X*ZHb zFGAUR7_G6`*2A6G)9Vg8BB?8-_M~J>FR7=Orj6XS**YXWy{Y+mxcn3Ju&TeY`H;@b zJQ~yP(>v-)!e3v!IXGyy=YY#)i=P8&_k3x$%D~*=qH@rNJlQt0XY`|L;wEXQ(}dL@ z=ory)s+!OOw)c^I>^Z;izD(pC^@KV{x>P42!HBj{-N&TtrcXt8%I9iKRXOPXB1Hhw zy{Zt>&Z?dpjqCWlK%S(*R7d%`KI)~UVO5*a<Vpxv$EkYFv2?QvtGu~-UKLJv0Dbf& z9jDR+yDrnlX6`S9&^gis8_BiK(?n4dSly8{Av^_gLAp*;p(<!oIQ9NEtQ$rePZdg= zLR5z=s10>NgCcu|ja}2tv%yX`-I%=EOBJKnPGDa?z4=pn<I;T^O%?vu7Qdjy)X8(( zqg*<bJ-3cjZX!&x*<)CXsVYpK#yZ*VDu9G=8f!KKA=kN>z19ZY+mVUE*k#hHLeT8} zX5A2vudEwXFqoE7EVWoLC3V83MnZWu9w`LY)|EN;VAh(3<K2<t#T+}6?qF2JDrZfJ zC+HL_76=B4rv;0-GFNURTb_(vShX7L^x{m-+Z)$0sh3Pk4Qh*<dTVDG>Gw3})I^}s zT1+c!TspooC<RxGsj^LtLZC9GIw_et`dwwymegYE%Hgl==T`7)G4;kF`HR1^sh=rt zMsB-Di>Vr-HgyI5?Vqm2G=<Kv7pq_=(Ej?FPSKzL9ofpWqNmkUyX`2v{8gH^W7-w^ zH>(n#I%Va7!w$FiXtE7Leaf!Vzo~V|qNcxAT}C+lwn)9VbD`-Mhp-0U#hBG24x^W| z<uc6lkt688a!pTZFS3Q{ldbfNcKu&^(l1Q^qt>o=sQ;1cD7(@{H^*38&yZt0osV93 zd;WA|@ajVIn&tVSJOA_@8JUE)ic~ShqF>?D7VD@S_s3ty`JpP=rn0O5F)wu9j*ja? ziAEn6F&I+6vxK9zq8w`xZY$|a|6>o{5buorE6xu^p=iRJy?&c+*dt`Pnc-kZO4|BI z9~G~6i<YmwZW~7S3JeIhaUNN8W`xd<J}RAh_$$7nNZ-a|^K0#rk9V{2c-@L(w%4_z z_-y>=QEx6MVw<0$q!BBOjn7`sh)_Ms+dQ=U?TaG%A8ozM;CgEkkv-4GY4cqkp*F-( z^-r4(XTKCUg!9kC-P*0c3A_t-HeMT*m5<U<4{POYk2Za4w?}(^yrT^leYEw_9^;*F z-LDSi%i7}|qtmf=D`#tuceL@^{=s{kPCK>b>vh*T)^7cOpx&vg2-43mcX2W~(nON_ zACW<FOOymW`X5UV?>p?GzQa747l)TF9n#9^Q`;D=`!R;<$L%#pN{gdD(n)UrED6vH zm1LZk1=9PcF<<`1&o}<FGMUUx;SxY^q^6)oZ)BFEmv+z(X(pv%{gAS4um3Ss6R}d1 z`2k?-fOJ1Lh9=Myj)r5P6Pya?fOLVL5B(trqz`l;3<5pdRz3QkH`80a7N1XiOA*hB zA8bq9M2mP%{0QRbx`;mBtnDH5_WB<y+wxbLCG|h<p>p^~B;)FTjMo1*w?fUi%j&uM z|0Y(eJvXWU?;lZEyDbxiegB=*|F?_v|MhB>e;X?U*(%K@SD&p_0xe2wInI03`lwl~ z=9t`)5=crQDS@N}k`hQtASr>Q1d<X+N+2nLqy&-@*cB2eZ2tdm(*I`X%t`%kyP{Sk z<48&%DS@N}k`hQtASr>Q1d<X+N+2nLqy&-@*xMw)=XQLz$Ma@Lg<_Bf#UULspahhJ zQcxPoKv~Fya!?*BKt-qom0=&K0{g;#us`T?&uUN|4uCAE0X5-3s0Fp54%CHu@F$<P zG~jp`)Q3YuZgOuJGB@Jb3YtJuXa>!p1+;`C;7B+Mj)r645Xgqs&<2i$ws0J@gX5t+ zoB$o*L^ugfhK_Iwbb?c%GjxHja2lKrXFxYN6V8IO;T$*@&V%mI1A0O)=nZ|KFZ6@+ zL0^I7zyKHsgJ3WWfm|307r-zW4kO?~xCkzWOJF2i3YWp<FbYP)|BzoE$1&Y92DfkD z`LoL}S>E*IeaAJpZp_dV?wZ_UN|UZ*Z&;K)=(zpwX;wP3>#VNXS9PfP@KrS)eE6Qc zO=Zj9e9c*3_t^iDPB{lot&}=-P0L@`?$f<htI<tziY<Ttrv*RWbJ@z4zurB3^sj5b znweMOrC}fa8aQ!b+5BS{9x`~t+?pS(etyo$Q_sHtr59&D-1VEf=?!}yd)5iR2F6c5 zX39PH)PC-%;JOQsTt2GmJ<k4*kD5E};%ZMnc+B@7yjEh(eYf>>E<3E)L#@xd@1{3D zYB6KcTeD`bd-b{fb24r!`C8qlFSur4>CFZEZa(AMdFSOl+~L%^j~_n0+_=^EWnb3! z=o>N?Y^nUvq+`p^Ta-0veUE9~9(;V#qK0d~oA7=9_kUE)8QQGVH?2SX<=c|ozFNKd zx16qz40y6z(^&)Fs{Uc?x5gYa;p^syyfUcjVN)jk`t;-{*I#<esQgXG-9O>$$8R`z z{j(_pQf@u^&BK~)T(YVEZ@F0))NNSly_<f#ec}-_PQCk^FYa5i?3{5MZap~n;^Q_> zz3tw6%08X>W9JJVo6zf!>(030=gmh|t1)(LM%vTu-^ls+`x~3R{@%Wm4nMX0kp<^g z`CrQGCr&@~rop#ov|0V=oBdyV_k`20t1{-1KRQmo;h1)(Ju+?E!=<}5%fD!2<B83- zo&3e0`#kx}xlg<>yjr=1Z~yVx+y@_N{NkNA4H|eW|APm<{`H|b_3ygz^aIaqo6$L= zb+PgzH=Xp%8#UjX-Rsd=wW?l{`Reb7jeB)@i}%M(dh+zQAG_g>xjn``bn|@&m91Q| zd#CE%rcXKJ>MGy<TE73f#{FkbDtF86qmR3^(^D<4zHW5MHP4>#!U@xl>pWz?z7JMe z`^&V$Zf<ye<L}OT^oI2xU$Z22(%ffHFFS47f=VAfol!9ExIf1q_u{#S{IGiBru}a0 za^2hio6#n>+bzF;d_>RntA`xA`ijp^ZnNd%Mjt-5a`vUmHkUoMO3J1dw>{G%=d>p_ zRQPek)tip3vnl7~H8<?jVEXNy-k;w3n4ik`YOvwvg*R?EvDAm<_Wd^XhHaBhEWhpL zb+b|qUcGth)eSzYeaqXU`Yu22z&fMmTyV~%Z=HE?oz_n_DR$R}-#V4L?8SHIS6g{x z;}3ow^5*i5&o>>C`@-!LzinK5`3aN1taVG?(Z3CDF#hQEBYUm9Y`<6Ud*+^fHy(cd zg*85Zq0<M$JAVG_y~Drkb;{Jun_7H7?$H;1OgsOFyX&l-{`JhS9zJ#TCnFm^T<NWY z$MwJE<x*8&y>n8>8NIs9TzA+$z2E=n+y70v<h^>A&s@3ap_@Pbv}dDcpY8k8>n-NB zxunfgYghdAZS~6<oLBD0UxHs$IB!Ak&#P>jbM!vPPCWnRL#A!}dC{!VA3WROy&Gp; zdr7+&UT=O|=llWB-1YgbXPvsKdWSpz=<?OLGe!>`e&mYZ8eQ^q?aPN;bm9m7T7A^6 z?dIV#Hr6<+*8XR8_~4KYPd{7byhHD)d)|yssy_Dh^68)7dcmV5_x)<z;#qY+-nMr2 zi$5=!mC}A;e*TNAw+{QN$xr<|p3#2ffOnf-wYllUjt6e7)@H<h*)MeH*>cj%oBI8q zy{`a^tH}~=+#!MB?hxF9LxK}5NN@@6?ivz;JHa(TaCdk25TtQ}Htw#kJNf_J+4*K> zXLi3gv+wO+x35*#y>;qTb@j12$NaHca~KQX)@fLST4(oe3Z5tiG#w}8BlymM<2a1R zsJdaMbvr0w?Hg!Gn}}j*8*>BHl^K*^D5~Jj{Nl-2kf_8p$WOFoLmP;WrPIx^`i5K& zyDL*wcF9JQwp{Us;xI+?jatIj(7T+T)j}NpH!rIFgLdql$!~*C(*ijksN#W!d4y=E zZ{C-7unrz+ud(d7UN%Uyj`@3(W+E!(IC?LE2wE3F1UOg=*}U}=Jr%p7?7kWJn{dY# zsE*(8=EJSzVd3Ns5oKm_J_{jC7;6J1X&Qsn3={n%biB|DhYt)KkLU>QkyO*WB@n7Z z`4J*BOBJH8C5`rg^=%PA47dp3vW_?1E3xy;c5Zu@@lAJ^@sm9`-Hy;Y#SVskH_5gA zFvFH7rnuH0JU?KWnKt+zPPmxo9KvlaRE&4rGK=;o<8;l!xl5w}b08yz=0!e_k0B53 z&C@0uQ_Js~udEH^^r-jY&Uh;qdW^+oov>KU2hu4e7JH`8Xcp9#1NUuvPB{F$R*6}p zTSp9Pb0>85srfchtd?bJEoM)GaVOj|yiTwf5i~O~)V`5rtpNCU!++=&M)cGxue;<O zW%}fP9<v`pvwT0<W1Y-d5$wiR63fOwU2^}4U+fdV=N>MpYY?JqdgX4t=(4gUI(5+1 z)Fa9PtHbG|HRtCFA1ynOCBs-++Qliq-`&#at&eX=-F)R~tebZ&cp_2+BF^j8torak zbGLhh`QO1Nq^F?%&^4G{AmODb&r<HDWBh1-v7joH*YD=s*<)>&urVjwETna?5M#{@ zS0-UaR3=otu{xziJy1t?JxT^;b;>rV?)Pf1%5;cUH&oE`(J*#wjO^37b-k_D=*g?z zYk6}<OJZ%{2)Gl01}sAHPY%|dtoWtIs{M!Mj2qZ(pRzNAuFFz-n8Dh+;Bgq?IU3;! zVs)p1ShJ3KrV*Zcc2Qt-e&_Haw%stbnWV9pdDNlMuRaJ(8LD55Oq`KxR`PoKsl4c! ztjmuv%d=*b`<2=wX*CA@U9V$}KE5f`-RIbL&pP<7+xSWVB+M~$dQ4V2G!K$XA;NhA z0JRWHHH2D>qvmFjn7qe2Q_5whE0`K$t`9pAMbHd<jWDedt?dmLZZ8um@ZXCpb+UVS zCwOXk$+YYXHC^&8zZWF*rWMrk&J(aiySUFIe%Bs(dl@ENWi+1XF^vY7Zu7|b<x+=o z(DIY5)y&pg)WN3+!u^cw9V$_*%QhdcBekxYpx?S&>wJ)9+!lno`S$qWKOLwv+GWCv zS93~4BtGn*fm6#;|HNI*!e_sy$4+ywOu61n0K}3?$Pt}z_Zmp}z(OH;Z%RRX-$#*g z6Djtv4>T6=W#0{1S1Y97T3lMcSeoKoYpC0fHFcfnOK*{z;JwaqURgTu^gp%CwWRw- z6bu?EBjFz_^9dWlclNn<W^>pyryWbGT0*t)#&y^n=j_7}TpIiF@tY#-XBTnG4{75y zAA+|qVAjTSK6qwFv>#^85z*|+I;JwvQF?zrmA&B@TdJPAwc`8X{agp+%}IPh;MjYi z?0X6A??|)6|7?ad{Q7ibxJo{q<IL)8*H&?~I!kBF(D$I@gmTxF*0iwkcuyy70Kahw z`#I5J;elZ0$-#YQQt5rBLR5tF{;N6c@5V&CtL!KPJkvEbH=j#W3QeO1n`{e9ca}n& zTx-}&(K7`FGYxngn;$|-)8DkFZnq~26dgaJE!X*Q@KUzfZen{qG1M+@<M_felU^4l zX!bQ(%lhq-Qm|SXqyF_poW;{!+V>Vk`8y%!ScU~1*4G*SN{>-jk5X@+k(+v``V@r= z-pbh!5}`;SOmxf~)jsUIuhR{)(|VG<w*Bm{!_BUDk~XPjX3wf`Iwn}u|Cu#=$5!O{ z;rZ!MLZR~kF}=^SNb83o#+#J)I`v}*2A<YWTJMy&=CYD3%13KdD>diEcK4cGa1w?X zH6wI&0-56m&0|H3!`b<V`lQr~p2c(h0M1q9y>;{R(isw{#=A>&CJ5bmB|zJIgEeqm zVR_pJzlKHWXLz0+tkpO82D)b%>II!)n~MMve|s?Xb~Rh6WdA&+lbw6VCqsEkTSb@@ zRHi*gCY%Z!IXhzY9Gsep3uoth)yaK{w8mVT`Ysjai!1uVUb<G%N4IQRR|c{6(r}Uy zTv|h;u*yx`q(x+n98YrYl=oC#w+dot-_3hS9EvrS3&z*ukDp<v)94DwKV#uOrJH?a zpS?#_rbYdpIRGKaMyF9@o#3?g8>L!LZ*g5eZiBosZx1C%)b?tU+3oYw^4)8RQ94VX zXiu#1ERhk?28)$>(jx5slJ;ra{QdG=XCosz-ftPN(QR#WqjFNs68yyF4DBb>?}+e( z<%R_WU*D>T$54%t2)-5#z-dt2Q7%zJA)zMR$)cOx%yP;o$X!+Rcx6vn0w+i9P-V$+ zxOuwscBTm0)3^+o)@0)mRz?roN{RF8itq<n)eks0!z^96^H+Bl{E2O8QY7O$qBx2z zZ&?*JR<Fi7slMwEGiOP==xE0CIaE&44GG8)!`)x=U8IW8UsrLqOEja{=*Nt9KD%%u z)?7PQ_kMrl!fg_O0xIvd6T2K^p6N5%E^$0Iz*w*~iyoMgQ4dYfhZ#a^5x2I~bG5U2 z$H^O0Se3<`@y$X~tHjD>3-5$|k9$h@wbRyo)|Co{57*<C(NMC2Q*t>-4KBNjtviQP znZ{tK%&uGRb#aZLL)XoSSCV`Vd~F`0F%oEzF?0hv`OYLGG*!l3^eRGTuqR3;_V%>) ziKA43;o5}OWbc}_VgNaFz=Z)iz3^BJ)@ybBoF7)I&#C1N?TnmwxCB@Qo-Mpc#Umvs zc4Vch9w{**A{6}bgvUHXv=Dy7TiJ48O#r%Z<~-?eYO<k4)27<GpE^`c>+KiWMZnXU zLRrK)Hc3J|3_CwEi)>{j{6PL#>3X@@fgSDKm^gBeUfEEq5u?{ao+uhK`C>nysF}8y zQ~gp2>;o|+C|YGP=nRioHF^BAzuffH*`cZ}(7quY&%l#==M60}g?K^{#xkM2)wF1~ z@_9?RP|pj6R1uvrP5-Q%J=_W2r)P_G8iUQ_)40Awo2vX;OVyDKV}Wj=|IKxv@ZdFR zYfdS27XXI}3YQ8>+5}?l4HbWdMD7BBHiM#c0YLd6Q@TJwBRqq6euj>>0w7Jpf^EW~ zFsC8Qg&#LJH-8Boe!Ie&hO82QgoV84Z=B(O`yO(Bb^$(MzktGpEN9}Hh66ys_#lJN zP|z?4&wja?27dweE`5b$_m?YmcS0092Y7=^iGlb3PD1=Pu;YH+IQlf~BcKo<Q-A_y zLVx-jf~<+w1A9C$2Kyml1A9_o1#p4S9N?&cT;L4=i1-IE_<t8ie;@<wmmJ(9KL^Y& zWc;n+y^0DM-q}z87~cQY;r-_r{9ir1|JNboUoh+P0(il5FE{u%{x7Kf->3Z0zcJ-! zVMAt>6X@S(mA~^h@uz>A&n{qM@$euq6@L9EW?}#OPdtJCkN=7P1LphxotR(;yZ{pb zoM2*r^WVsTf7*cj_sSvk2QL^D0N{^q-~rDHka^(`Oz?om1SHzTADH0%Nvr>X2`=zN z1^M&(0}~KTu!Daee_-MlCLkR9|EPK54`85S{xX^O2WI}j3`An~kFW-RjG6x@#>_vB zb@)r-%l}bh<e!F#e`liporC)W6MryK|IXF_!9@L%Z~VbT{TdU0Fj2qDy#9x>4xV6M z=Kq=!5aJ>BcP$C$PsJZZ1qe|DLfC3Z+!rx$$l6~C?2G(Q5|B;}vjsX1qD}mp>GvpF zm9WT1V4sHo7>EyM@T&~Lk-w<Gm+t|-;0^W_!~vHuSZxXqj?sn+4l@b~VS)${hIs<^ z+|L1^IEKWDX#?lI1GIsQ`a%hV-vfzP@+(Rh_zPcl0KySE7-AS$SD%C?C1iiZk_X>D zy)}ueN5Braq2Mxr<4@oNIEu_Wa>AokaNeJnd=Alk{+0&8ZF>cNC|}kXK<CW_D2E{H z!EJ6))6+_83Sap0W)A3L)#p8IV@|ItE(L8L6cghAE#MPX&S+QpB<F^PNK8m<^#G<R zIU2FPlOb7SmNjt-e2{9<q)3fwwp37HVy?^TxdL@mh-Uiy6Oo+oPjpYwj$01}_SSYi z)8?zOjU!r99S?ayp6}Zn4{ESi$-67oFrlsKq<;84mf2y)<U~i*#-SlEQ6SIqg_ndp zQhZX`ec9ud5hc_qM4GEqFtqvPq*4Am>E&~g>CQVT<@wjC;g$sY(Vvap@8CSGyk!>& z(JvMqAkpG4jm`%0N+aF~eSv$a`{fH~UsoAd)T3IIUN;CH5kF(-w!fCx?4|yF-b+1= zQ7r9JUCB)vDVA9&kNzikgn=%wb1vU8F8Ky%9FD!0N{>|D?IJX;#kIZ4&{@V4DN>o* zu(Ob#$`q``&z9_6^wJ5Lx2jG^oVnGURJP|h^4T7A7yGmotN@Aup%-G$)J`9i&A{xB zx7$izjv-+yQeFE%9U2l)=gVI3qWT$s)6K4QADSaAuv|QmB974MJ*+XXqV^O|warbA zkEW}RdiNF9jBRca&$3;+<*6C+s@D^o$54iQ!(o{(o>Ys>AlOok=;)Yj$}$5Rzvo_k z6OuFeuf2Z=x58_pig2W)@B#SlK7$@etl4WMwaVQp@sVyn(^udO6R-?kS!jPR(FK2| zOK2#8@l3nEg&&BTsg-0Xkhg35IWiMOclaAh@Vb;DU?kh8-!m|pNNA1qjABZ+mg85v zqd&~fV8hsS)O$z5^EHuWg)QvV^Y&Fo+83~yZ(_nDfUgsz(vi9xy|>U^!S=-+Z074u zL%-zok;QX>Rb?9O8|lZn*HMb>FD*+_Q9HLh)EC?D)do)MVnFj~cRp;kWgy<S)Qfuk z8>%O&lhbhoO$V&wq<y_oF4p+xrZrQUai6sx$*e#4-a*Z^eB+C=df;*Sj`P@JG5JaO zfZp^+CkiK8b1&+heQ^pf2K%vwQ*Tb1l1!AoxR>pW!%BLc7G5t$g{EjYngOM+5u3j@ zmUmFjVLV8B*$nmbh3B3DW<lKRa@Eqnq;il}`1Wx#t)Ji_jzZ27(*+!+wbV>TrQ&C? zLTLjS&tm6vB+uuj!GedDsGdv5M&*5GyA3n$t>vc4zzxTA?Y)6IJ(9kvsLv%jYXc?b zM1*U*V(A3Ng6}>^pZlsxzs%O{Z`a=%*fPRRQ9VBHSukN!E9O{zi+!1v-%%g9xNK!W z7y-8SH6twQ7)j5E(=D0C*A>hMtzt){Rrfr;T0}03sK*OvE&>@KLdx|&S{>~OrVS`9 zHdNXT2dQn==G*YQ#XW!LmNQ!69S~#j{;v4w^*Nhht{;B$iK=W~GdA<R6Ab1>-hL|i z4i)i^Rcag~xJhL=qnKqv^!)-HNX_hX9?UN3EX@wrGcAW7O#{`iURrzY7j-No_p%jl ziz|VfW9|Ro@G=kTY8S?72fF#S$UKGub&b2CWuDTArDQMJ2T|kiHF#x0D5y={tHb9a zQ9AFf3|J!Y*@n$niiRTnR832d0bS+ZAGA@sDn8d<9iph~&s1lugeWD3GVqvmvr;}* zb+Fb%4K&V);Xoc+h%Z9fe>Y>^-hxvMm&obxVN6@kbA}@$%Ku@`Ras=wb)w_rwJW8* zaAx|D#=4ay-u|KZ-3ReH0t@wKtjsGDH`<fJn=Wr!gL7WJL$PP_g=g~ZCuveVmuW#= zupAZe3{YPYzO*1;1ZEKIK=*~9ahZiNO~2#a8kCY=OOVZiA3{znrj;{VQLo5^53f{5 z6Vmu*nhhWM@w?tjka?oho2GIuH&i2UB)|6oP+o^0ANX{aaD{XqUXEwlQ0-m%w?%?T ztmDT7lY4kqjqBYIV4G24u9n0(D$czGF3mu05m$(3jGsOTcVz7+-#fwzRTVo|)r7u0 zs_!~lfH7=Ar;%ANP@E>7%!j?J5tVa-c3G6X{ED4QaOEhS<Ye-Mt8!+@tw+{qO}&h= zNg}LLBfPs=)zbrQa*{>=!NaVL{iv^Et@f&n+xwuSsuTN1qIBYNK%>Ph_}8LiXjy#a zIzg0AOI+?J0YGco3bq7{YUObD7P;A!tqMIG^E<gVuh2h?^h}aBq~TjpZ!+oIWV3CM zTX-e1Fq@<2206P+;MV)Sr;R7wkuXquWT_V&=xaS4m$hn9w*&Fh4y7?QdN1%Io=K*a z+&_V}bub3eM>w~)@CFFP8KZqWeJhw6Xt<73Nnk+UcHfhiz|134ojcagc5zOyuXZ|D zP~!$-5FYDyJC9D-{=v{ch2O`g-B3flJ8Ute7KKp;uZ>zJWDl_fuDwcG!%nB{WCd~j zs37_{lWBU|SHUNEduO;lmj3F=F5!=b-t<>Sse072m7OC-i{=z4eLH7K*1???AFNrR z7JJ;66r+YtnMWNDP<fT%NC*I_`+=z2fkfK~V`4wnXEDqKQ140FmtLnM#C@;IZ`Zo^ zUKDv~)f9Tvd9Gi5)RP7$d)Oy?*2~7<8q{vVpSTzBzHFt5{U~s(BcxQUb9#2QsvTko zy!pIa5N3K{`PAI~$S$4pk*{=@;(_=K{>l|PJ+5p8xI~jkYU17?yPB{{ihGkw|BTuE zIXW(v4x#ScBqsU`=TCWrSo$4?#CM_aC#Pm8y7>7h%&463=k4JgW%rhT8MoZ93Rh}) zXScSL<T~U$ZKiigJt)=|I<vSwwZ}u{>P@M2z))8a)@^LW!DZsTI_SFX6I(d;<NVEA zCZEH{+7!XFVU7+xihYb5jROpq^uQ4Z*3v2>BG};*zR`VcJE4<N8=w7v5j&B=GOTiQ z0o=h1Lgflvk=Lh$nFBN9-wI|xnT8cCqPBexSeOE}&|}~6PZ%_?kgN)i;SS1@PJ~q) zJKM51IUWy^gH!LmC$CstX5U?NO)cP-hEp@17QHpSo<geN&CwO$JuMF07~XyfU+06! zdwPY~h4J(-t(=^5#8-NLt>P&DD&)xQuJFjtOaCgfp8xK)KEC%W6D2C><OJ_}q0Mof z;ql<9>AOQIo}*zY^B>32X6=a_r74K+!l}ZhnAYAaFvk~BZ%6me%Tur6_wEiT29rF# z?Ybj=^ZVwrbGNcS9E0O_!92K*s%sm$8F?8KuQT2m4>Mk{2{X>(8^Lu5Jx78q5W&Tf ze(gqNx%B2t{B&Pj`K3Qo9WImkEa2>AG}s9EgHXwMlHI1;b>-%C{@YQ`SF#rtd;EPE zsmltZ{cUeij_f<FQ^(fU-z=OBYrWLtG#Ja9X0R>bQ7vWsa_u7FeAJTAQu9{Dd3$F( z(`Za$*EO?VXt2#w3ETfPNot@iDErXIlluZyd{vM#`r;uxErs!lPK5)*n|vqFmfbd| z)rhvB?&Vtli?r5D?T_hH%7s_h*ji;uZC*uu6K!P%m&99y4h>z>_v@4+>#RA$jz@Kc zint>xA2|fI29ozztEvunVjnlqnIuc2$m<RGp|s1HRF&vWD0SoLIW486EU5z9g&(TR zWby+yMSX_-Jbm!^VaI~^(-vF0M7f>NF3JOTz0nt&MC00fL-d(lvDT<gU%&A?l; zxX>%!w)@GokE9;jQbrsh11$mg2WMgKP7-JW1$;U9)cfHKGW=;|69^uN(p>AfxiOXd zefb30Zl4|+3zPQVM9r|2gpt&Qd}d>p(5(s`Mu)4x)a@VHENZY7hM#<yB(F~1S16Q3 zwAW(FGXNdH<}i`J)h%P_caz1;OduYX6O<ab3A^@S`CQ8`VU2=9&6rnI%m%4OW4J#e zm4mq9ZLXI|!~)fo6{f&_Ziv{{xfP}9I#*MFOF@?EbhK8lcTqto;-FIu_oPH+v(LLP zWpzayv-52QFZkVl(2|xg(U$S3>e&PtL7mNz>RNJE;wjfX>r#6w9%G2p)r7`zmWo%K zFK-_37Bx_gdW5J;Cj`R`u2}43+>&Ei>-tVpoeM$L_z<5oXWbTc{}7*<UUm2ZxiZqC z9ObL*b70H~;+=CN((S3;EknO2=aPY{(L7PgMFx%G%RuQj;sn{i3x}Ds&s`F_o4k9Y zyJJB84IaCS(G}JjH~xlD2R^x8{hr;gLeXX{heQoy2uZ;W1&Xouj*nKfo^&j1{M=Zs z(Sc|j>`89)X~z^AqK=}&bOncI!Klt?7wA+n_AKZQ1$<>lrhNQ*R0y&;^TFs3Q}nN} zgLOuP_-30;u+j+B-Dzx{Lh^fbb5xT=nS@|)fOPxk;T2k{Writk?6WoW!RMh(0M&|= z0~C_R1j|WV4?YLo4YULPUV2xAHWl|72lz7boY*;9lUOQDv}1YPv1b|i<Quh&LgUu* z4sfIzdBbrMg%mJ;_X7{553T*Z4+kr)=}I5o8)P`1V)>;Q=A{eKs?d=pT7;6AK7DhY z^zDu+FIT~#VceyI&O&=%1<7QG0F#n1R#84>q8eTvvCgiO_oGLg{t1V1*g}z2rgyLM zz~GZ;HY@=xjwFK|TOqWfSiIT7FuO)lizr3xy-#s3d6*|uje`V`2_pQkXWEVk&^vtY zo=J(`pyViSMaI11f;VL2W1isn(M0@ZW#WhMo}L>TsWLiDTGm-UJCsw%UBGw!Ez+zr zyqvDsT6)@*CG!&ovkF@^(PO7>-LpH4-T9WCf12nOB7|lGv(CTRXdW=r`cJjyf>g~0 zHk$b*-D3M!Rn7_q;GbOi@21QDLL)j}u#FBIc!Ox*|EU8GVzdo0f`Awa{mUy)`b*}6 zFu!c>2azD=gL|-)F3>Pz82>FJLa<2YPmBl$k$xEw?!ki3&@kYa|0QF>KS28fYk%K5 zj{j(|`Ulqjz#8C>$>aaCpTU=>e_gMk#i)cE4;}vx>ovgPeg2|e1Csq;*K2^m_^H>} zc>>XE7#X#c3SN0OB5F6<%hBp(KLUEe`QXk045Wb%zv(qv!FhjPl1~=${jY=w)}JJT zAL@s*0el1U0>Z%MA$pB{El)cYuwDanu-LcwiF#H*O7pc^KgHLTr?PQo{WNIrL^{3- zD1UjAj`<ohpRA^n6T5^dTb1v-QfL~oN{MkdpDaSr_v0z~DL&14^cp(r8Vn}YhXP~9 ziTy)<(8Atgm1_o)LE6D+g6DzY^0hALw)HfviaS*!%w32*y@ITWQUB`O@^Ndlm6g#z z^Q?6$3EL=odQQ=+_Y`4^YH*42WBBv1Zd@dhSY8~%GtWcOe3DBI_OgQU*e#c=I&;~? z$yN;qGU72fF76}QUDyzrR|dQnVQBd6{S)41>7W8E`v=v7VfvIVfqsu{3u4$dK@}g$ zEwE;<eMhuwFGY1}Gv=}N-lL$f7zq|9lo$eE&KB7%M(lb`N17I?lX^aSr>9xS84tn_ zk-7t{-QOEin;YW^MFP(VNKQ9dzVB6h@Fl=i<J-Mq$Mq&nF_PPd-Z!i<9!}4ie|%<g zNy?S`-Pz_ey5MrfgTjeW%aaL<F$;ZOt>8t&xJbw6iZX-^KS{gAtRsTW<pp+E&<N9H zor+)z3M=u=-01@KVzeA|d&dlHyV-Y76G_7B9ew4_D~jG+h8z~?H;y%;wFGciocuGW zwZYRpuMxU@u2P*ywIsX7;qO26)PJWUVxtc8M@8E@TAhuc^S-RZd7u1pY1Z%_k5F#L zqMcl;NVHZp&nkiTYV+&RYk)|!`(zw%DP!ksHK&is(1v|=%WEKCyLIlT7h8>VWFT3f zGo6RL-BF!04K6{^9O5?5^{a+Txa$wJ;kLs8KX56ZE<%HYlz;Q0Ou-mFQIeNCq9DyL zvd%9nvQBRGB8RFW+zB*Dv3gPNOqhL_c$NW|WaB4mySfukE6D7AqPX^+TOs!rRV{rT z8PzmhDuGrqcT+lYFtiWwzVoiyQ1{`3z-2iLFSpV%IhU!6%_PXNDzQ)X#b@VoaVsb) zoq^3)qa#-rFXxKvm*H*p+pAU#oO86_pnVZ27tzUMz$+=8c=p66B_`#EwalOnmTX+g z4f=JAV<U52+60U9vAJNtt?zR1yMkKGYwwSgIDt&SKF6VREwVAMer0`XhkK@k1^a8J zggslqN%@!i{LF1n8kQJYfhpz=-ndRBfzSz>!P;fJd_)aP!yLd}cN@a>1!Sl}a#Ia5 z-ZA4sg;u~7N3TuaOcUFI?SqkCZY%D+NZl*FX?Lc+D)FFp=3x=stgjPKEhmWWr*hM0 z*__D8u7wUe6K-_RX#1i@ff~5Rp_y2^8k8-e6`n01SK_-CwP}$<Um!_YSmfu=u3`%E ztrZ7$v`{rHvP_%{$H!P@#r_f<=A<XD1$2OyqF$*Vtyn(x3$xLtv^4bfX}0(MaBb_I z$=93akr&Qs9e8a!ui&hULVTRr=TGb>mg06t7d7a26BH;66S+aZ`;KCXPbHNHD4@l? zD(Q7tp>!?utY40se`liSx+Q-7I0gk{CuL7A!ZA%!$lm5XN%xiC&IiIJ-Y{Ao<Yv!s zFW}?{d?fkci#Hbv_U9EFxvBOq<d>0ZOhHfjoAxR=e+1=xAaaoK(5c)AtAX1@y(RMB zyrLIf-EKq|9}{s5NXhV0?%;beKkBH#{e7Mz1!M2+yHg6%t=g?7eU)1)Xm{>s^Xn<x z(wEu3MdTBC4W3J9_3I;q1MlmJJZYa~3Gf~ilzkfFVB$Y;*3Fo5NG@L2nA2P;k$;Sk z{O;8u4!^^&GSDEI(4mpX?_9Ti$hq#mBwFucc~)SnMsilQQELl`FdR+<Pg@QP2vKE1 z=rp7b>%}%j7EX0snJ#(^P&Gvo@1HnKtF~W$*~N}X&Dr%JcZeq`TZV6j=Pi1*1y6a& z2XbkrbGm~o$M}?hH_$5U&E%%Keq@{m)J$lpFGd|rOtOe}a_*`VR7%g&S<h_6q2#S~ zaz7~`yvP@PWy$KeXjh~*jb8Q9zx&5gM$^(k9N(<NX9Di&w9sXBHC_Et+AkLkR|xuL z<A-rIT|4h6;GK0?x^=ro6t;%r90d2F9E%8%mu<f%?dl@1oO}ql=`s<$AJ6JagPjzz zYE1x@eibfpG%dN?fuBQZDecuImC~syh@7?p=}Lj(8gVt_j_)F`d{mDq`6fzKTKS=4 z%4lKq8gR1+jEgOqzMDzk3E|#M<^d`A?yYL1=*TRiYhPM0iFh}ie92(ai#Q$7Tn}<i zKYbTbgV+O@q7bgebT7|r<(Yh=r(0o10#y?#O8QA)>l|E+mmwO#S!Wr;l(|Nzfn?cs zLoM_Tdi@wJ(1%ZN8tAi=U9+47<D|<BB9GP{6%8UiPBWvvvSExrL>5rq@KPhwXYo+* z6*_BbV_NHjQIg>B3u{PCo77ZF?@=uz&Q~b=;6%cnJCbVgB~MaHu-2ag_%bpwitC&6 z%Et@x2seDZc!I5hr%JS1HX-*%#*e{)Ec3*7ZxNts9zPEyiG+&Q#uHtTn>!ES+)lyu zK6E^-gwJw)vo`~DCJssO(tu$?86e1ik$O5St?6lU`XPs017^0lAK}Fd<`*wswC=U! zrTNZ<hG)*uEZ<4qOx$SVj<&%U643XN&`XzK|AbDr;M!J1p6dx1(<!f&uZ7fOG-0;A zu(;l|*TC;E#a$t2Zz*T!!fc;aO})&Zi{|=v5i>~;bmOuiCY-E{R!v1^`33lT%#mcc z0zM1x3&EC(IR%D|)!8-oivx6@<JZs@w|8Jv&)~&yJ#k!rr2|BXMmQ%br=S9^smYv{ zeUJ}WpKHsca^BAqYJvamj(w8?hNLxvUT$MvIYtw><>gplsT%v5q)Er^O@=OTOW>ry zlJ5w_;9JEy%`&nwUo_KdU4QM8SoIQT*`>EJspD~o=t_-FL%4X!Z{4mP4V#_x`#qi1 z6%FhmjVIsMY#Ylse*sp?*yJR)XBMetX^=!ppQKDmo|wjIcfQ=39BXqO1xGlRv8!71 z8yCwS+aVW~RK{EFo}|ht>}D^~9#py3x>uIw)DD)N>C)9wd6Hcl*uc0p)zU~b(S#uj z_Q*8+`KR|gVF+0lGc?ZO^i9n0-_v}#*)IErKQW~p_YqxpWPnHp=*nMsz=s`(Py)J1 zQ$+bm3DAXyr<SL?%8MAV9waW6E3f8nW@s(qyBjS`pmU*mSA4XsUWdyWre-At_tvYM zZd9wwY{<4_wtFm;MV6FKdYd3HI_9&djK!)wt0Q`iuN8*<<E(z~p*H*atlsJ2LZC$w zMht`GVat2nw#;{2&P?`G)>w*YQBT!%3UAoM1tH$Wz`M@nxeBvItkFG&ihl1E8A^mM zv}pdW2@2271o2h^n_w?$tBEUWGZIvj+~fI~%a3^mm#~j`{Fq)$E{s<ed&fU)4HV#= zGiDJqW&D!7H&2<G{Mv%TnZNfPd}6i@<cJhJ8edy!h?ZUf1Ee;*t4kIE)v@M&t95ac z_vZaBlfhnOy?lp{^CwlplrB3VGa9S7T3x5<-W0MiQlgVL*3B+S+j>n_)&tWd&=x5V zmnUJVR$||QqPcYqw@m{Sy$_EzC)e)W4OHigMqN2Ld5`zkP@97Yoe1BK)vWcTy(0@a z5SnzSK=BSEM*Yt-U5{D}XlH7UI}8RGI4R<A&joY$^__JuNZggtYmO6sY$?C{&}XM( zi>8-qvT(Wa=5u0%`ekm%v55x1h*a{e7M3N#BI$O2>ZK@0`c@Ek%Qt(1BlaJ&xwHUD zJ}ZK;7t+Z|W&-ooP3IfAyIKk`tG?gD7JctaJRXEY5K{QqL5~x1pv_56>m8|tM_2tN znw1W=w!4h#l~V3u=u_dAv0D_fa6em;T1?Y{S%+0Zyi0BYu;GDL$-?E3Qvg;^ecOa* zmwIG^)*OHAnJ#sD9N(%0Nc>Tz9A0t4ulajlEk(dIS=HG}6M9LBo4o6>TiSQ$YQE6K z+_|X;Pr{vNGgltPkI(6hBbxeUy{n4X)q%$G6}n-mF#-ysk7%g$P4kcZYNclGZZEsv zL`%g^K7Vm>>>GGPbNZb8unjHprbM)qZ-KR!x&9!zWY=Q?<Uk-CJXF-tkmV>*qJJX% zq-SnwqUj*H|LtzA<mTmN>5hzOAj$w^^tWw<5c7`cy{9&6Nj_sjB)r?WrZI-y=KZ`~ z4;wEdxIevbv2;V&g}Yu5t<~ouVe!=TYPyz5eYrHi*2uU?hR{GYl(+QCD*e;G^2~t3 zy@9U9JL9ynk*?g=K#ngI4&;%2IT5w0jW}iP(`A4|+Em{;c-QPi*#h}AO0{IeYs!U4 z#e*suQ{hXE(~4t*Qi<dD<N<P0AcXr0FQ47v2yqk&22jadb3@+YPMkGLsK!&qRT%X! zMqbP(V)L--X3CF<;=49%hc8O{2im_#d{+%PK(Nmv-NHdRmT^O@U8eV)OZcij>}>)= z?^rP5kTLYK7hl~sI^2t@&XjEGk-?vM?ppkZRb_Ph(g5y}I7gGJOO3Ngyn#NOjJngO z&P6)9+4^S;4c8O=M<cE?gnIy5H_ZiH3*t0Y@@aQs$_%KuvuS#4f=6`saJsgx^o}4P zzDAyudapqoa<=@;SnnGlq#|hr#*dFl!@1KbV&SN1Rx8UDEg}SjUFIvCy4Tt?Ww9AP z>S1KOx9gU!X{rY<uAhsM8MLueIwFwraW1co5+yEJ)8AThY&i~paU*2q3D#j=Z6lb$ zsFL6kmcnk9x~f;WcBkNwHCQ%SV54yOPOwhFW?<#VAd%US9WnxSR@DW)8FVXRDxLRM z%IWN#k!gr^+BkV(<PT&OWbsb)G`w-c+tz;4frpH}4F-57#y+&Eq2(`{@Hay3NQw0< zlRkVUneGi8MNk}1hG3^wg@jpz+xzlsfQv&6abtswHh^1zEzz(@PiNVEXP=y6+0z3} zsl;}1Mze=D8N15c#k=>dU|1e(k9d83)`dRuuC{)=o-oJWeDrkB>%U6^j$&KImNz2I zc)CYYUVdI|8QjT1uG5mzUmIK?eP(YU+2i}e*l_(#v{6`y>bq)!`(Y6IyVce=MLX32 zIM_1LDG3A|?MYuW7eKh!hXjVK&plPNO~2hS!d)~;)aJWQ9`V>IXRltuyPh?P_uQA_ z`AhUD8KQs5XrX==QP1M^;H2p<-lHW!t7T#o8RDaVZrtuO)Q^LWL68drWO^=-STu*X zo!#l3U`$n<W<XBrk@rm_1_)Ci6+yB$Z+c2gbVQW`H`6YJF_ZPKs{M0$cuB9tG4I|+ zfnX@9siWfO+T)Di+V#%Qdsg%JVacbTS|-e+G&UQ&2!C9Wc{x0(MM^As#lIY3DZJYm zH>Y!_NbbmAI_bk=)H*ctk!zhEPT{#5^cXkFRjDr%bmR|y2^N0X<(8otnz_)cG5=wd zD+O_WwIpj{g@`V<ULJv-Y~LQMtXEI4!Q-Y#L0^SQg8I;30lOX-ooBT~R!j=PQ&h?> z1o&|xZ)P2_H8H_A-xB6|1fRNkcXT*5FFr{CPbECawK-8wbl4W<qJ-%VzMYwb@Dm|m z5joy2m@+f`J^om0Z&`cX+_n3=%9_iggsU1an}8br=X>^8dc!i}XWF4pJ+G4G1b1(0 zC8p0V&r7tbYVz7_$v0S8@?(1B?5RC(j?Y6*VdpEkk28>jUQo9rr+r;=Fx+cfl^%-u zr>anX>Fi#BwKuFkja~!6W}bh|=v4}H>%Sx%g8M7NA&6I(|GIDpVh0N`dL2iF2!~u| zZ!3&W6O=(M+3@VGC|i$!5^z35IJ8*?5&Zlzdd&gn{dq}rPRRGa(o66IS>QcUoeAJ3 z%MWk_m;Wgo(nNs>haScjU3DoU_au}XDcH=Dzec@7Acd;@P%qui`pN8#v>2A02^s81 zB#9`MV&BLxbc=a>yZoMMbMNY~{cj<)#QM3)d?iVI%5%@>RQU&anD|6EUYp+DgHlsk zJTGl3rC;`JAKZD43PwKOMIJtmHC&c{0YneEK2?O@kSF)Lx@13u<7Du<uS~Y+kfYj~ zL}f;MK*AzE`N+KHl2!9%twKF)8;Nv$8xZb=^UlhiEtgS4wJY0w)H-oJr+X|bG&uc+ zU6K5z6gSv=1jdHXB`(lGaSYl&$e23W03YicaPtPv!wP-8T}8*Vmf_{1$kgRa-CaJ6 zU1#r5vz^yFU!5oA1>am~#(LAKee<X;$z;B{^Ntur8eU;1beaeq%PcJ|8!#?G?b<!5 z7YrC`$<6?icRqqFxz4q_GUzw0Dg=pDM9mmD3X~J#7?0l1?~mXN(Gz5F1%yH7v3(Bk z1tkgVm~c4rflg`q)k>w(XStGGM$k_P&+6S7To^SQo%<*bnqJj0!8I`5B>U(xQ;(d* zXTi4TBgT$-u#}dV6hGj7uDzbRA~o06g*I5Rspx;9g(W&&IV_dtj%`7VI^jYflp7I{ zgZ=;m%rv4Ez`#GK?Qef>OMjK`A=5Eve5g0leI8jj(t!8k&6Bz*U-8=Kp;m8IXHB+` zqv(5G5=)(p`0E+@#wPj7buO~>NpU<8*)<G5-B;qD6-$O+^Ll;8k~%}XyzgT%CO!^N z1Id}~LdCyOD!W57d@)}xHl%D*KzUC!aKvgRG@XR5JJE5P@&doU48=MryZ>82t=5M% zX0Lh0dDzs`w-`JLX840lm9b`b>soUtH3G66Ua!-G`~((&*izj^IwbzUpt9i(Q<uFZ zl)e!}I+8rv;Kd5o#>Jd7cA!DnCg?D76C^xQp5q(5dz+m>Bcbt#-0uKjC$7?;99|PR zWY!`PHcD-C7nlNBZP;fHl&@FBx(g(y_UWLzr(QnlWf}^3O`_}FFX7-WxV|(T3`1$M zO&M2(*T6;!hWl)?{XMK>e!-#yL^QqH3R8<$U6x~T#OrEJz~%<OKlV<S#o>pS^&W)` zV_HeeC!d5R-A;!SpUS5v!>0@>>A}|YJXrI}=kMUKfOXGgY2?eo%2MK)OH%V{N<h0V zRbR`acqg|F2RCXb1vP<~-nm3#Ae*hZb+xs<MtO-bilLj_QGD}tdfHThQ6c}-GEt~D zmNad_H~6>=x(c*v!V+FWk!3x2X6Q}}--%`xyzRKKfc!T2^Dkg<=22yzt5rS7kWJVl zI(F`+7A>Ni9z23}s$z>0s6ZBVqNP4i)lX!zkH)nl`Q|lFX)pIB=l$dF%rC9$&djly zay2coB)T8jr53_%Y1dncfm7eC>BZSbzl!LL0!<5Xz{gnIZ3dtrWqhjMfg=0z0U5{T z{w2+(SJUuwkn03+qW_x3PZ8#0?u2)QqfhcBMq4j5gO`OZm!psBXttWk#$G|PH$4`R zwB@9#|2iFM(@P;FwGE?j)F1k?VU2gWbaxh<ZNKT|2^K!^a=-F@fygtGk$5Q41lqVQ z93qz@-Sh$U9^PP9410^VcHcg~)%4Pv`n08m&cY~J%=LxaB9w)>$T<aHl(ccOkz;XS z*I_w|g)Lxjw-9e`ok5N=z=JhmOpfiFVY*`z=>@WL<UP{X)5sHRNxS+|$}PQfCm1YX z;4V!SDPNzYMN(f#WGzy!B$m?#hoTSxhFfgL&n~LMCcTexMC|lN-MRQmO6oNx92Nm& zJ(T~3sX!s$P&WM8ZOm4$XrxxyUvjlu7!#{zhiy}8cs(4G``(6n?2>qWrIlU5U}0uM z(Oy|(yL)80ngy?Kd4kY?qMrM#1*vZuBkcG<vA~{x{5GbpT0VCnjP(7e-EfAo%AQ_N z_xZ{UE;;=Bf<rl;2Xw+gkc*CRD4tWNbjBOgOoGV5j9r1dL}RA7Kzmxu?!(tKrQ8TY zBe$6Geq+swh*ht7K;(IjCoOmKoo^fuJAI*}@h%s*#q%%GO%~>XjlA2b!ytn(uswDD zsIbYw?5e83`&BZSOSz}P4SmdhgMtA9mvb3q>^1e1{0WP6Db{xlww{`I^d*j58Aw-F zBc>l6ldHZ9sB!3CTaAF=IZT~lMX!lFvR3m56YEI^AG1;kudLE+2Q<Jyvw#BLBi6Vs z8Ge0lGc$12ef2)ek!e%cmdYUMmdAv{>bBasWZms;UVw^efC|Xp*@n8$m1zA(tGL98 zd&l#@kb<o0Q54*cAWubeiEEC_*-(0{zyK`typT_>W%4}Ly*Z}Oish@q+FlQNRQM!# zR)5@z!;I4!-i^=qP!$;KWXToQ<u&m<n+@?EPy6!X4O*$?bImN8NP-bZP7*F`h1lx1 zsIhynf+&0;yV=-fu_|-xgy|@4UD8FXmuX1N>Un9{;ysx|**O;tnM1)5IvmprD~&4+ zeWh$5-I5{yxl)dm(?f%I*)sbW6GR67j1_x?ri^)2%Qg-LkH|!qnvV=mK+aNaTcFDa z`77^WM@&4Ajy&&}!}{LNVqvu5+|Uu_S+T>(o{HHdnQC%&zETgzc?t~Q*0d(_6P1I- zFN^typ@{+}p!U}D>{G-|Z6#Y@d1HmL_uTUcH{}N^7yQmHUc~9IREY42^(_573zvp< zl+uv(SUQh3%&xfMmvQh|T6=xq4P}pHZxQZd_1|2$2PEB)9n3N&uIyqNzRMN5%Iin# zSQeZ9So;CqUJy@!?PJm_2y*;7P<HCzOsC7>76FBQ&fZ6|m?jr6UDQ*Ch9<iCRMaL9 zW^}_>IvFg(%@G+<dc50Sox}Q8S?=fd!&d&$T7B)qjo+N3Bi_6<5;e2=D(oa}#2QQL zPNBm3G0C<4w1kb-vGAy+Q33f;>++Sp%YBo-Ug7(aqwhCe{_f{4!_}hcC=>0&YNtM$ zamXBpmcxi+rh)jok39}f!sf(zyN<~+S2=C$8{q+7$hHFXI7kN!SmeQV3aAN7kCQ1( z`gm0YhkLV=t<2}Q6zO_}%aQmZW<s=v)9-TzE)COm=R7-swU_>C#d>wQ3~;36)F}N4 z5_h)cCt)aCoJLB4UH+@mPbE&A1~|BdjfD&oAB~hw(aaMf(Z>4Ur>ZoCT8mcckno9E zuObRE;~>+N)**5AF^A6E!$mTph%@GX{ZWLOneGm1B>f=H-!V}wQ97w#b%lGgsNRHi z9~qQ>5#F*-*tJf55lrf>d#1^xo__r0iosZObD^=dsOWxLE^W8TgLNs=7LXIEPEzVg zuQhfX@+98fs>~>OR>@^(FSo>iTM%hGslN4XV!V{(WlN$nh6y#rirDZ?DW^A;8<SKb z4cBe_3`5Og_}hqYx{5fxu9T6dPaaKn6%nX)hZR>Ui=P%W2q2AM9cQOw=2jwi#N0WN zOR^G216_&|ubv_iT%92Ym-yfpROuX0jmp;w(R-PDu)wASvK~}Zl@hL<EHMtB1UEmk z7tlStW?W*3@<9r5cOv&VEgv*brdCy9Dz&z-(y7gDYO313nBIviM|t1!1;EHBp2Y_c zf(pK16cer8Jj31A|Eyfk$QmDLnC)I4@m!4f&h8B+kU`9Y1fA-7a&%}m?}MV?cu<m> zZ|HXL`fz^bYn9@7jU4oB45e%{&E{rjcW0QrSZXHRmm}30DgxBjCJ}PN3@Xq$ac3lG z(tH$Uv=+qtWx?to>)|`52+o3%>=RH%f#T*E9G;+<?dMJ{buBt&3Z~EOP8aLDR)U97 z)v>%R+M6jV4|Gwtrygd*UoUoo=f*}Eyl;6uUtp+6+e!_72Cfa@seQAremf_iAMSOn z`#d{VGsw8Gdy9Juc|UkPC{og`;Nk;sSD2lyc(}S025&^78G62$kxFNwXw1&~dADME zza<6TVfS!=qM}c9wI~XgG%8E`7WodRHA++;o6ROP)(X=ZO1K>tEmvpSn7G73uC&Wh z)}`f1#u)QpjA?S36T+6UG(YDe?Kb)(_I~v@mmSf04-Wt}kQ9L9LZ)UVIpACqB2}Ji zzW8~r%DyP~dpq-~v66}Cptej?H?h;_t*J@LBE?b(iB>(OlCL_H)zLQ3T*;ShbGa&g z4ygC~3hyV8Ejk8iYCgJrI7paeF;Dm^)Tr^g9*r6}*7B*$;2dg3ems1YFgbuMJnNRa zrO^DPj2lZy%()Xa=b@0cQspBQL6!^qzk~;b7*9f00RB@eX9Zhr@`71UNYxOd(JAmQ z2HyW$=`VSG1@nu5AAjZz)(D(u25<szb^tyA3wU$=xiJGw0X6_<05iZA-~hg60XTxM zOu*$_0s7z^V{ncs_{tSv3BIxhUqMRi1FZfepZVvTt-*N!Km&OHr!`9IuQtjS+)QII zsE**x>Q5R64&0*t;f$a7y;K?FN1bkeT0`(F069efz{)=paJxSN-0`>mfcWSA)d$94 zfQ`YpHwQ1Cg*3nx+z@8)8PXSy;8Kttu>~I?{o@3_hxo?g0n0Twz><x>-awl_v)Ysd zfITJuX0=KD3}UsZh5@nKw1NF)wJG__z41@q#$Y>4l;4~=;y?RkhpC3~%MQ~9_TTI< ze_kNNNJ1RgN&<?(tAPKSd<7H17-|b<3o=muW`Zm#766y{eNi#gZ}JsU@S<Woa6T+# z-7eq*6xhz^31rdmli!vTgRhPtMZxJKL~=p|h6M&T9hSYD@_nJ4`~{kx$Y{sgN5B<$ zWijLp5*?7Dza%F|;JiOC$qZg@>~sc>3iJSuG;|G)9`p!~q7?EJaO4aFXoaj!esD|8 zNpOFo3c~JX;ZHO}(|ii0Q60`PUOxrPrI}#15P}^WVmWCxNwd#0C9(Tex-Z!JyX?I1 zjigDexb_nuL7#6{5ORTLRt{PHyT0V8Ml$B3^h@3FvF%fxZ<?ljpYdChmYXjZ$K1!< z4?Nq*Xb0^@3@C_bho90Op-_&&mbDMYw@*}clsXDl*H|YBS%gmRW~Q!sVG*rYKZr;R zt5RqzVYrYyYR>!Jv2*4dYQ0Zf&MUOO?~vcMc;sj3X6fSPPcuG@0;MS~DG~28P1qYj zXXLrr?r<KWrLDA-a<uUB4GmG@8xcrTex4Q5<!E6`J_w)Ww5@;WC+v0aa$-+fN1Jls zem%5+D7Y73$u_HSQQ0~XJ_%jtXJgNAkxp2`Yg25}G?2V|p+6tm*hT#Hc7a@TJ=dbW zRFVX?*<<}xzTT4gDb){9-RWiZ;UPudz}a^bg8}aDXk7w{EGlvSXfx?)o0zW^G5N<a zUxG37kT8n{rNTa0s3A>^VwR3ceF~8I3NQT(7`*DC=n=WV9`+RpSVW_~J0d!X|0>+P zQ+PNb{{=|Vvh`&PeIK?Xs$P<kHaE2yJHohC$Vw80@2A&Kv!rNwgP0u<7js}M9Pk9! z5m%)@#tL;jJv*E21_^XWlf(@1Hf%lTb(60gj~0u5G8+_VLdn=5W0P#f8O1<@iz`Pm zn&hRDRFcmL$77DHsPD4+X*S%@ge4-``zq|>p(nM&#u3hQL}!n?{nd@vf|zAa@YHjx zGLWo7iy7v522GM_R2G`Rn&sE%1&i#0@C$L3yP#70O*Rjd0nEzOyD&xVSE|umVVh0s z-V#p4l#S_Lbb{w~Ve5PnCxR08OxaiH*;gprUxaCgz~zG&$xi!;F2>epWJi;j$&<+= za)(5X`n`vrgk}W2im!fGy3hsP5ZdEFIP?|Cc8IAsN}@O>MV*q{%jX>SaFFXxf}mWt zbXBw=EOG<-fzI@pwxFF9?>f?m)Q8q{rVVA+2%*oW&r_-0U8_R1)~;nlTNq;qf7?Io zh%x3BO_fkQK5MFX!8)}`-#hk~Cu~6)9G||jTL!QdNw7Bg^tbdz*$>wPzb2lB9vhnc zaEcM%jDfS#8fKH>HEkg3QP|)q_;D)TOdqE%)&!Eq?o)HrMf?602WvwB*xY~4;#gL+ zaJjtD_VnIe_1@hFCjV>4cWLFEqKH^^V#yvk{o-6U6ArvKM$91FTlS3vpIlVu-Z@>q zXjy6wtB}#!0lsCLZNe9d33IUC^S#^1ghdS2+&b1xTblD4K&>B_7w|%rTvzQRJ-4-p zmixNJ)&6cnHXZCKkv%UkP^_6ZXNipF!lkMRS<}PTPi0;Z-p>L9*JAcxP|ZS9&FxG5 zxN~b-W3#vR>We4)o-Y2$y1nW`Xt#sFnzANk|Eqm9eRS=4R=BsBrSP0UP;K7#$fswt zKlE<p3zvio>QY~)dtw(*C*XxLeEneG@aldc(+72JQWkBI(ltMr=6k>T(ie$RMFq5V z8H-K!8fD4C{$+LHfeYja{!w>hOfg?}cVENR6&~j^-qTf1E+>hDFUbUj*#SERnGBO- zYLhZu%AAA1dfLa2aWeH|&7Nd=>LkYZfMjFt10`<P{1h7c^%>~V*|4F>F5aE&7(RMh z>UHI5l!657y?K!nY4r0L$uz4RdE|m<!QuP+$(K**Gf4)eczLCt4`|e?Im)8-O)F74 zr+TK>rsfG1ZlLz5tiU=eQaJO7g%pHS?A!xpDbHu*g<ni$Xzx&JC09fr#)k`J6Q$46 zSQrs<RVp{`3IzixdNX6$3dlaF*Rbq(-{nj4GiWKDeN_15v+77#BLq4M9@E!88d$57 z^;L=~F8L~u>peYuQsUlWzVceX`4wN3{8yA<@?$E0fic2d7JMn)7t%M#_#-K%G1A|h zu(CBadDDjG&0FoA(kl|JZ73(SB?GPrl-&sx*wolQaBDOcNW}AgxNcs-ImIE8(`9Rl z8q{(xFK9>EWNfu9jFMfI4!h<b5S5YfrLs1!>s$1S%uby;v+x_EDc(f?a5GVDo452J zpO!|{$|V1^BF=0hlvZl|z{Xc#VLhc}a*2A<Pay=}ECbunivcrDtwoGjfhL->jJAz- z?OJD6r>gmI$BHG{X_{A85>r}4!*%8okd)rzH1;kT_z~-XjmRZ(6)?LWub-k7;dS}U zVUeTX#j>ATNKao2=C)Kn&=c!}cUuX9f{*6|(2sN3?~wPiRcvmwQ)?!Nb-l^#n>1rl zw<_3OBEqkZCE20H9hggGGJD2L&)%vVDXckbMKm<anVeW>=!d!+dIca|0D3ElY%uhL zn7Urxsx|kge90)G1!{1+CGDcE-B8v8=?F8+9F~t49=X_~VfV~4Obc2~1yk{`GVQ5? z&uF}*^w@ouYlT@eRkX{|xkB_ep`N00jo^v+qjA=K19B>{g-ekKQ$=)NiET|(vwSAG z55?b4>vJnZ|J<x8du|bR@Rm*HdGv;NgoZBt5XJN*W!HQtr!8$C_G)YsJobSFk>hg5 zQ&(*C7?^|Cdz7A6&3^m-d&>t^@NiVi_gq!mFeX!djE}=N@Fs6bTpCi23!2cf%_M!t z6^<SSP>%&~FjhO$eI5Q`+6W=`2h`8-5C3KQDB#cPlz`A<zeTS2MUVAh{i4Jq05F_T z2(hY<f3ZS>-w3j9ES6~$02B(C8hL~SrvTqUK|_d}pLc&wq)GfD(o8s^V*gP%CLjI- z9EiUWhQ$974v1m(?{EO1ARb|Uzk`B?kY@i0RKtG>D!5;3jLy&@)G9q3gjziSA7Nm- zVJKZ-;jobZ9(<jl{~};%;eHXYdyq2>EKD~H_zVjNgN6JT@QCy~#Nh9sVg9r=u#m`} z|5<C+{;V}WY487}H6*{aM)Fth|0&kNfPzDf{N50n-x_l8XAL3#)sTM!?`O0A4fQ{V z2Q)ZZ<<Io<4x$45y^~<!;Q!<f`lr?VU+l8qsD1E20+;_I{f+@PfC`vDGXOK6#=mF% zLuYgV^iR$N!XiO>=<j)$4cyftd%sG;0hGafy7f<v-2vbZkOuRRzxYcC5AOu#Eg@Xx zUr%%ZXh;ZK00nsed+UdcpK{1U-~<Qe{cOSfD+C4zBkuGM!ovfu|L4g3?eOcZfBVP* zu3L=wR~fmVe6!fkw(5iHb^=2Kk!Jk8i2#iK-|MIPD-XS4+2Lx+9D`!Tx%heh(_->W z9AqlCwpNbDPGqj;PG)2((kidy8Og+q9St4K?VQYQZ2%<T2V}v!(kn6Px5{L19BiFz z4Q;K+<ZO+ct&GVejctq_^qp+~PkZkHP*wf^|G&8GB~t`(Tv2hLY!DZM69p9kw;~7# zC<3z7T&R?*T&ZbUnj@`TIZHEFuCg?@spTxQWm=9*`9ELh+;i_amwN%F|M&O#em@>~ z+%w;=_kO=$?{VHIPdyAIBy^~(Ol}!>N{I67H$WY8HUFiod+N@~c_WhZ*?nwh6zH9w zmY1*YQka>V)=bSOjTC3n9nscig6%~?;+}VD`336OoV)@-UM<KA2nh*j-l0c~Iv^lO z9qR9|?wyuxAD337?j+jDX`@F@-pJ%E-_)Ffk%BqC78}`J-8ZUhEDnWhTt0=NYmVK? z{^*{Wl9!X8Gps<}bJ(!Vlr(kUoV-+Aj{vmx-F1zm<MSI<FEahwM7ZuYz^86g&9VBA znjA-*k60$}o#9~Kzp+W&<FL%uW@xMUoWi`6w0w1ZT2@+0L0W2j!Pu;{wqAoGV<Ub0 z#m9K5g$q5BN8%!`d8x;Y%*xJhHMFf)MnM63`hxJ+0$nmK@v1b>ykINC$wS!tY0lYR zzRnXw>H?_{<zw_YV9mA!AsYqh$>aV*xx6NtbL^f=UZ9@5`c;(2uZGLr$GMWvdE@=F z`j<PlM0s_DeGSbycF!S?LsKaa9Y}(l=am<xCy%wT=l3tC8>Ra=ys9FPKeEBepTB(8 zDK9f6KR+j1-8H))EiXGcOLLF2W5-VM9pbviCUouDLz@N5D@r(v8p`^(ESTr)j1oXN zW~~Xbx<tkg5YA(8{%;q3Y#(pzSN2b!e?V|^{}#;y5TJbR-!A%OMeRUESvy#?&k=TZ zj_jxo@NcR1_YVs73kVe4!S0L;h!l=FPT~uavs07vQn^gcOU^97C9NMiWv6Fl=4bSd z*IeUp?3|36MfOZoTC!L^X|Bn`fsZ*qN?{_|g-cquNXK&7oZjjtjK9m~<nq|PNH`;Z z8lg_j8BsVgExX`qO6EO57FPvX$*6O3e1{2jPDGj}wfUyxjMRmRBCKGB?F!yG<`=nL zr0LL>my7&dGR9GO&!30qJ#W01$`p<h!$Td$M+Nll7(!@tK@NY8-jE$!UK+MTGn|q@ z(R7JUP=ET4deK4pmU`1!>W<8Ch)&{4EQWv1&_3#k<F@$I-vY@*tN%3Azo|JdPygr& zjVBGd*Yj>R8vV-~0xGNjaiM%(V___`Eit%xj3N_m5!8=LJI4+BucUuf)_zY&@2#mp zO{fFxABkb0p3uUFSK40bLFebNza9+dX$0i9^7G42$w(WSobQ{Ho0bjT09xG0<N}=L zrTgUw%1p<c6e0Wg1^WAk`VGw-nw6Q8o|l}PF;=5Y2&zO?MTNKV(<(FJaGpG`7}Yo0 zw1bP)MNkr<skZeB@b&jnr)8()q-JKPxAp3s(7Ab-mpWf4wX$-up#f#*c(n_+w`r4_ z-zqh^AUPj;Yg*TWw2^9D$i%*D$F^SMLW6?*BRdCoXdW2SDY$uX$4)Jqhjj=DY#!R7 zrGHT8kdC1NK`kdpid1U;^Ljs}5Y~_EH!{mBoZTbFLtNUheB~)StuQb1d2La|mmfk| z&niAw1O);=oT>}q-vR+|s9e#;hY39`HO2C|oc1lOQ3_$(EBsPtHTF8am=$7m%NEU% zhJw^misF@bse3%%!zGN15%ICFbl*3O@HO;NxUAdQJ(Bx;Dsms5HLjoXr$t5oN%9(2 zQC_f~yt-ACr_-Os`0%KrJe~e5%5zCH>r2j1=WR_KgyoCjer#sK7g@QItq9@q3Vw2t zEGoj72)6%!a(h<$p5=Le?yAC;fk=E7bD}BZzmi<zPyFZK2}IbiLbMmT`vkZG?r=_r zM&}6Bz#l|_SdavAK{1#MjG1G(jgkJ&Bg}6BHJ*JQIsaG9JuSr&=RyyfGL3Lat~&G8 znWes-j<3IAMLx|QZRm(==6cuWB1~fduSJd>^cW%sFa{u~=~ciA?*hQde<|Qb>?*)| z*gC+C(5-+=|4)Gn_#C)_V}NC!2Ha3;220p&Hz1sqaK0ur6mdwLWGKsA*!PFUd_E07 zy!Se)xsNJ=?c~kaz78D2{)qwqX5-Hea@qatb`Fn(%z~^m!F6mK!U4*mS~x-(flGWf z9gb%+IU0YMdWd0L7kdudAnaLIJoY@vBOiM%UnXJC0|Ilf=X&-!_Uzx^vFC6zttp0W zJoa2k=3~!sHw$}?i#M?6xY~lfGxmqE=eRkCy({)VV_zNn2iS95nZoTHr!}zWyj&l9 zSVckD;}L3&J^rZ+ez*aaf<1S*Ov9eTV;T0`z*(a?XFsz$hu}q?AyF}1dql?zA;oTu zPfLMHR4}#!T5<V8N@E{GZQy<`AynAsv3Y5^$$4q1Lhx`9@dG(RAn|SV`(?7;sIBEX zWTd5xz~g*V7dsqw3^cQ}JSdlGLMU>`cT6rw6P(DFN2iS)&7FRnTsfE{b93`@iqcZs zj}=0fFDImp%*}!s!I2!)9L&<iKB5vUT;qo&9VlUJZkiAe?5ddL?DWFq^fVzt_(JE* zthCtVf(#*M*p<2_HpdZ%U)O9=rDvaVd~vvr5n_z}5TE%{nh<Rq)skDfrlPfs;1%ML zJ)^zRQHW9&JtQ(UDkp`*Fl}^)u_;+;T{{ZV%zhfuBW<+oju7pF9@c4Oa%NV1;n3me zsuU6d`*cWTVL?Vto^Ve{5uAGD7dvL=BizOc!Nw_tQ_m1YZc%1VVZH%pa4O=IH$-#; z+5$o!cYH?9=<J>xfgA)}ghXQhD#Bzw@);KqNz_o-_r?Q!&KvJJpjc=#AhoCe?Fn%# zpR+q}Z0G-q{sUpSqUzHz_5B`>0*1q2k|tiHFp=Ux3MV#aT)*cPIK{A(<c+POyf8g^ z`BjvM?moevlKVzhQ6Bf7a=1zI(yJ&>*FF;CBe{z5g7w@tu!{0@?IY2B+^xd?=Z*Kz znqGA6BT-(@D#{DcxI>DMu2q!huazgZ-#S!D9)H4EN-v_kwpEm;%O9e=3i}UWzw!Lb z-$_%tFQAI<)8!A*eJ}bCo@G3b-w9C0hf5XXLzh3q_^_{{JYD{%Ddd04D#;VqFc!;G zQJzT^<>~T=DDSZ*Jh6L@@=E*^yWD+$RZ*TUe~9k;y^8X5^@k|$rz*<R)gPj~>s6Ge zt3O0}m#ZjGmp?>#=c*`Amp?>#-&9eaE`N9m>FvuZ$>aBgr1C(Ncd&}`booP+x2KBo zboGZQ?~^LZ)8!9Q-j*uL)8!9Q-uf!a)8!9Q-kK`P)8!9Q-n&(lr^_Frytk?-PnSPL zc?+v3PnSR3h5Rw6O7cQv`9qX9ql)r$`9qX9wTkj|`9qX9p^EZ!`9qX9x{C62`9qX9 zs*3V-`9qX9qKfi#`9qYKRz-Qb{2|I4Qbl>X{2|KgUqyMk{2|T{i?5QrU|IeU<#n&3 zJYD_}<#nl|JYD_}<waIeo-Tig@>*9>o-Tig@}zT!t)xDQPB2GM(fCFf6yJW}A+SQ{ zm^<hLCIVMjHYCc#Y-E(RSvJTA1%MsVktpepQWf^x^L=F82e@WIJ%nx}p5dE?bBI8X zUWaaO)U%t4dI60zD@d|pNsGt?Qtr|sND0?Sam6I5G)PFrtc`5EX{yHLp=RjN%hkM6 z%h$&US25y)jx~!0CN|z=+u4Nd57i_qck_qVjt)t#5gz^O<ktVL5!@hbE~~DXM0itu z3bC5pp<6AAj;f{aES(1<NEP8kcPRqyYNv6Rbs2YYrgnrcZM;p`dY4rhumP`#cIf6# zZOAmD9wfAZgb1S&xR|j+gxYwkSVDw1UQOWeYC~ob0UFa%=$5sg3q3pZk=uBiil$9X z*>{*aWF8R-)175;Q`R&mDMxgq*m#?<Y1dV4V859S4YHa%*lKcex0)1377-@!UmV#X zDTr}gRt_h9SH!)Ix4CU+6++>TMwYoVyQXJ1LevwBO@_~6$x@IRTdqvbp04Q5xAC@6 z%CvA4LRS)+jF65cD@md@C6;w17a*<}53upJR7$jTpioW`?!?KQlQ<+=S3)AI$gUVs zu<^E1O0?2Qbk<4iNRdf*OW)<(f_x^1q#Mroo$F-GQP090B{l5jH>#77=J_`l9nxyV zA<vU9fL+L!lo@fabPM)&-2WwPcCvZ?YQ6lYCVn5K#(gv-#n*470~^yUe*K1XD31X& zrV;8tOZQ>V{c7wwe+x@NmKx(^nV31n_N#<32ciM0_ClT=pt7U(8oxZoQ4VtKShzR= zz8V7)oM(%$=dz$Zd~_f8c}|#kPkLT=<p%tjD)>CLj9Hegdy>}x&^_4+`7#!^HZ$Oc zK-twG*|E-*YPc>9?o7j8ENS9!oR84waOZd4o6!}lDsYZ|qOWjt07tiQv<BCQYW>V5 zRVtq4m}&+&O20^cmD}13xhjoDA?`EbXPzl1n$Cy$IK+A{MM#QQ*hZE=6eh$nRtj@n z*eKoVi}&_@VM4kpoyU<k-bqkXbHMY|^5EZm9J3$P+K^_yr{FHnVoSym+s!5t;670% zLAnE(H!u;3-tWx}7rhQ853RXaNW|V?eV{FP`%zu4RZRK`BY#q@BGm`HCIOFJI+Fb% zD^gu?+*{8?<+2LNwys`LPN=U)E42^<uKh?2$<BI`Id|m<{$<JbkS&vpx}rljy9y;| z(9@hhO1(@nkU!!z`N2$^3y7LxNUt&>RB`AG6Ko1J872#zYA8jN@40aNWWrD4n?E)f zKjiRd>E0CH)TC^6tPL!oN=9JqrEnpK?<F&BiE6HpT7;5MsB}v$rO0(f{ThBK0l|ok z$1DH6EnygBm5M&l)ZR*kLhA!TJ%JCh$OS&|!k!CCPDi;a_CZgicFyHIE?pgQjn~+| zYh>e4;%nzra`cJIsxe5TzII7CZYt^tI@KjntG<-64TAs?y-d7J!VTKST7nz?97-lT zIF)Sp$7L14mdOrDI2P+`Oj0YyJnIN<7|1QpyjwZug9Y>M<(MBNq^tQRgJkK-2B9Ur zKgMq_jn$?n4@l|_AM_UThc19b-L6dFpa$_nT&ysO5$X>yPn+SYRIk`$a9K!8cF-NR z8qpZFdAXn9*3F81Y$w!J@hGLZ6wg9Qm4TxatQf<!mS-jNaUVhQU9MeWPIRZGp3cXE z8nxhmF3&PdI7QagPbZSXtW}nW3Ua+nhRQ<MN+@-?wvbAFo{3Q#k{<|?U4@kR06A7j z?-d4e4|>{jp2;<n9x^*z48~w@O-+@DaN=5v8@4vc4GtxoD!FliG6H&aAiZmH*Ti2I z78cq#Qwzfd)+lv_c;k_N8bASvWtD1x%!IAXL=WLjyrHm9ENRuES=JXTjPqc6>aY*_ zD_ADm4&|Phf_R;pp^&b7r%*-p;G#ro#btmhQD(~Ch>JuY+2d_P!AGW*aaAIDLH=FX z!=<FSSt4FpbJMxS8L3Z9FJlC?nA1#sG(KF7)hkjVj2esUmAly6p*bz4M>}XbJg;5U z5Jw8{73y+k1HmS?fooYu*kA_L+e~V8Y4cE$AURHzB!rCU@@jf6S3?`@i;!iFpa~vv z#smt75_fYhBe|)Nh+}s>KUizqbz=k@hN{NM!roOD_FS^0pd`*0(qKB$BI_Nx6zKu| zM2HDXSej|;R5IsjBKAqx8*Wi*{We~(IZrjd0-IA2iiL26zRk6<3Xfp3wbo{rRhQu1 zO4&Y9uziYZqRjRhGJo^hRU=_5=YsNl-&k}57uwI{`#iz^`Kr81*>5Zi>=ENa7<dS+ zxe7wONU(E-sz_$1r_9gg$2F(3(Xw=A4Sh+l8`HGP=!&jV6OH>0kcu7VsWxj;v6w&V z$m~^ywPC-OwcSUwots4@rltLgv}D`{!)dv!4b4OwpqP~LpU~4HRU9t~;d)Z_QU&2! zIiJ}>a~Hz38shX)MRq4rD9W~LM$69jNXJ~$rlF*h%1&QVevQh=??e7vcB<rct-Q97 z%jda{exhu*irk$lgqg}TRTgH>vNR!=TQ+9=MO!fEul$%1(}lCCu`)(!OCUl>nZ|2F z0~O-J2Kjrcg;UAGr(zj1)glSU71-XMYNL0;%e1}Fmmrqj_Ch}aw`8(4?HOHLlXaj# zghz*NuG$WX_EbaY;b<>RYGfI5{g``(Z1D1%L&*YFBH+48?8M>zmXT4lQQFovYftXw z$lzWf8@zVxP?Bq!2#m?_C`ShO0@>hI4u_H$vqWG_M$K|$aKDcYUf6ReX>6VdjLGmU zM+W!w*kH<vLy4J1A}}n&pL(N@XR@iNGr<UYQMey!te}@l`WEY?7OZ2nZ;I6aH0N&V zJX6jE4QQ~<J=}9LTElZoJp<YW>rds^@9n7(_cn0~K`C<~{iq;Ud>>8fXHX0M55t6- zh;`5u9P#X8)*F&R7}Y_DY&H#($v_%H>f$vWM6Fes##%%7<TMsR!y`U2-E4}!Q?2a| zWlZww5d2;o>*)osS%p4N3)XhgPZ&i@VE0MWD47KAYvP`yEVzJsW|VffMSE1#cx<8Z z*is^3UqlHZe3d1UiJ(LITU682>A5{94_g;e=T`O*Yb5<4NKzS<#Ccs8OBzY;ioRxz zBoi}slc`ZjL53u`DJ2c3H)#vGm<=a8Gol?)tq_j#cAJ{IAhoa#M@YS``b3h;vwvk5 zF%t>%drdg4)-&5{Vuv1|cZz&)?T~>UH=X~>>;IEKCH0O;eOU5)@_sb=b!E?@ymwIk zl)Rr%eqHJ@lwXrvp-WftxYYG6%Hu_MRcA`SKT&Rne$S%(p43C9>|>NaVYs(Z_e4dt z7W%0$>oL%b`>F8mf%C8UwMH9J?2%O?H;TQ9=qyGW7J95|kfp&MJ*m$ppaF$7pr{5= zj~`lF3Elh!QKe`Ram%H>nY`sC+Qj{q&5?(twm<iQJCvMub}DJ`K<ptr?VN<;^6TGh zLH=Eo0=kyEJ=`pBd3A;z=_q5kZ<SY(=|n<r&#-E+?^AoHk~Zjvky<jJ+9%<>OlwBl zrpVIRmnE~0%R;$*y517Dt+Qm?-e<Q>)Zy>K<vQPS`6;)plhAW4Uq{Cad0p_~y=uh{ zCCjQgmGpnC^Wm~;NjNv|Ls5sni+*sOolbgo%0pCY8M0raM0+n;ML3jPvQmcZC9Cp7 zwm=iI1u}av!lUr3E@b7lc9m>Jd_JqKqGo-U<eIgMo~`;JEVsLxX!k>IBJQzPhV&lm z@<Tct@7kkYH4B&d*m$o5Yhu=TlV8vl`BfXFdCpt=&E#oc-ojM21`M}JSZ0hU6ZJ;< zc`cCI!M!KVScBB{iggg`VM#jII^7W#OC1vdPg3uN`uiID(X1!cYw`#tZ4K5H+_%Z2 z#@yef(>-G0$GfF}m|=_%_eArKM$F60KX;7|AdWS2{g3vd&?gav*u_YuIqF=qUKB9K z7xo&K$m>)|BRSmL7Yl!Rnuz^zo+dm7$8K{nXPqrpBdNMUx5*{RUCEk?u0v09VN>c0 zovogEQ(??Dq2qE&GO-Z)ceuZY$H6(IMExjKa6^E3DBR#ogKfEgMqZNZG!WMMb#{eA z3oxPf=HY_Yzuc7dT6x-2wp%!ESgMfr_<anl6aCb|gyPIw32C8LW7cIkUgd2;-MSCf zSaCuyTaV3lratgrvN^`2k>*w<O~f@Pq17VlbfZyDr=lz=t1a7!+A`&46jL$9Mw_A? zU?IHORgZr9&S6g}B-O%H0~hQEcF4h+GT8+~_}!}f!M<2SVBNegdmQk0?DQb&pQ$&S zcU!tS!m8m<Qx4BQykh*`BTE{%9X-E!P4CAKVooNsU#oV@YIY&$!8@(5=k2a*x$VH> zrE9uvyxZQV!Oxyu2Cx3UMb8WC`^=bJ)4fgdYKO&t?)>c2#x155cb)NO-0E>Z<fg}L zZaaH!UfsE?PW~OH`ZA=*yZA|QwXX_$U2^|<#=NlWM?0LmX}Wz=?S5^4yZLBwgKKlQ z?ray@V_mlnR#Ug^oqzh5wU0U<b!+eY#V3va@?GUK<K3_N?@xH-vFTP~TF5scYrj+9 zwSCq3z$UvHLyo7bJ(~Zpr}aBCez|zIf7Yj$XK$W8J~Z)IkA0=CNq@Dw<#OuSq=AzV zBBiCKdf~PD?3y3<BAh~zlDUgxNM2f2zMn7umdrUm{D8mRwBKLeJ@uOjy-pr*Z&>8F zdTs~5l@sV{<4GA_o)<lTzS#4yh0QLjl2yMyc)#t_4YM9yUGSsY?adD?4qWTd?#qm; zMQ!&?nsW5zRcjhr4IGpE%F1yUw+;C;_M4S$z6$VM9ktzmp|ivE3q3!L+t5Dso1=~= zyLGx4JhZ{2HS<OdIahb_J04d;V^00$7I&^i(uO%}kCtvZ;D79$p8F<kY<9DgS$2yB zF_|}pzPr}%di?IWYtueBUFXEMj~|_V0<V<y=!mh4+;|S%Ou#Rd6<{TdG(XvI_vCE6 zZI{O>#O_#kn*(ach^rIc9X<C#i<DiBI}P3Z<%V7Nsl(Emk%yO`Tz2u?&FfQJeEq%a znYW_t`!`!^X+JaVE8pom?u>7?#&hkrQMC>>%es2F`VT*iaX-5CHJ9(Z9?9=Dq5he< zFR$NrS$%e!&zX9^H@lqpNrT~SXLad&>(qlL*E;>|<87k~GwgW(%N?4mMgP|-yf29^ zkFt&rU}yi*zh}<HP}e;U=SQotZd;?GnwEt#&wun*^X{IXXHTn>Ib+fJ*cA~cyH4=@ z_Ik0&ft|_Is-GV@EqUN%xAUtX2VZEFRr|!oO<m&VAMBSnKlJ>}_2CViA6<W3TBq*& zAD;W|uw8BEdQEzMoA@N}s}2qR7#s2Wre81Dx$n1rY*f>wW{dwQ*}A*QyzjQX_Tc+n zGtc$zICM(V1g~?WF3wue?c5uSRyiE#m-s`Iu1VR)I=x!`)0w$V93NWUI+T_9NuPm( zX9jd{v*3#Rk?(5GdB5k0*w_CI&AZmtV&jbYFYQeqy1c7P`pf$)EDK+o8-F29ReR{! z`^7!?&Uxj=XLlVB#O>>N@xvv{c5EG0XuUCg*5U!1wr|~#Gx5UCtjOF=Sz~7ACit&^ z;JMysp!o#Tq~UeW{ruO?-7iHRr%k_4eXq}=z^^(_TL0bA%taCRN4-<D<LtVSLE~pU z{bK2{^*z>{%1YbZZ-qr_UC;c7+rAy1l7C^J=iGxWe!TPA*TZ(~x_!m|$hE#d-g)A) z{>&@0S}dRb&5fjL>uZ1ed-`eHBa65E+U;S@z2}B|jDKZHM&lLHTiow;Y(8_F`}fyZ zIFNm6zi-Um&+K;S{ItfuT^rM&@mae&t@f?<Xno_$PwIVT+jYo^gl)SW;_W;FRzA4> z=)uN!+I2eY@J{V^4}W@i^}uz@b_3df{lUnkB{zHf?RoOc@xygjwtHvdy}RGkI5VdI zq0+w(G}`meKVw52Po{f+J<D&|Klgt*I%{M2lP9~nRKL@Ga+kD+a}RY~@zxEiU+=lQ z2K5=$uu=U{pH)9#b?WZSuNo`}+xKR)`IC2M*820SCc~DDuGO;D=i9E-Ho3XdX3T`V z<4$87XUteped*{G=S_ag`?}SjgaOH2?loO9HmvLZ;Xe$GJM?SH_<jd>&2l-sXLnbd z!XSs}E`MZqtQGLUy@zYHuI*h<=KoVX*XGyX;%=WWeB<va(cyh=`F5%u<I_EGRsBY9 z4x6<-({AFDK0nz#Ey~(5&ayD<!;>$~s<kufh|RI4C3T&DSo}w;cN*8~JFnKY#S85x zntr&p+mU?<57P$qY<j04%Dv0(;;8=Hepo~kqI-P5FZQFRmp}XRy^m(O&a9L0&8L%F z`qkg@FtWw|Q3GDCeWF3rly-A19ap&jI;yw%_cya&xi$KZX%DxZkE=DDy{qR&iyfJ_ zrU%<PwheNs{@JHJK6cqNwTWlS&~Emwg=_j84t}(2|5uF@vcJ4~&8EeIFKP^Fw_)z% zk<Bl>wP{@Mo5$|YXusQP^yW6BKe4)Xamd>{?libif3D-bfv0y}`)5PgxY9@0K5e|r z@3RKSKk#?WxIF88=Zjk}|FM6=xEK%5wN2``Se5x{!(ZA)*0uPnRsOXG2b(l|?Mkoo zK>ys_clQpncOEpMWAEVUxi;O$T|U*Z{gQdr8g~1n<iHA#4Xf7wapIxRxYJp;J4|0+ z%Nbv&JAbu$+oj7wYyvxfaH3X5erKOI_x4}1e$dhBQ?fT6ShwNjRzW*<I(_BZY1+Vd zH-~=Ia>3N2wr7$yZSoEdu^Lcs)7_>^ABBtv`z5KfYUJpjS6*s<$hO8$ULIGAQ^QZb zbo}w!?4=71f3ehSfP<&q-&e-WJk#ycfH!~f%xyjE^)G&@X?y<WcjH|AZaTHO=N#L5 z$?RrL8a0YO(d*)fkT>3{b9dCY_YdXvc;#@I`NrtWU52{tPkVi1iT&gF*Ds_#I`-E3 zK>;nSZ|DA%{A>7{P4Sj-_0G60nrCkxwD4t$4sPUAn&)!trCv4(2`jgB{b;krzB?Pc zniLfbjy{xf?ZeGmqU(QKbU(yr_4pOj-8=4cs`=53^M|iYto_0Ao)HZPjb1!+`H(Bw zJqBKk`Q%{B=$&_8TfFbWsADIs(r@-zlkv_`w``lZdQ->x%&^?q`-|)at@kwbzUddW zFwed8c)~Z2tuKYIGyB#we2~5Es|D|EZR?xx`MWl&o&I{Ps%aVDT0P*(#2W9_TYF{7 zxBt|*5nH;WWqRh~t*>-g_3fH^&aU_CSGR6|e|fVdw_3m4ukFQM&AKjf3Uuo2-1ogc zzc{sQkhONil@GqV*w!_2?OVg=FEp9j+GEmh;}%7(jBU~K=J@=k{Xcr}ZLNoETGxH+ z*zyGfr*-e}`o%qtA7wZU+x5ZVoJBv5%jxgbHeke-nq&LWmXm!>d~xz=NT;wL`;728 zyY$ePUkwVobM4bZ{{4bGHn~)<-V@9F?V64swx{Tpec_P@?{4>cIOg3Mk>?{4hHQS# z@}&96YO|M*+B`LMad49n->xe>+2_j^KimFRVEb94SJyXeJ!{YL%wJZt%)ij`lQHuS zeckMr^WV;H9vm{}e(KEqC&JntaX-BHc<N2R{^JWAYV9`v-p)Iwt4qwCx4R|Xde_q1 zLH($Cmn{X?{ZMn2t(fh<nY(N|?yxT1NUv@awGp9`mQ~Lh?WDWSet*}J2UA8{<>Z{& z={V2(^7IqyPn(w92(b@s*Pz!gzuIqTX5~9A`LiXNyWV*Fs7p%VcL5n6)U;~#)51}2 z?i=~>FS8@!+<MHo&^mQf(v;abEq<+@J}<g)ckc#qjeP?a=T&Re?e(Q6W+pr;-VnBO zPM;fIE8mMevg<_DgTe{R|9Hz}{J{phhdPcsLmrD_-z?qoB&_C)bicZ8gP-<_%)jum zdE*s_j$Nt$)(0_WUku#2^YibuUN=!SN7tk=brp}vHUr9QY_w8<zW$~&?T_%3X><Ap z_4Og0K@TX3GQCLDkz~QIFG*iH(MdXMNRptc=*!Sg1Uea;t(C4RCrQLc3rj>}&W$+@ zhVR!4la8Kw-LSD~`QpN1$*oed^13JIYL-z=uFSGrsd>qxu?WG)EO7-jtbvg2r5>6d z(AF!fAizsqFa}4dBXBe{J&>;j@--Z#j=)iJN(!1PctUd^UBP|viuRcx=}M6FOt5q% zSh^A-T?vt{gi2RJz0?_5nb{-YBi?yoJ>RS-@q%>Z<rmJ8FygrI+O8L3Qds$muVI=f z60itjM`-(TUjV<}`!OEe2|fj%fxX}W;O5yM;A<Gzjd)pv#>Q(f6pgter69xsYB_oe z9)X)qMBAK+3ekXzaV7Gpj@3?}_MQi?*1%E$?nK=@i2ear(Fd{(TJbB;>HA`dktbjU z7LJHQ`*fQZRzzutc0G!frI-_Vv>Cq46O82++7i9jlW1jMtVA*x?L>44zLABQi`hh9 z<q);RyC>Edg1Gh)(f2Rovsg3mU9Nd>=OUt)mtg#4IgxrTzPYmjGv&9!t{p@NcM+ZX z4BGiYqUlGl5HP~+o0I5+KMgmZML3?rVl@Z`Sb^5NxOxt(!F&fKZ%_z|z-TZAj0Lcs z#)0u*0+<Af!DKK6aC4>vz=`w<m<FZ;I9F)qyo&v6;C1j0cn^FC)`2Ym&ZeDUH`ojI z12|n+f#)Lj-+?RO8n_OA06&7Cz|Y_p@Ef=f9)l-<+ur=@tO}R|el6D;R0Es_79idy zBR;1hj=rjoaA<&4W`MdO=I4Mnz~7*^H_->+2sjO{f!}}%ap?d&Kp2Pzo54LkZ;Y@7 zJpc0w@M?nj*iB(qFupy|0_6d?0n#u8cmsq+ATB#$^_m_;3uBR96X4H&NP~kQD~af2 zD$&s4kcWsHIg)5Q_!BfoB+dmtg9t=sA{Y+FfD*76tOgsw*Wf1*m5X=*UjuVQd@E1{ zJ_dJ?00tvMyUfJA)wu|RH!w%^ZKS35;lGct0?=kGMFK8^o`|?Zpz~J58;IWqcLJ~N zM8AFvHzG3MI)E@ef|VbSAzY3l+)g3hP9x2nA!>uPm<$rn!OeivCA=hzAx^}87MKm@ z062x_f%#woSO^vYIFA+sWCe^j!9K7Qz{#`>EC=s`6<{S;1y+MKU@d^R=mW4GYyca< zCIGJzyeO;?1uqf2MDUXE1-D(;e+oVWd%!*bZwjkN9mM_+I1G-0FTj@o-p9ObggHPk zVC_@nNpKP%NU+)|VFgr#6*vzrfN#Mia2b3Lu7VrjCb$J|gI~e#;12i$+y(c*pWrX> z06YYbz~A5>@D!k{jZA?VumHU3lMS#1{1yPe5|8dQas=jhyeTLGlYtcOJ8;bYVRvx; zlib4QxW<nGJpcxFs23OoW`Q-}eeeNT2abWu;1PHX{sB)x9TmO{4+et4AQ2>iVz2^8 zW%@oGbGd#UJOwpPQGSEkpe|?!^1&Q156lM(z*cYy{0{yAcfp^))eNIdAQr@dc+eXZ zg4y5$unw#T8^Lk#J$MYBfTw^1O%41(4Cn!Rf?i-0m<pDGcfks<3VaSOfrsF4@EAM+ zwJnfmK`Iyq(m^Je0rrFMz!h*6TnDC>C{I8fNC3S-UoaXh1G~U(z~5%u3$B2FfV&mK z4tRpvpe+~z#(@c7A}9vS!FF&GoB?OSdGHX_u||0U+JbNp0g}KNumHRP7K1mzPH+U= z06&6T;5M+af&HK*Xam}Uc3=o70CU0XU;$VJwu8gqI`{$n2z~<ADBs;dFlYh7Kr1i+ z6o9$lb-?ui>j2xqN$?x^1Kb6F0#`etCZH3D0$o8g7y+h%mEb+F2D}fBg4@8t9&P|O zzz#G6L%=vN5ljM;!Mor9_#RvX*TGF-UJZ2%2mxWBC1?!>f=uu-m=0!uS>Qvk8(aXF zz-90~C<TrVupjsVe-H@bKn5rQ)4+5v6MO)^1Al`j;3>d>1gSwF=mC0xIFJAeKr!Ia zm1ST#SONBfv*0fH3)}|}fx8pj0ir<<&=d3mqd*B*4pxFy;5~2%oCkk`2jC(28`N}0 z{Rg^&7|<Q`1UcXpumY?G?}4@82)G9vTrgu4xPa;)1at;NK^hnaGQf23CfE)>0XxB` z;1YNMTwGBvf*QaBv;;%JL@*gl0VQA+I0&wS8{j7R5m;7-c@PLfKqv?U{lEw?4a@|y zz-wSV_!OK67r`a)9e4_=yAcI|U=RXYfW9CZOaR4TGMEZhg7x4iI0n7~$HDL5Z{St~ z{sA>XEzkyZ0V!Y@NC%l<iaX*QEC&yOlLy=ZVn8|=0k+jdT?bBscC}E?gKV%6Yyw-s zHgE!*0i~d3ZImORE$9aZfkH4BECffuJ@63Jhwjz`#Dg(lC0Gk4*F_l(Hi47iSMUd@ zp+<OvP|yQpf{|bfcpIz$pMeYDJ8%bh)<fC{Ya1Y+f+HZ(8}0&0;Aj)XE4T&bHbp)J z8$pH-!X3;2>CKSe!DKKKybD%>zkHFk{7}Y#TrdmF0Y3gnlb{<|1NMVM;MX>&tJ|VH z0WO2lP5^=6%|wJF_yn9uB_w3j?Z5|g2Hik37zRdwg<uod3QmFFz+GTFjK~}KfJ86@ z%m$x;8{j8UEgfkcgo7Fx_^J-*3^Kq}Fb%8+N5C;~1C#>OOyqqK1j0Z9$N>f574Q+* z4&EP*a0Z7#=m^9Uhz0#YF31B`S%?$R1mu93U^cj&jdC*wWiBw!#WSD**f0+91dfAk z3z6QyX^_1Legv<9unn*W#DRez4-|mL8&QveuAtpV$XB307z)OMaiH&JxC4v<t@j|D z!EjJ`1bzayK<<~QXTW+8eGGmE^8mMNU3#A`U0Cd5?^^28Z$YU`L)X%Udlw#iar`12 z{@c>P!dG2Px0Ws}aWPFO<zw*|=>S(w3%}xV<$s^a6l@eFZx!qke;4p^E8*8p_|-h) zS_$`@uEaBC<y78O0*8{uZK5f?U(rWef4K^wD*To;RrU(|^i`LBuBFvWgx_NE*8x>b zYY+*tK{1#D-Ur*j$KU`s2vGD1ZQQfibK8<XhQ~`1MuYKS9{2=Y2Y&-@|J6r3&IdFH zy}%&A?Y~#RbTAWa0o?9$>AlcQC_hUyzxCkSVwal2FPE#ho*?|fFE|!|#p~klLNoa1 zP6XTst^JM~za~~<-y*~l11AZ4={SPw{Nade;<x8Yskpe9+uDv;&|Y;X3OCebbq6v8 zgWTEVK&E&6an2v@ZY*54zQY3aH!Rp7m}4{Me3J#v$KFvUkiYc(%mQJC1+oL$WACi7 zh-GniX*}89f#O8sm%_hf4{N>`Zf0tY<96sS;EPUo*Z?1umU8S`;VUluwo;z<D|(ig zd&Dyv`TcZ$i%|Y{uD$G|U4fYK(-MSWHh&mq!P{x?h2ounAY5;Wcm4R=?fQ2@h3kA* zCod3ZK`_^Xf`#8u**)b4!h*`NE6Au_fiijec7@6AiEfZSZpJRvxl!L8Efn_x;c{MF zFBCpzDaOqy?UR2@jct&dlVpZKW(fY2_vGO(cZ=MA{&0~}rrf^Za{LzzJLUE%&58cw zS;xaP@y2d!3E%tcnNy~dAcaijy<o*XrF}|s%6sLRGZtp-b9tH###x9a21Af)<vwRu z>QaPKqS7VCQ!S?rxy%sQ9}KAhLj05$(sH*1z!ax3PA9w&lF}_onZ{Efo3ur44G?VS zJjx&O3qc5kX|J<v&XJtMITcFJi`O}ivZ<gl*SRzZfF$|z{49qq-zj^&C9X<x#E|B= z;bmsS@W){$rm_Io$+>`C8h~FhRU5h&0ypczT0hK`aik10<Ef0FGcHqZAD4XcxHX<S z*&oJb%Hv&MrZV2;X)r{u<Wags>35|$x!?7}Oj&{`Wh(uyl&SQ)(wx$NN^?s8Da|R} zqBN)UpUzwuVniN)%97l8dSMAlb4r==_|umu_n$mGS%T7>Ql{~I%QdRu^uiL1#h)l$ zXHK4$I9%lBlzvdwe)@hWFRYdEE{`Lw9gVw18ShGS@^I02i!u!=!&B)_rA(#YmFAQ( zmFATGQ<{^<yMA~o{iif1k6V3nazE(%U1^_OCO;_;Yo#BQ{!^M$#*xyT+&+D`DE*+6 zDUUyW|CMJ>?sug*{s67qe@gq5aVz&j3%xX`yr*=hTtjK0sgI=3*2?d3PLjKY>vgX6 zSg#1sGpDpquCvOu5Uw%B+ET0)St}81Kz{?*1M##}d&{5aV?)me;c5#5a#(XUWG{d4 z*RUK8&9d%feMwAVWou}5sWNtyp`}a>%Fq&Xo=zrfajYq@tBuQKjaVK#N}0-BDR&Ep zw{dgIl&LhQOhrojlsQjnPU#1wIeE?#HAg9hv4&>coyzc3+Nbop+&=vjt-PlU7o|*P zxG2pT4;M}o`r09<A=WkZ(-)^j{!mBR>s-6Z(>3doT*q-Pl(bUL6Vi3|rRXMIni924 zHo<zRJY1FjRK}yypJg>>HXEpQGq;t*@`|qoYxAz|x~MOg&C?w79PjL|vTo+kDlblz z_muuo`c>&4Wt=L_DbttIoHC5$<~R=JVXHK!bc@oQGVLkNDczzpXFTmmeG$6w^hYRi z+lSjo<;gUjU%6dl%zrI4Y0gkhQeJzV{c2n$uVEym3GOZ6lAk|U$*Em;hucrw^5C2z z)l8DVIj?XX#3gDd%*oT3?jDC~*>YHv$@Yn9tgOsHL9)&zq8mAvi8;WqZQR<`PwgB# z>;o|`$jxy{&-b`=V0ZGpD9o2Dz_YrP!gXtT_r%mE`9Q2I#onw?g<IH1K?n;jfAxK? zyr*9qim}4|WLyu+{iif1#klAe`8{@zJfwB^xDCjCa=LI)-s2L-_&qUK>f6V0#l1T^ zbDT3cq*=$|R3oN#Da^R$<noT&@Z3+p=A_iFiwBM+Wr?J`rz~}p_mm}z@}9EvP~K~a zUQe+Hl>1XhU?g0hNw}uZ5?ot}QSwC?6<?*tCQtNu*TaaS9<Ss4I>3v}3eGpgECLOG zW29MvN0^N<755mAP#yCynyjTAjx{Xph>?9zzcWU-H9WwcS<^+tryF|cLDy&<pT%JG zT*HVSn4u7><GVPFsB37Hfcf>{aX%gH2Vf)_+|$r`5Jr{3Ng25q>1JlgSU3cu*`RZ( z$WDwPf2qf5obxDhdBoxV^(>L@xtL9&!F>WotwB?a7BdHPEtvxz{!N|Eo@BD^qK z%=iHwN!BL;*Mcxw%<w3(oPjvc+k%nkts=9xV?-OgsbR=&%pL+ZpNUM`gSgf(@pFub z0B3Z_=N!UpT?6dEwR(p!+X>tQ1CL-9iH6(QGv-Gz+e1TN>~p~qunVZZz-S9_#_07% zupit84#yDgAPb||yqN$Ms0K`d8Q^?k0jz-yumzUD3fKWmcEY#>W_|!<1&mDy6OQl> zE=G3%vW@U%JvZzzaYp!_AhHvBj>Q)!Yh%x27j=OeNLi*njvD}El?ZRp2s8#wKvUoY zn&W;m;0yeKKL`MUAP5A55D*GlfH2Swa4FCV@F*Cvk?@uJaO@*MBxnyhfR3OO=nT4m zC=d<0f^Gm=1n;{ey@4K}C+G`$0c019%V4Gi=neV+WEqUO@S28*LxAi-gFzw~0+K*7 z7z$EADo6wA;61PcWPnVN4~E0ZBS01y39>;BK=O|m1@iDr0Vo7TU^Ey5#)6l?I4~Ye z029F^Pz)x6DPSrn0WX7Bz%<C54rYLvU>0~4*Ixs(!5o~=1@pjs@H(z70LXgUnWu|! zyac=n-U3U(+u$9r3@iulf|XzuSPj;I4d6rYK3EGr0PDbdun}wmTfj%KcQe?A<E>yj z_!#T}pMafU7x)zH2A_dFU@zDQ_Jaf9bHJMk;BcE*L&;*CGh8=FY;(s5Dp=_uvIqNP zo=A7~MCM|@4m{CNiajIM5iVZHGa7C*#H=n27Cy*>8jRHue0>$z4t$W{CAPLfIB3}4 z4*t_{xFcrifGJ4aj4cv4vrj{7ByfrJXrw_6U&mnPum-Lpu4&-<;U^8jNc0TX5oY~G zx+2jt<^x3r3_?E8a20!r>BtbwDjEBSz};YIstDH;Uw~5@%BvgrUOxCeOGm$4<V6jQ zCt#Kk7=T2|{P?y=`xPh$KszKv=4T{2UnD}N1<<b__`DE=BLOn<`hkzfgGorBn~*4( zB}kaeDh+wNQHKB@BuHlQ9vw4~7@4{UMaCXN9tKkZ*A0yNu*mD!b3Jhv)H#AWT*FV; zn;k{j4qAggAPMAv#b75e`2uAfaQYJE5!eR~f?t8lF_d|L>x$A+M<iMcn)_rMCSsc4 zn9t_njK2&op3PU>dtGt1KykKEVQ!J)-W!Uu#fm4FDDJ(fID1QRwp3y6ZN<HJ6lcq1 zXa3%(Q9ujO23*ka9rg_n6HF5j%zK0o(;NhYmO!diRir|YsDzMF3H7Q<s99A)-Ks*! z@m)*d*IM|s5`JxjUt8g~n(%8U{Mrk@4#ICJ+|n8dRV4P80l(wIG={r^Kr0Q+;HDrD z2HI*6-N@f!5N8OOLaG^#&9S!tmN>Qs>>_rLEspI$HNdW6SFo9un&YO$g?ZVn@>8%X zLUMldk(nuZIr%xm3Yw?njBJ%NY*=PWTC4n#$$13@$?5s##rQ;TN*Wcng<<y8vlzB6 zj%CBbr;Y^yoFbn?fbfOjVtB=5%;sV2YfRSQjXfqEv)iO&@p{=SqA6q7<#$;YTQnN* zRA-*zd>BYmoOx<<Fp#D;^OWXkK$_CbQ<*OUX(}^MVGaY*6lR{fyb?%LmwC#vMRnbj zWuB_s7f4f;d5ZEnAWc!`smV`(G&Py0B=-T*l;p`cUIC=3$UFu4Hy}+x=BdZ6fi(4) zryReJg5yK54r~A$!AD>-*b26RkHJlF8#Mh2g&-ILl0gm_1&YBoa1Z<mT7QiS0jvV6 z!5MHCSR99cK_CbMgFz<X<Zg-tZi<BcKfkvWvN>mU2{Rl^SmK!fq;o@iE=d0SQqNkX z2u?vefPQL7{EvuLU0nTl#!yxB_a+1Rx-If?Jg98`9#STcb3Xr{MwhphdE6W>F-Pte z_qt=w@49Q^_5a>9Bu_`rQ&;@&tsA%mVYN`1estwZMfE~s8edvkS~Ggs{b-?%kpGy_ z6x_S9<hLCO^2@@p3C+O0@GI(KKLht3<KEM5zQ3@7$a%?}N*%;Mv0=>0zH~*mM?<ep z6V=1_GY-a-x$8(y<1ee4nLm7~k%4<_2BnzS9J1lnrUvdUPV8)-`d7g@9|QNsdcI@t zd~C`Hog1VhN2(F{vCDq7)mG_>ZtqA><DzRcwM^>ZS4Jkvoob)eDDYX)IKaR?)0knN zuFYPVt&=4kIZ{@9JN5G7FdJV3=Eeq8^LA~&KgP?zy{(z;y&o>R?NPJLJx6-|rB}Vz zb{)`PvPHLdq``S+jgDA47wN7^M~?KMU;9R1oSw2&x}w`VqT}jEpBpFE*3w;*jvUD& z{7}fps}_0pHsF@bfy3Iwoc`9nnSpy7O&+(6TNyD@lBC-^(l-`O!y8w>-C1`{I&!4j zVN=_AJ)WD?#DL5vh2EWZI-j4`+`zri3FkYvDVe#|zsx;!So>wf<+ciIE!m>mJ5p@$ zJAE35g}>!q#+)M!i;C`lXq4+4r4ITT!i0WP9ZWns_tFKOEa}LR-fsS6$o`lqHPu>~ z7Rb$3LdWUSe*KdV*^CL7p4ROhX?@h1?3qUrCN|cZlkPfF)9jJ??e8vVTGzn6j5c!$ zTje_@NKfnbj+Eo$RFrjO*pJ=@%vEzV8Pho|c%bfi>By1#`467(UC!;Z(iPp_5e+`x z#9u|opu-DG?V3B4EPh&@KYVoB9E+KsHc!Gi*JQqe88iaQY_@{QFf*;mFkS{d%#2O; z>}G;xe@%EH1{2zGhpja(A_*Vz&{&>i3lT~9poc*b!n^W%?r;=b@c_%M-uhc`KbjAT z_*_mB&cmCs1Nfylw7;TsWgd>W)vMSX-Axb<m6OAUIb1YhYAQ55Wzrn+wam)OVzVsE z7iF|o9``25Hb-|;rMw5$M*YY}C3(Im^>s42b3(V-yPFx6sR%SSCKu?7ibN*VRwokO z0Pf}xy2-|=q~AY6WURG=LpRwZ;anlq&VW!~)K6>?ZziVZme#iR!m;>c?`{FnYw<y@ zBaa2qj@2M~Ek4S1<gr3@H9W8HUQx7#zIa&?VeihLlv$4Tk;6psR~#XJIo3xGQ;O%l z0OR5<%UI#0^@Ba$@^>h?;^<V8B&O6TXIOE?F$w1iAD}m(0xPU^)@a3R575~o1dykR zg)Rdd%=*%kEmU}tlb|N>wW72K(vxwfcv4lFC$r7)q-kZIoMDb9%_{TcY70CmOC(z7 zX%8fK?zO~|viR0MpgoYDykvzZWznX6KzkrPiA<+Lg-|w>GQ?mbd!!8qlwMq#Nu`(~ zV);47tXN}0YX=U5a%{P-9A3`l@N!K#EJcoLiZPS9SYkV-REYRoE11m165BDQvdA)O zXN0c!jo{)pLMVQ9k!Resj>s;Wf?LRqj>s-tYe<o4+_jtwG_Dmg8s`Fbtu}Ivx^|O` z*3L~XaP1}+(M~C{jk~tkO>45)4JM1-M3YkF8+UE2ht{>R9xxf}A-Yyd3{rt8k4{q| zJ~I%ubH#c!gTpohVLSIJ62*(8ASL<#`$@q;ND4FXL7zEdQkY?Zq%Z>?^_lZjz7F?` zWFclCA-Mi;B@40K*LY8(E{Y|D;biguTT++|m0${(3QEAs;1w_p@Y}sJ0Kefo3%m+m z1GB*#Fc-`N^TF$20ayqYfj7Wnumrpb-U3U(+u$9r3@iul0$xFCC0GSkgZIE1uok=z zJ^&wrbznW%05*b6;3KdZ@Egcm!Bcc`yx1xq0-~DnLRk>Cxc?W*LJe^=Q78)}%~5Ph zA3@_rqfQ;+cGD3wZVa}AYs?i(68=?+Sd32zYeXz|fQZHToG^<JKlmw>DmjAgVO&H8 zzPh6kk--g=419TqMcAQ1ZzneB*N6>zqpk?6t`!kh9U{W2KeI=y+_fUC+#$ls{h2*- zzNS{h`I-=MzUDJ~WNmG&h_$sLVr}hb_Q)8uR>T-JM2t~Cvqz%pYehuWhlr^9Mm!>{ z8K_AbQo0Z`yy2vU@>A2CF`KJvS13&yPEoq%qH4Y|lbnz=I=(g`DOw~(?KGTzWGxb- zCJiSWS&PJ|YdN)OT&qnjiWZ4cI}IliUGvj;*cwh7y5^|yu;nD7ajiB<uxq6jiJ{K6 zMuJ{76fKfPq8d7sTO>o#B3bk_#EL@sLp%IY7_sLru^UEfagH)W-hpPkFHh`1+krCd zLs9$}T!!sH8TR4RvK?{F#ZpL<SmnD~Lg$$+nwINCId!?C#}-Y?bu35xoS(LL(SX}z z<*Sr5y@U?5aVQ)$GUssNI1Yv5I*r!_$<FY-J;j2Y#wK#f8rK?-TwCZytLEfXk}tZp zniC{fb4tQFe;qTnTQ%YPXB?b*K^ZOt0rITS*Tq2~IalmP+l`pgbmi>knA(k)(i6g+ zZ-zRf1VI|X+=-?W%$;bJ5X^=Q3HC*&ib6QL&~(DN3#}5ux!cW{a9{MrC@pZ3S->4= zm9T*O+{&}S7x{!OF`i4Nps}XOB~!SuHU*8fe=(Pwv()C2+m;Z2&hq(ki4VHHH7U9s zcM1ET+q;sv1m4%*#9Xozy|)^fn`|I+DSB@exr9F;US2NI7mITbA(z;pY|wOu*m2ol zhq7U=kV|?YcNothn%-c!Trr1SMl5M^$YqYD%ZR0C$stC&nJXc<!W<$AFVo3f3E`E> zAzBOcyO=9sL8WtutjLq}f)~oFzSeD6>v$%u`@c_FHD37sSE(pcsa8o9<+%%A<0{H? z7QU6Jhs#w@q~c2o0PMvvzDfvw{=&Bs!mC#JR>FeH7QQ;wN*6|z>@<YYG9%ok!U*?X zj1wJwB8(I5<#D3D7$-XV1gdF8gW9HoUd{s={Y2y10gZlayv#VZpnmEc&PS$#8h#F{ z{XB7a_#CVD=b+lp<Kbb0L)W4fE69<C*-gcv>&s3hzldTyzK56xmy>V~F*bO(toA2Y zDp{JjW{llb7_z?eJwDee3j66Qgx&cbpKE1d#s{idNGbp5Z_;>Sh6$$Ni^{QPI9sL) zm<r>~SFdZwo9q7oYp-6{j5l+&Th<ReI>zH%(uftuvM^5Wpi==%g;D1EKWImpXZ#4k z^?%TeGC#}MGItLsH!<~HfF4&@Oam8KkGlXpuCADb@OBVhiDOTj6^mY12oPGJFUB}I zX0aI!q5s4&&KKR5vZ+jSb*WmZ6~E8~Ib_5ZLZ!Pc4JEDWLQ!G3+fwSHLh&r`q|tOu z8HgJXL73s5Oi4>mL?5}HK;u2-qU$Q`DVMu$%^lA3hPvHFVTSuWpVO=5C&TCPYK6^{ zXYs1x4%6rKs^LD=D#U7q$<}~Z4YZP9Bw+nPA9=V{lviIQV9k)-bL7>3H35&)jY*DU zU2mNJnB=p>YP4>2GMYQ!qZOl*&*4>1-B_h3k5zi=k5$TDS5XQ4v#WNP?PpgA``J}* zuum?mq6ECFhE~|F8W6UthJ4uXIlMYcH<~$%M>A*Xk7mkUSCLl->c%w(^0?+e{c%mX zu!_9uqZ{G$;So+B#R%tfc=fTDHtZgILEvLAz41=D>oi_9Py)Z`r+m>*X-MCCM(tE; z!|POj?#SSozW>8hw_Z%$;km{CFX#EbXs967zi6oF-ffasL={z&|EUd?XRRiU*0klf zuhF)~>tI61m!WJVx}w4swFwzlZA1|jCQt4AXa+h8L=ojTKI9%TDx$*na>X90u$5e~ zN6JrfmGVf1jS0yk@^|wdXkIm|EmV`47&6dIe9z>0ESZ?cqMZ1i*iEJ1_afH1hB}dL z1fhmIk#+e|HbKq6D>I@D!?R%JGPG|x8R)7NWf*>WMlM5o2g<l#48KMrmr>peHKIEV zPnVa=DDTx8QHJ4eXSs~>Dqm5C;g@XWGNi!^L$BM2G7P_NBbOmfb2Ief&5O4!_$}W5 z>i4mXPc8VboYz%T7<R41ye_@|Z{u?`U(DwcT7%+C!<CqBRkbMvm9U_)Qwj{JUe%$| zIh3gExzi;P`{(QR5`>%-I`|SxPFA5~PY|?1=-5jvS@E15dV-KV;WdQBlDy~ai57&k z7hXh2ENQQJ0pZztwFE)Vo?-wydsf_=HCNZ!AdN4Iv2;!7xJxX#_M9Ddf=f0F9d?N& zo2$@KCkUD%yqJL5vHCA0=<4e7)I<An)I)JXx@Jx&kDM`vR4B7@)Im00z9J}^HmnGW zrpr?SMbm~=K+$x0%AaW3u<|FGE>G<fO&eDGMAPLde4=T?3ZH1YJXKFLZCKS4O_!(S ziKY!Jd7^1ay)#sgi%qmN6Q`25#0mFlCTLTnnIz#{HiW2c93i1fTbP-6RQ_-<)_*oU z8(C8w%JOFA1d8uoRjS001U~=xvH|b@E91+O%fzrNzlHo9UahdbT((4!ckN296TMnt z%ULe0Y`2XhO!R8`ZRqFlYK1Lox$DH<4&!ZWo{pz!TWhD|RkCf3B2_y@P}gARMR1lu z70^r(TxO5VwG1l3(I@gZ)yp*4jZGfZ3FZ}Xx?t4@&E&x@yu3;mtoqQee8FX=6$(?{ z#C)t1&dcL$$HEYrX@%Q)VTkQm7-HT(<+|G7ghO#oonV7xfml)9F?A|&6z2%uF@*(p zOp|b~(3vZ<R*q6=F_up%7FV1p=H-)$v3ydoa>bd-&Z1QccEm~|cf@sO9C;-XN30}r zN4d_-v&^DZ3g_Mz%_271WlHoGv3XXNS80Ji-t0K>NSLMS&u@14<IRo}j}&43JSwkL z6Nr__U}PRmB{G;hrUs*9s=`V{5>b97@(g9ZB=Gsmd|8d86jothsJy5tTM$aZ{<Sh+ z5-57Lie<i1SQX2BN!Y(u=1T%auRc$iFKE1?n1`DFRIwZ~x~7agHjOLHVjtU!{!=N2 z#PBezNb5qh{H2LR8HUwqxs39ZYEgz^rCKhdJk?s1VOX`6%a9ao@p~~+NQirJZ2J-3 zP}I!ve#CDmKEfM{FXnj5LrQ3O8csIlCl+xW-*9624;<e{i^2g*QHY%vWtODSr7A-$ zE~)dvLl7bk5b7^VQ7IK#5+wG5h{J>imZp%q#`r*?C`7Cr4J=L}7gDxTlw2ZuNo)w| zFHi9tUJ@%q1B+D1T~m>l#7fY>G8J+m6?sW)@aQj8@f=<fD?J0tRmfc<ddc`Wj^WBq zuGI^}n8vF+F}E46?#k~QdNJSTKXJZ|sJd79Vt}?Zk}1bh))hrme!7BD5ih1IaD^xa zXN3xQ#W7NTSBsF(jlYs1x}riwTk4NCG!XKvNeh*lw7p1LQb_2}Ijyjjr;QP#+3bH& z(rS)i;8pi^p@Ajvu(G)PoL7;TpYv+_@^fCHU4G81>dVi0b#VDPuc9tL=N0<p=e!cW z{G3<fm!I>>_40FGwOoGAE4a(gd4+ZPIj^cNKj+ob<>$Ooz5JY4wU?js>iF_=xqEoj zhgbQR-{%$j<>$NtyZoG2qnDramlfpayn4L+oL6F(pYzJ|@^k*eg8ZDn#vnguH_A6& zeP4bqw~wFYRrclg`3nH@b9s8;=k?Ed1$g=MyfVN1oWGbLKj*J2$j^C|c=<Vh4MBb` zPruyp0Pp_m8~ban3BE7!92=W;v@%hc738V1g=>cH>suo{13A3sjzr$`tI@pYz~enW zyd~^=(@0_OrdgVZ6C>Y80}%E##_zwqm6kSvNN0r)^?e|nv)z?_(wT~?$9*W7G`4pp z$0_?uJ;>V36F2}v$Ij%Re)_bbJ8~1w)bD=yrHY@zXX?yMfjKaC?2NCv8Fq{Odga2R zvQHUvi~M?JWf==^`Sr@mlG|_Wm_O!NnNa;VpBjE-;)aUjQSM`7$N#SD4^28dzv5Il z<^IG06+dOn#q#Twb^Vl&Kki$Rjhw%CCjJxqZ-py=9i?JfpY{u0UXjcG-PF1?^2phW zZT$CAD}Raa+h+f$xdat96J9O9)aH^-dl0VtGq5mHdW3{4ZHCssr*Ji!aOJIrO?5hi za3u&j7|%DrY9Mq|^JpNheKHXrqg9#EzB(%Et}><Ua8nwQYf6vDnNt5CGn#H^PB$8w z)4ULKIu~wEV-qdNtd=Fk`&rWa5tj7!cuQ*E#EK?nThU1`Yx=W|HF<_x)1WA8a?ZCQ zwWlpbHnF8EQMRNmw57l7?5K{59lbrmj*2_lQ*P^Obarqxnv`0N&J<Onj=deoJi~!Z z$2(BZbVurM=|ru)oT&G3XR1HRnZ`uA(j@ch<T|iA^%~<wgH<)?wp$H4)VKzHHmL?Z z8t6{_3f<}N01xsV=s`y&c#zt?CcQDPCbeqoN$YxeQuDr^R1{K+s`sr$y?fTCi5azN zecd{=(yI>b^R7dged^Hp(RJv$bzMr0uS;JyQPZ6yHGMcqO|3fDqgT4tqZaw~Xm>9! zn(t7b26)w{r>XU6tXl)B*T9>0cK4<w{k$n^h&S~s@TOh%jmRmp5t-UHCeOi*DRNX} z8f@EyuGMHlCH<Sw*z~6OxU>)XS^H41n-BSP^r3f(fT|hUcr_#6?#;-xMspg0wN?Tf z`%=IdU-~oHkB)};QPChjy3os?esBw*q__b3$}y0<BLneu@j!apG>Go|1<{+SLG(wh zV0wLgFfC~oN_T@oDJ?OS+BI!K?mjK(&z3Dn)x8C^H4mel(P6aQv?aY+qa}S&vnB0_ zYDG`_x1!Zit!Z9<Yw8f(hTiPohSCb!(4Nt4shxE@S~oTVJ@=8cB_@)3z0@8Hb$6gs zT{_TUvyQZKLPt87*onMab*2S{o#}!_7b*(sLKdN2Xijn$EcP8mv%;fj$A~EMjOj{& znC+4|svCXn9!>4~MAPX}(X{lXX!_hChK8wQXiIPmH5?p6ITK@OYI=8ClGmN4RqsLl zih9tgfw6SkycgB3){Ek5_o7=pdQt!UUS#DFN8=mDk=yV%`m;qmMGcR~m)#S{Br|~~ zj835SZoMh0Z*SV$uQyo_?@dj*_MySneW}#GFAeG1kJ=6FNBPzJQwPfdG_>vjd@X(e zEp9o0ipCG11wjL8SL7hF_83e7od;98Pa@UyOQe=LiIizJgi3vfkb1-r8f2G5Z#7P$ z2C8KGtL0F#9Wa#EJEYJ=*AxnkNugz#Ddd@xLJO=@>6Oe>%50HF??$E3YO7)NO@nlN zJwBa^QqyUJbp{o_lu4NbhSP`6Bj`?}5mc-32)fW2sUvCxZJRiPJ`T&Gr-QO+UrH7^ zjLD)l{v+wb<dNiGG?MB%WRqW9Hq9HIO{0QxXktzdy+OIO#v_*=w#%iqLvqQ_eH6u; z=g}6cJlY<WM}fWb$f-j<J?NEBozwE^cw7PbWEW6(&mwv!p@?#;kEW=g(bQ?wXmXq| znp)NzL)F`kr8W6usd=53XmGce=&<QH+CE_%J+T;1{oTf+>=;i8ea6#ns|hs8cLIIX zZ2~?RK9N=>O{Ct*6KP?GNt83DnAV$5rrnm4sj0(cx;kJoS%plYe+EyXA;YH7@3p7W zvVf^{BD92x(@N-^)yrg-@-l@Ny-c6hdIe?GG+H)(8WwS%PL?jy>3+;~+FLlCzOb4> zoodgdUEVXvqV-H#&}}B&$eBq!TxOBlYZmhJEUM9D7Fmp#Mb*d6qT4~QQL`4W(fVGm z(f1Qyqq70Csdw0Hs^vO|BKyoCyJ6S|%_Wn<xzyfl9xaKSM{%9!(Yzk>XnXDX^kvie zG;aKSn&SRCx!EtEH^LXt)R2XADS9ETuJs08YWW7ep7#cwv06;Ox-X`VEtb&mq9s%` z_$`X>vXs8dTuS#$-=@3)Z_}Tn-zImb<&@BIImHcIPIVIBr7x0JQ2gi>w8w2FW!70q zhoe@KSMVyb$XZ2CIjd0Ct)}DMSJSMCtLb*X_h{?D_sDDTdlXe?4Mhg5p#>e*Qp4=E zw6@m!q>6Z-KFWTdE<}Dn?FWBAN5*|XsevC-oi^)eRO~uh<+h$Od#$JW<{Rkab{lA9 z(gsS!m&ymZZKTn4H`2id8!5EaMtV46BPDd(MBDN8@}ahy>0{5$bi!*hSq<JoQ(A4M zzZ1980+($RU3(ji_u59*y|&RuW;^Jq(+&!(w}U46@1VlLJ7`$p4%#^AW7^T^6WSfM zlX3^_q%|?S=vLY;>eT5|N}sTsuBbkvTI$beVf<&*r}Z9Eb=*UDdhDTPL-)|Uls%Me zzL&y+_R^2xd&xOsKh=6^KP?&kIo;`ekm?ONNHZrKqS<DLX=10tG-~h>avy$#x;h@E zPH{)cW57`g9ek87q#vb+eZHUr?T%6BA;;*$q^~He#@Ey)@oReB|2SoY9j7ZzPf&sC z8@lN84ZR%p4Q&rPNi8i;k&n$ODv3Nr_PtKgsS&5>jkMD=!ukwN@Hs;do1dYr31_HU zpEI<!FZKh@(8!pxbTs)aMN~USIa%lEM)-M3@Vr1jg<YT%)i2VYkr&B++(jA~c!_3( zU80x6FHx)5OB51(nO3#EOb6OurlS6rX*@VJ{(JHXy+U)su278WRhndZl}voElH-u8 zG@$i0@*aMTZs*=0`@9?UMZpc)8GVyBrQf7uW<Ss+>mTU&fFG!L;E$Bk<R|iL`V%>3 z-=>B+x9OJoFQlsX3*|Tch0>jWrP(ciC98qIQ(VV8R66kv{TTZPnKZmh=0$hO+TtD! zwz)^6WA35;_>)!_{Yh3G|Dw`n_v!tR`}BwT18Q9VAvNs&kW>>MQlaZ3s@LQZ-Rk;? zQWGChlcA4jS?(iBcX&)+2RxxoVNa-O#uM@w_k=z(c}ge8KPB@XVke07%}-WwxK&&l zVOPw1-6nk}O?TzjMk=ZAbi{E&VTiAGM{r}B4O&uf%0|_jjkg6y<Cm|p5+!ZoQ~WfK zUW;8Z@?)0Vr4Fywtx{Q-nwy!cOwCH0(v`?Dv{y5af&`23TmogHai2!{q^2I&kH$U@ z_Ku`v*o=>OLk<RW%}rD$_@I=uWSr(3<D!F#c^6M(VP+^yX5lQzSFqjI!c4`RV0#Ax zwntJP>`xZVv=GfWn6m*>m{HNy(sdLexp)}|4Ym%#^O>-V%@Vb1E7)aeYOPY4tIUkr z)d6lR6wIXISMn`F3g(M#5K`7=DswA@l!~rAesUPfpSUeU81vR0epKT(6XB9V8IVTQ zyfmm(P1T0gMs3-;+FX-YELB+Y&eViAacbe5#`v<hu$c(TFozU}cs$&~;X7+!d{3fC zDZDJ;dH9{bMIw*#Wugeug%`U&8UDzFJ4WMfG&++s4+%TbcHI@}W)$K$i;D1D0C%K7 zMsw<ku*|~QD7YyNMp{d*sUY^s%0kRPbGkzs)7po`YKEBirK<yzXfJmG@m6Xgx;_D} z<#6Y;DTX&sGtk?lY{i$0`KPZCW9bA12O*x0l#Vn6S5D{j!Vh3WoG<_TpX0K)62-)7 z;yWE58_h(n#1~l7{3lc!cKS`Cws3VZsci9)Or#qjy_S=1VyO#UUI6!Vs3XS3a56K8 zmo3E9ex<YlwP)AxCQt30uf%-9=`UH3Lga<?6kzqLJKZ^<x?v^`zr26SrOWbJji%-L zICtqywGeF1weV${O+<BQ8j=J)ChgcCo>pGvE4+Q9qC4{76R*Dbty~DKw%BXA6^*K5 zat>CS@H&dv0=#|FC%Bz>^lZOk8N_Dn0;i7Rc(S@w`b5grWn@`JMesH2JEaaLRwl6V z2Dikqp^IjcwC7_9R$94$LNiXbnNUsPte(cS>=rp9WjSasaDO}_ZOb)jil^@Kb_tZ0 zN@Z#^>X=CCNL`VqxKxc5%CQ3EkQ9)GE8VeAMR}Bk5=o7`lZL#@<u<4O9PHIJOtViw z9o7M*VRH(?)dXB+3Hf-s0OzBT-#FLtovt7fPd39@N8HbcZJe)i@kAy}Wup}R&vaK8 zgcJKH55F85g>Y{w&e<o@okr!{(>EgzGnOHp7a<Jg=h7L66^CZ55atDlOIPXyQ&Hqc z{b&I0#L!hd^AbY-9?m)=p7Nl<B;%SDOhqC-)hLOh5C^fG9Lj9#aK!?Mg9&y}r0h`d z+F?yzJ0wdxl=F7DZwKAT4ifF~QDQqRb8APofdA}4HQ)doffH~BF2EI32X3GSa0ecs iCh!EcKy6S5)CFo#4|sw4paEzIyg?)IV*B450{<UvQI)>{ literal 0 HcmV?d00001 diff --git a/doc/RADIUS_ProtocolModule_Generator_CNL113600_PRI.doc b/doc/RADIUS_ProtocolModule_Generator_CNL113600_PRI.doc new file mode 100644 index 0000000000000000000000000000000000000000..a42e543928495b46652d2d21343c4860a539d652 GIT binary patch literal 84480 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®zk&ey`SnBNHz`1Ve*Mt+ zSp($f*AI<fc7Xi+`q4wxkMw}}#W&LrjUUGsyf4v_>f?yk-7n)YI?(S&8b7{%8VEnX zerWvk>k(|Ps(gO^(D=m#SU$ZxL$TF6>v?m4{QUZ%@#_;HKfiux{P1>LK<(kz4~^gT z0rK<fhsLjSfc$j*7>3CX+k?aCtG)hs_t3{zIzQ?|ApEEwoK13?pihnQ_}c6ARN7q4 z!pxT3lyS*<iY0Y?tdg0Nmg@`a#&nl?+}s1<mwZ(0<H6}D^_=D4918r>P1bz%yb$L< z>XaJ%^?Z@(7+z02=aeZS-Z&&CJ~74!rKjHy@#wsnye41pd>(5D%p(d&Go>h$S$zE9 zVR6O;)t@r57`4ahY%8m3uh!!*yFFfyt;`FrrgEoNmbl8QOUI4z`BA26HoUdaERKJI zsHG!+I+lUIsRz0o^t|BJ6t4en&YONg_dhHF-gLQczz&BO2|FLIkZ|3I7Xp_excb0O zjtayD3{GbCMGkhRU4Ux=Uc_AiuG_KGrefRxz)-;V?DcX|tN^`%UjluAzCb^qKQI6o z2=Hb%2)G5{LPHD?3-G4Oj+hrU6`VJrApmcdyaDs3ejcwNvU42?aF9S{9|hbB+y*28 z?4(8m$v_H_3ZwxX^ke{;!0iAPFALz{DhFU^N&aI&EdU2`dB8YeJTL*62yn2N4@?H8 z0O%8B8o)tmAz%ZF06X9SsL;hg2~Y}@0n>qUzy(wQm4F+l0%ianpc-J0Q3K2bW&yK- zTA&V?1Iz{H0rkLqpaEC_ECdz-i-9|UCBRZ(8L%9<6IcPTzAHiR237&9fi=KAz*>Oe z_kpeh)&utg4*<UbHUJxe2LZ<W&WEkObNUfM_tQ#%Z~pV$SOr&pC8$TeV$dk9bia_W z5WU2qNE6=9pr$;arKc)2Ipuuk_xKLi!|-YF`KCYvys8#7MZ2OO?ZwcPKg-dY#KRG3 z0y_{mBed2A4RooRr}<sUu_N*iL4t6gwfUP7cRCdmZUUt5f##=x+M&JtGK1~VT6ZJz zr^Lg6*5*&%Ms^}_Ve0n{708$G$<|)ty<{!!#f}57LjHG=QIy6l?0Yrm_ZF=$&v4}5 z2CP_jI*se)kM|;2>7vC6LC?=`U#iff7pXn%<<qtd?Si|fma}$j8GfmA_Srv_yPEv< zym{>g``zXe{QvqLg4Pdhujx<AzFWby;eT(JFYGEK5@QlDhf(xrSnAj?+sZI_sY=b? Vv3hvyaQSM)P7YFn?q?~1e*;LjH#q<R literal 0 HcmV?d00001 diff --git a/src/ATTR.awk b/src/ATTR.awk new file mode 100644 index 0000000..97756c7 --- /dev/null +++ b/src/ATTR.awk @@ -0,0 +1,388 @@ +#/****************************************************************************** +#* Copyright (c) 2008, 2015 Ericsson AB +#* All rights reserved. This program and the accompanying materials +#* are made available under the terms of the Eclipse Public License v1.0 +#* which accompanies this distribution, and is available at +#* http://www.eclipse.org/legal/epl-v10.html +#* +#* Contributors: +#* Timea Moder +#* Endre Kulcsar +#* Gabor Szalai +#* Janos Kovesdi +#* Kulcsár Endre +#* Zoltan Medve +#* Tamas Korosi +#******************************************************************************/ + +# # +# File: ATTR.awk # +# Description: RPMG AWK script for weaving RDF files # +# Rev: R12A +# Prodnr: CNL 113 600 # +############################################################################# + + + +BEGIN { + FS = "[ \t\n;]+" + HT = " " + + + # Number of attribute descriptors found in input RDF file + attrib_descriptors = 0 + packet_descriptors = 0 + # Number of attribute type definitions matching preceeding attribute descriptor + matching_attrib_types = 0 + matching_packet_types = 0 + # Identifier of generated TTCN-3 module + if(!module_id) module_id = "RADIUS_Types" + # Use APPLICATION-REVISION prefix in Attrib type identifiers when true + if(!use_application_revision) use_application_revision = 0 + # Replace all enumeration type Attribs with type Unsigned32 when true + if(!enum_2_UnsignedInt) enum_2_UnsignedInt = 0 + # Generate original structured TTCN-3 code when true + if(!old_structured_code) old_structured_code = 0 + + print "module " module_id " {" +} + +{ + # Remove excess WS from beginning and end of EACH record + sub(/^[ \t]+/, "") + sub(/[ \t]+$/, "") +} + +/\/\/ APPLICATION-NAME:/ { + # Will be used to prefix generated Attribute type definitions + application_id = $3 +} + +/\/\/ APPLICATION-REVISION:/ { + # Could be used as additional prefix for generated ATTR type definitions + application_revision = $3 + if(use_application_revision && application_revision) { + application_id = application_id "_" application_revision + } +} + +/\/\/ Packet-Type:/ { + # Packet descriptor line e.g.: + # // Packet: Official-Packet-Type (Official-Packet-Code) + # <-------- $3 ------> <------ $4 --------> + i = 1 + while ((packet_code[i] != $4) && (i <= packet_descriptors)) { + i++ + } + if (i > packet_descriptors) { + new_packet_type = $3 + new_packet_code = $4 + gsub(/-/, "_", new_packet_type) + + packet_descriptors++ + ++matching_packet_types + packet_code[packet_descriptors] = new_packet_code + packet_type[matching_packet_types] = new_packet_type} +} + + +/\/\/ Attrib:/ { + # Attrib descriptor line e.g.: + # // Attrib: Official-Attrib-Name (Official-Attrib-Code) + # <-------- $3 ------> <------ $4 --------> + + attrib_descriptors++ + new_attrib_name = $3 + new_attrib_code = $4 + gsub(/-/, "_", new_attrib_name) + attrib_desc[new_attrib_name]=new_attrib_name +} + +/\<type/ { + # TTCN-3 type definition e.g.: + # <type> <kind> <identifier> MUST be in same line! + if (($3 == new_attrib_name) && (new_attrib_code in ATTR)) + { + print "// WARNING: Duplicated Attrib definition removed by gawk script!" + if($2 == "enumerated") { f_ReadTotalEnum() } + ++deleted_attrib_types + next + } + else if($3 == new_attrib_name) { + $3 = application_id "_" new_attrib_name + ++matching_attrib_types + ATTR[new_attrib_code] = new_attrib_name + attrib_code[matching_attrib_types] = new_attrib_code + attrib_type[matching_attrib_types] = application_id "_" new_attrib_name + if($2 == "enumerated") { + f_ReadTotalEnum() + if(enum_2_UnsignedInt) { + print "// WARNING: Enumeration type Attrib replaced by UnsignedInteger!" + print "type UINT32 " application_id "_" new_attrib_name ";" + } + else{ + prettyprinted_enum = total_enum + gsub(/\,/, ",\n", prettyprinted_enum) + sub(/\{/, "{\n", prettyprinted_enum) + sub(/\}/, "\n}", prettyprinted_enum) + f_AddVariant_U32(prettyprinted_enum) + } + } else if ($2 ~ /^enum_[0-9]+$/) { + split($2, a, "_") + f_ReadTotalEnum() + if(enum_2_UnsignedInt) { + print "// WARNING: Enumeration type Attrib replaced by UnsignedInteger!" + print "type UINT" a[2] " " application_id "_" new_attrib_name ";" + } + else{ + prettyprinted_enum = total_enum + gsub(/\,/, ",\n", prettyprinted_enum) + sub(/\{/, "{\n", prettyprinted_enum) + sub(/\}/, "\n}", prettyprinted_enum) + gsub(/enum_[0-9]*/, "enumerated ", prettyprinted_enum) + f_AddVariant_U(prettyprinted_enum, a[2]) + } + } + } else if (($2 != "enumerated") && ($2 ~ /^enum_[0-9]+$/)) { + split($2, a, "_") + f_ReadTotalEnum() + if(enum_2_UnsignedInt) { + print "// WARNING: Enumeration type Attrib replaced by UnsignedInteger!" + print "type UINT" a[2] " " application_id "_" new_attrib_name ";" + } + else{ + prettyprinted_enum = total_enum + gsub(/\,/, ",\n", prettyprinted_enum) + sub(/\{/, "{\n", prettyprinted_enum) + sub(/\}/, "\n}", prettyprinted_enum) + gsub(/enum_[0-9]*/, "enumerated ", prettyprinted_enum) + f_AddVariant_U(prettyprinted_enum, a[2]) + } + } +} + +/\/\/ Vendor:/ { + # Vendor descriptor line e.g.: + # // Vendor: vendor_name (vendor_id) + # <-- $3 --> <-- $4 --> + + vendor_name = $3 + gsub(/-/, "_", vendor_name) + vendor_list[vendor_name]=$4 +} + +{print} + +END { + print "// STATISTICS: " attrib_descriptors " Attrib descriptors found" + print "// STATISTICS: " matching_attrib_types \ + " Attrib type definitions matching Attrib descriptors found" + print "// STATISTICS: " deleted_attrib_types " duplicate Attrib definitions deleted" + if(attrib_descriptors != matching_attrib_types + deleted_attrib_types) { + print "// ERROR: attrib_descriptors " attrib_descriptors \ + " != matching_attrib_types " matching_attrib_types + ss=1 + for(t in attrib_type){ + print ss " " attrib_type[t] + ss++ + } + + ss=1 + print "\n" + for(t in attrib_desc){ + print ss " " attrib_desc[t] + ss++ + } + + exit(1) + } + + + + print "\n" + + print "type record Attrib_UNKNOWN" + print "{" + print HT "UINT8 attrib_type," + print HT "UINT8 attrib_length," + print HT "octetstring attrib_value" + print "} with {" + print HT " variant (attrib_length) \"LENGTHTO(attrib_type, attrib_length, attrib_value)\"" + print HT "}" + print "\n" + + print "type record vendor_specific_type" + print "{" + print HT "vendor_id_enum vendor_id," + print HT "string_val_spec attrib_value" + print "} with {" + print HT " variant (attrib_value) \"CROSSTAG(" + for(vendor in vendor_list){ + printf (HT HT "f_%s_subattr_list, vendor_id=%s;\n",vendor, vendor) + } + print HT ")\"" + print "}" + print "\n" + + print "type enumerated vendor_id_enum" + print "{" + i=1 + for(vendor in vendor_list){ + if(i==1){ + printf (HT "%s %s",vendor, vendor_list[vendor]) + i++ + } else { + printf (",\n" HT "%s %s",vendor, vendor_list[vendor]) + } + } + print "\n" "} with {" + print HT "variant \"FIELDLENGTH(32)\"" + print HT "variant \"BYTEORDER(last)\"" + print "}" + print "\n" + + print "type union string_val_spec" + print "{" + i=1 + for(vendor in vendor_list){ + if(i==1){ + printf (HT "%s_subattr_list f_%s_subattr_list",vendor, vendor) + i++ + } else { + printf (",\n" HT "%s_subattr_list f_%s_subattr_list",vendor, vendor) + } + } + print "\n}" + + if(old_structured_code){ + for(i = 1; i <= matching_attrib_types; i++) { + printf("type record Attrib_%s\n", attrib_type[i]) + print "{" + print HT "Attrib attrib_type," + print HT "UINT8 attrib_length," + printf(HT "%s %s\n", attrib_type[i], tolower(attrib_type[i])) + print "} with {" + printf(HT " variant \"PRESENCE (attrib_type=%s)\"\n",attrib_type[i]) + printf(HT " variant (attrib_length) \"LENGTHTO(attrib_type, attrib_length, %s)\"\n", + tolower(attrib_type[i])) + print HT "}" + print "\n" + } + + print "type set of GenericAttrib Attribs;\n" + + print "type union GenericAttrib" + print "{" + for(i = 1; i <= matching_attrib_types; i++) { + printf(HT "Attrib_%s attrib_%s,\n", + attrib_type[i],attrib_type[i]) + } + print HT "Attrib_UNKNOWN attrib_UNKNOWN" + print "}\n" + } + else{ + print "\n" + print "type union Attrib_Data" + print "{" + for(i = 1; i <= matching_attrib_types; i++) { + printf(HT "%s %s,\n", attrib_type[i], tolower(attrib_type[i])) + } + print HT "octetstring attrib_UNKNOWN" + print "}\n" + + print "type set of GenAttrib Attribs;\n" + print "type union GenAttrib" + print "{" + print HT "GenericAttrib genericAttrib," + print HT "Attrib_UNKNOWN attrib_UNKNOWN" + print "}\n" + print "type record GenericAttrib" + print "{" + print HT "Attrib attrib_type," + print HT "UINT8 attrib_length," + print HT "Attrib_Data attrib_data" + print "} with {" + print HT " variant (attrib_length) \"LENGTHTO(attrib_type, attrib_length, attrib_data)\"" + print HT " variant (attrib_data) \"CROSSTAG(" + for(i = 1; i <= matching_attrib_types; i++) { + printf(HT HT "%s,attrib_type=%s;\n", tolower(attrib_type[i]),attrib_type[i]) + } + print HT HT "attrib_UNKNOWN, OTHERWISE" + print HT ")\"" + print "}" + print "\n" + } + + print "type enumerated Attrib" + print HT "{" + for(i = 1; i <= matching_attrib_types; i++) { + printf(HT "%s %s%s\n", + attrib_type[i], attrib_code[i], + (i < matching_attrib_types) ? "," : "") + } + print "} with {" + print HT "variant \"FIELDLENGTH(8)\"" + print HT "variant \"BYTEORDER(last)\"" + print HT "}\n" + + + print "type enumerated Code" + print HT "{" + for(i = 1; i <= packet_descriptors; i++) { + printf(HT "%s %s%s\n", + packet_type[i], packet_code[i], + (i < packet_descriptors) ? "," : "") + } + print "} with {" + print HT "variant \"FIELDLENGTH(8)\"" + print HT "variant \"BYTEORDER(last)\"" + print HT "}\n" + + + print "type record PDU_RADIUS" + print "{" + print HT "Code code," + print HT "UINT8 identifier," + print HT "UINT16 message_length," + print HT "OCTET16 authenticator," + print HT "Attribs attributes" + print "} with {" + print HT " variant (message_length) \"LENGTHTO(code, identifier, message_length, authenticator, attributes)\"" + print HT"}\n" + + + print "} with { encode \"RAW\" } // End module" + + +} + +function f_AddVariant_U32(prefix) +{ + print prefix, "with {" + print HT "variant \"FIELDLENGTH(32)\"" + print HT "variant \"BYTEORDER(last)\"" + print "}" +} + +function f_AddVariant_U(prefix,flength) +{ + print prefix, "with {" + printf(HT "variant \"FIELDLENGTH(%s)\"\n",flength) + print HT "variant \"BYTEORDER(last)\"" + print "}" +} + +function f_ReadTotalEnum() +{ + total_enum = $0 + while(total_enum !~ /\}/) { + getline + sub(/\/\/.*/, "") + total_enum = total_enum $0 + } + # Replace $0 contents with data following } + idx = index(total_enum, "}") + $0 = substr(total_enum, idx+1) + total_enum = substr(total_enum, 1, idx) +} + diff --git a/src/ATTR.sh b/src/ATTR.sh new file mode 100644 index 0000000..0e245ee --- /dev/null +++ b/src/ATTR.sh @@ -0,0 +1,107 @@ +#!/bin/sh +#set -x +#/****************************************************************************** +#* Copyright (c) 2008, 2015 Ericsson AB +#* All rights reserved. This program and the accompanying materials +#* are made available under the terms of the Eclipse Public License v1.0 +#* which accompanies this distribution, and is available at +#* http://www.eclipse.org/legal/epl-v10.html +#* +#* Contributors: +#* Timea Moder +#* Endre Kulcsar +#* Gabor Szalai +#* Janos Kovesdi +#* Kulcsár Endre +#* Zoltan Medve +#* Tamas Korosi +#******************************************************************************/ + + +# ATTR.sh [OPTION] ... RDF-FILEs +# {-v <variable-name>=<value>} {RDF-files} + +ATTRSCRIPT="ATTR.awk" +TTCN3FILE="RADIUS_Types" + +if [ $# -lt 1 ]; then + echo "ERROR: Too few arguments" + echo "Usage: $0 [-vNAME=VALUE] ... RDF-FILEs" + echo "Where: -v sets variable NAME to VALUE" + echo "" + echo "Supported variables:" + echo " module_id ................ Name of generated TTCN-3 module" + echo " use_application_revision . Use revision prefix in ATTR identifier" + echo " enum_2_UnsignedInt ....... Replace enumeration ATTRs with UnsignedInteger" + echo " old_structured_code....... Generate original structured TTCN-3 code" + exit 1 +fi + + # check gawk version + FIRSTLINE=`gawk --version|head -1` + PRODUCT=`echo ${FIRSTLINE} | gawk '{ print $1 $2 }'` + VERSION=`echo ${FIRSTLINE} | gawk '{ print $3 }'` + if [ ${PRODUCT} != "GNUAwk" ]; then + echo "ERROR: GNU Awk required" + exit 1 + fi + RESULT=`echo ${VERSION} | gawk '{ print ($0 < "3.1.6") }'` + if [ ${RESULT} != 0 ]; then + echo "ERROR: GNU Awk version >3.1.6 required (${VERSION} found)" + exit 1 + fi + +# Process arguments + +AWKARGS=$@ +while [ $# -ge 1 ]; do + case $1 in + -v) + shift; + case $1 in + module_id=*) + TTCN3FILE=`echo $1 | sed 's/module_id=//'` + if [ -f "RADIUS_EncDec.cc" ]; then + cmd="s/#include \"RADIUS_Types.hh\"/#include \"${TTCN3FILE}.hh\"/ + s/namespace RADIUS__Types/namespace ${TTCN3FILE}/ + s/RADIUS_EncDec/${TTCN3FILE}_RADIUS_EncDec/g" + cat "RADIUS_EncDec.cc" \ + | sed "${cmd}" > ${TTCN3FILE}"_RADIUS_EncDec.cc" + else + echo "ERROR: Missing RADIUS_EncDec.cc file" + exit 1 + fi + ;; + use_application_revision=*) + ;; + enum_2_UnsignedInt=*) + ;; + old_structured_code=*) + ;; + *) echo "ERROR: Unknown variable $1!"; exit 1;; + esac + ;; + *) + # end of options + if [ $# -lt 1 ]; then + echo "ERROR: No input RDF file" + exit 1 + fi + # check gawk existence + which gawk > /dev/null 2> /dev/null + if [ ! $? ]; then + echo "ERROR: GNU awk can not be found" + exit 1 + fi + # check input awk script + if [ -f ${ATTRSCRIPT} ]; then + gawk -f ${ATTRSCRIPT} ${AWKARGS} > ${TTCN3FILE}".ttcn" + else + echo "ERROR: ATTR.awk not found" + exit 1 + fi + break + ;; + esac + shift +done diff --git a/src/Accounting_IETF_RFC2866_RFC2867.rdf b/src/Accounting_IETF_RFC2866_RFC2867.rdf new file mode 100644 index 0000000..adf5f1a --- /dev/null +++ b/src/Accounting_IETF_RFC2866_RFC2867.rdf @@ -0,0 +1,129 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Accounting_IETF_RFC2866_RFC2867.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2866(RADIUS Accounting) +// RFC 2867(RADIUS Accounting Modifications for Tunnel Protocol Support) +// +// +// + + +// APPLICATION-NAME: Acc +// APPLICATION-REVISION: RFC2866RFC2867 + +// Packet-Type: Accounting_Request (4) + +// Packet-Type: Accounting_Response (5) + + +// RFC 2866 and RFC 2867 +// Attrib: Acct-Status-Type (40) +type enumerated Acct_Status_Type +{ + Start (1), + Stop (2), + Interim_Update (3), + Accounting_On (7), + Accounting_Off (8), + Tunnel_Start (9), + Tunnel_Stop (10), + Tunnel_Reject (11), + Tunnel_Link_Start (12), + Tunnel_Link_Stop (13), + Tunnel_Link_Reject (14) +} + +// RFC 2866 +// Attrib: Acct-Delay-Type (41) +type Attrib_Value Acct_Delay_Type; + +// RFC 2866 +// Attrib: Acct-Input-Octets (42) +type Attrib_Value Acct_Input_Octets; + +// RFC 2866 +// Attrib: Acct-Output-Octets (43) +type Attrib_Value Acct_Output_Octets; + +// RFC 2866 +// Attrib: Acct-Session-Id (44) +type Attrib_Text Acct_Session_Id; + +// RFC 2866 +// Attrib: Acct-Authentic (45) +type enumerated Acct_Authentic +{ + RADIUS (1), + Local (2), + Remote (3) +} + +// RFC 2866 +// Attrib: Acct-Session-Time (46) +type Attrib_Value Acct_Session_Time; + +// RFC 2866 +// Attrib: Acct-Input-Packets (47) +type Attrib_Value Acct_Input_Packets; + +// RFC 2866 +// Attrib: Acct-Output-Packets (48) +type Attrib_Value Acct_Output_Packets; + +// RFC 2866 +// Attrib: Acct-Terminate-Cause (49) +type enumerated Acct_Terminate_Cause +{ + User_Request (1), + Lost_Carrier (2), + Lost_Service (3), + Idle_Timeout (4), + Session_Timeout (5), + Admin_Reset (6), + Admin_Reboot (7), + Port_Error (8), + NAS_Error (9), + NAS_Request (10), + NAS_Reboot (11), + Port_Unneeded (12), + Port_Preempted (13), + Port_Suspended (14), + Service_Unavailable (15), + Callback (16), + User_Error (17), + Host_Request (18) +} + +// RFC 2866 +// Attrib: Acct-Multi-Session-Id (50) +type Attrib_String Acct_Multi_Session_Id; + +// RFC 2866 +// Attrib: Acct-Link-Count (51) +type Attrib_Value Acct_Link_Count; + +// RFC 2867 +// Attrib: Acct-Tunnel-Connection (68) +type Attrib_String Acct_Tunnel_Connection; + +// RFC 2867 +// Attrib: Acct-Tunnel-Packets-Lost (86) +type Attrib_Value Acct_Tunnel_Packets_Lost; diff --git a/src/BaseTypes_IETF_RFC2865.rdf b/src/BaseTypes_IETF_RFC2865.rdf new file mode 100644 index 0000000..8886d79 --- /dev/null +++ b/src/BaseTypes_IETF_RFC2865.rdf @@ -0,0 +1,137 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: BaseTypes_IETF_RFC2865.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2865(RADIUS) +// +// +// + + +// +// External functions for encoding and decoding +// + +external function f_RADIUS_Enc(in PDU_RADIUS pdu) return octetstring; +external function f_RADIUS_Dec(in octetstring stream) return PDU_RADIUS; + +external function f_calc_MD5(in octetstring input) return octetstring; +external function f_crypt_password(in octetstring P,in octetstring req_auth,in octetstring salt,in boolean decrypt,in charstring secret) return octetstring; +external function f_crypt_s_key(in octetstring s_key,in octetstring req_auth,in charstring secret, in boolean decrypt)return octetstring; +external function f_crypt_tunnel_password(in octetstring tunnel_password,in octetstring req_auth,in octetstring salt,in charstring secret, in boolean decrypt)return octetstring; + +external function f_salt_value(inout vendor_specific_value pdu, in octetstring req_auth, in charstring secret, in boolean decrypt) return boolean; +external function f_convert_string_to_text(inout vendor_specific_value pdu) return boolean; +// +// Basic type definitions +// + +type integer UINT8 (0..255) with { +variant "FIELDLENGTH(8)" +variant "BYTEORDER(last)" +} + +type integer UINT16 (0..65535) with { +variant "FIELDLENGTH(16)" +variant "BYTEORDER(last)" +} + +type integer UINT24 (0..16777215) with { +variant "FIELDLENGTH(24)" +variant "BYTEORDER(last)" +} + +type integer UINT32 (0..4294967296) with { +variant "FIELDLENGTH(32)" +variant "BYTEORDER(last)" +} + +type integer UINT64 with { +variant "FIELDLENGTH(64)" +variant "BYTEORDER(last)" +} + +type integer INT32 with { +variant "FIELDLENGTH(32)" +variant "BYTEORDER(last)" +variant "COMP(2scompl)" +} + +type octetstring OCTET1 length(1) +type octetstring OCTET2 length(2) +type octetstring OCTET3 length(3) +type octetstring OCTET4 length(4) +type octetstring OCTET8 length(8) +type octetstring OCTET16 length(16) + +// +// Basic Attribute Data Formats +// + +type charstring Attrib_Text length(1..253) with { variant "PADDING(yes)"}; +type octetstring Attrib_String length(1..253); +type OCTET4 Attrib_Address; +type OCTET4 Attrib_Time; +type UINT32 Attrib_Value; + +// +// Basic vendor specific value types +// + +type union vendor_specific_value{ + octetstring string_val, + charstring text_val, + UINT32 integer_val, + UINT64 integer64_val, + unsalted_value_integer_t unsalted_integer, + unsalted_value_text_t unsalted_text, + unsalted_value_string_t unsalted_string, + tagged_value_integer_t tagged_integer, + tagged_value_text_t tagged_text, + tagged_value_string_t tagged_string +} + +type record unsalted_value_integer_t{ + octetstring salt length(2), + UINT32 unsalted_value +} +type record unsalted_value_text_t{ + octetstring salt length(2), + charstring unsalted_value +} +type record unsalted_value_string_t{ + octetstring salt length(2), + octetstring unsalted_value +} + +type record tagged_value_integer_t{ + octetstring tag length(1), + UINT32 untagged_value +} +type record tagged_value_string_t{ + octetstring tag length(1), + octetstring untagged_value +} +type record tagged_value_text_t{ + octetstring tag length(1), + charstring untagged_value +} + + diff --git a/src/Base_IETF_RFC2865.rdf b/src/Base_IETF_RFC2865.rdf new file mode 100644 index 0000000..17f010f --- /dev/null +++ b/src/Base_IETF_RFC2865.rdf @@ -0,0 +1,305 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Base_IETF_RFC2865.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2865(RADIUS) +// +// +// + + +// APPLICATION-NAME: Base +// APPLICATION-REVISION: RFC2865 + + + +// Packet-Type: Access-Request (1) + +// Packet-Type: Access_Accept (2) + +// Packet-Type: Access_Reject (3) + +// Packet-Type: Accounting_Request (4) + +// Packet-Type: Accounting_Response (5) + +// Packet-Type: Access_Challenge (11) + +// Packet-Type: Status_Server (12) + +// Packet-Type: Status_Client (13) + +// Packet-Type: Reserved (255) + + + + +// RFC 2865 +// Attrib: User-Name (1) +type Attrib_String User_Name; + +// RFC 2865 +// Attrib: User-Password (2) +type Attrib_String User_Password; + +// RFC 2865 +// Attrib: CHAP-Password (3) +type record CHAP_Password +{ + UINT8 CHAP_Ident, + Attrib_String String length(16) +} + +// RFC 2865 +// Attrib: NAS-IP-Address (4) +type Attrib_Address NAS_IP_Address; + +// RFC 2865 +// Attrib: NAS-Port (5) +type Attrib_Value NAS_Port; + +// RFC 2865 +// Attrib: Service-Type (6) +type enumerated Service_Type +{ + Login (1), + Framed (2), + Callback_Login (3), + Callback_Framed (4), + Outbound (5), + Administrative (6), + NAS_Prompt (7), + Authenticate_Only (8), + Callback_NAS_Prompt (9), + Call_Check (10), + Callback_Administrative (11), + Authorize_Only (17) +} + + +// RFC 2865 +// Attrib: Framed-Protocol (7) +type enumerated Framed_Protocol +{ + PPP (1), + SLIP (2), + Appletalk_Remote_Access_Protocol (3), + Gandalf_proprietary_protocol (4), + Xylogics_proprietary (5), + Xpoint75_Syncronous (6), + GPRS_PDP_Context (7) +} + + +// RFC 2865 +// Attrib: Framed-IP-Address (8) +type Attrib_Address Framed_IP_Address; + +// RFC 2865 +// Attrib: Framed-IP-Netmask (9) +type Attrib_Address Framed_IP_Netmask; + +// RFC 2865 +// Attrib: Framed-Routing (10) +type enumerated Framed_Routing +{ + None (0), + Send_routing_pacets (1), + Listen_for_routing_pacets (2), + Send_and_Listen (3) +} + +// RFC 2865 +// Attrib: Filter-Id (11) +type Attrib_Text Filter_Id; + +// RFC 2865 +// Attrib: Framed-MTU (12) +type Attrib_Value Framed_MTU (64..65535); + +// RFC 2865 +// Attrib: Framed-Compression (13) +type enumerated Framed_Compression +{ + None (0), + VJ_TCP_IP_header_compression (1), + IPX_header_compression (2), + STAC_LZS_compression (3) +} + +// RFC 2865 +// Attrib: Login-IP-Host (14) +type Attrib_Address Login_IP_Host; + +// RFC 2865 +// Attrib: Login-Service (15) +type enumerated Login_Service +{ + Telnet (0), + Rlogin (1), + TCP_Clear (2), + Port_Master (3), + LAT (4), + X25_PAD (5), + X25_T3POS (6), + TCP_Clear_Quiet (7) +} + +// RFC 2865 +// Attrib: Login-TCP-Port (16) +type Attrib_Value Login_TCP_Port (0..65535); + +// RFC 2865 +// Attrib: Reply-Message (18) +type Attrib_Text Reply_Message; + +// RFC 2865 +// Attrib: Callback-Number (19) +type Attrib_String Callback_Number; + +// RFC 2865 +// Attrib: Callback-Id (20) +type Attrib_String Callback_Id; + +// RFC 2865 +// Attrib: Framed-Route (22) +type Attrib_Text Framed_Route; + +// RFC 2865 +// Attrib: Framed-IPX-Network (23) +type Attrib_Value Framed_IPX_Network; + +// RFC 2865 +// Attrib: State (24) +type Attrib_String State; + +// RFC 2865 +// Attrib: Class (25) +type Attrib_String Class; + + +// RFC 2865 +// Attrib: Session-Timeout (27) +type Attrib_Value Session_Timeout; + +// RFC 2865 +// Attrib: Idle-Timeout (28) +type Attrib_Value Idle_Timeout; + +// RFC 2865 +// Attrib: Termination-Action (29) +type enumerated Termination_Action +{ + Default (0), + RADIUS_Request (1) +} + +// RFC 2865 +// Attrib: Called-Station-Id (30) +type Attrib_String Called_Station_Id; + +// RFC 2865 +// Attrib: Calling-Station-Id (31) +type Attrib_String Calling_Station_Id; + +// RFC 2865 +// Attrib: NAS-Identifier (32) +type Attrib_String NAS_Identifier; + +// RFC 2865 +// Attrib: Proxy-State (33) +type Attrib_String Proxy_State; + +// RFC 2865 +// Attrib: Login-LAT-Service (34) +type Attrib_String Login_LAT_Service; + +// RFC 2865 +// Attrib: Login-LAT-Node (35) +type Attrib_String Login_LAT_Node; + +// RFC 2865 +// Attrib: Login-LAT-Group (36) +type Attrib_String Login_LAT_Group; + +// RFC 2865 +// Attrib: Framed-AppleTalk-Link (37) +type Attrib_Value Framed_AppleTalk_Link (0..65535); + +// RFC 2865 +// Attrib: Framed-AppleTalk-Network (38) +type Attrib_Value Framed_AppleTalk_Network (0..65535); + +// RFC 2865 +// Attrib: Framed-AppleTalk-Zone (39) +type Attrib_String Framed_AppleTalk_Zone; + +// RFC 2865 +// Attrib: CHAP-Challenge (60) +type Attrib_String CHAP_Challenge; + +// RFC 2865 +// Attrib: NAS-Port-Type (61) +type enumerated NAS_Port_Type +{ + Async (0), + Sync (1), + ISDN_Sync (2), + ISDN_Async_v120 (3), + ISDN_Async_v110 (4), + Virtual (5), + PIAFS (6), + HDLC_Clear_Channel (7), + X25 (8), + X75 (9), + G3_Fax (10), + SDSL_Symmetric_DSL (11), + ADSL_CAP_Asymmetric_DSL (12), + ADSL_DMT_Asymmetric_DSL (13), + ISDL_ISDN_Digital_Subscriber_Line (14), + Ethernet (15), + xDSL (16), + Cable (17), + Wireless_Other (18), + Wireless_IEEE_80211 (19) +} + + +// RFC 2865 +// Attrib: Port-Limit (62) +type Attrib_Value Port_Limit; + +// RFC 2865 +// Attrib: Login-LAT-Port (63) +type Attrib_String Login_LAT_Port; + + + +// RFC 2865 +// Attrib: Vendor-Specific (26) +type vendor_specific_type Vendor_Specific + + + + + + + + diff --git a/src/ChargeableUserIdentity_IETF_RFC4372.rdf b/src/ChargeableUserIdentity_IETF_RFC4372.rdf new file mode 100644 index 0000000..508f625 --- /dev/null +++ b/src/ChargeableUserIdentity_IETF_RFC4372.rdf @@ -0,0 +1,32 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: ChargeableUserIdentity_IETF_RFC4372.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 4372(Chargeable User Identity) +// +// + + +// APPLICATION-NAME: CUI +// APPLICATION-REVISION: RFC4372 + +// RFC 4372 +// Attrib: CUI (89) +type Attrib_String CUI; diff --git a/src/Cisco.rdf b/src/Cisco.rdf new file mode 100644 index 0000000..b5e14db --- /dev/null +++ b/src/Cisco.rdf @@ -0,0 +1,133 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Cisco.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: cisco (9) + +type record cisco_type +{ + cisco_type_enum f_cisco_type, + UINT8 attrib_length_spec, + vendor_specific_value string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_cisco_type, attrib_length_spec, string_val)" + variant (string_val) "CROSSTAG( + integer_val, {f_cisco_type=multilink_id, + f_cisco_type=num_in_multilink, + f_cisco_type=pre_input_octets, + f_cisco_type=pre_output_octets, + f_cisco_type=pre_input_packets, + f_cisco_type=pre_output_packets, + f_cisco_type=maximum_time, + f_cisco_type=disconnect_cause, + f_cisco_type=date_rate, + f_cisco_type=presession_time, + f_cisco_type=pw_limetime, + f_cisco_type=ip_direct, + f_cisco_type=ppp_vj_slot_comp, + f_cisco_type=ppp_async_map, + f_cisco_type=ip_pool_definition, + f_cisco_type=asing_ip_pool, + f_cisco_type=route_ip, + f_cisco_type=link_compression, + f_cisco_type=target_util, + f_cisco_type=maximum_channels, + f_cisco_type=data_filter, + f_cisco_type=call_filter, + f_cisco_type=idle_limit, + f_cisco_type=xmit_rate + }; + unsalted_string, f_cisco_type=li_configuration; + string_val, OTHERWISE + )" +} + +type set of cisco_type cisco_subattr_list; + +type enum_8 cisco_type_enum +{ + cisco_avpair (1),//cisco_access_control_list + cisco_nas_port (2), + h323_remote_address (23), + h323_conf_id (24), + h323_setup_time (25), + h323_call_orign (26), + h323_call_type (27), + h323_connect_time (28), + h323_disconnect_time (29), + h323_disconnect_cause (30), + h323_voice_quality (31), + h323_ivr_out (32), + h323_gw_id (33), + h323_call_treatment (34), + h323_incoming_conf_id (35), + li_configuration (36), + policy_up (37), + policy_down (38),//sub_policy_out + vpnpassword (66), + vpngroupinfo (67), + h323_ivr_in (100), + h323_credit_amount (101), + h323_credit_time (102), + h323_return_code (103), + h323_prompt_id (104), + h323_time_and_day (105), + h323_redirect_number (106), + h323_preferred_lang (107), + h323_redirect_ip_addr (108), + h323_billing_model (109), + h323_currency_type (110), + multilink_id (187), + num_in_multilink (188), + pre_input_octets (190), + pre_output_octets (191), + pre_input_packets (192), + pre_output_packets (193), + maximum_time (194), + disconnect_cause (195), + date_rate (197), + presession_time (198), + pw_limetime (208), + ip_direct (209), + ppp_vj_slot_comp (210), + ppp_async_map (212), + ip_pool_definition (217), + asing_ip_pool (218), + route_ip (228), + link_compression (233), + target_util (234), + maximum_channels (235), + data_filter (242), + call_filter (243), + idle_limit (244), + account_info (250),//cisco_info_service,cisco_account_info + service_info (251),//cisco_service_list,ssg_service_info + command_code (252),//cisco_n_service_info + control_info (253), //cisco_byte_count,ssg_control_info + xmit_rate (255) +} + + + + diff --git a/src/DynamicAuthorizationExtensions_IETF_RFC5176.rdf b/src/DynamicAuthorizationExtensions_IETF_RFC5176.rdf new file mode 100644 index 0000000..8bc7010 --- /dev/null +++ b/src/DynamicAuthorizationExtensions_IETF_RFC5176.rdf @@ -0,0 +1,66 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: DynamicAuthorizationExtensions_IETF_RFC5176.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 5176(RADIUS Authorization Extensions) +// Obsoletes: RFC 3576 +// +// + + +// APPLICATION-NAME: AuthExt +// APPLICATION-REVISION: RFC5176 + + +// Packet-Type: Disconnect-Request (40) + +// Packet-Type: Disconnect-ACK (41) + +// Packet-Type: Disconnect-NAK (42) + +// Packet-Type: CoA-Request (43) + +// Packet-Type: CoA-ACK (44) + +// Packet-Type: CoA-NAK (45) + + +// RFC 5176 +// Attrib: Error-Cause (101) +type enumerated Error_Cause +{ + Residual_Session_Context_Removed (201), + Invalid_EAP_Packet (202), + Unsupported_Attribute (401), + Missing_Attribute (402), + NAS_Identification_Mismatch (403), + Invalid_Request (404), + Unsupported_Service (405), + Unsupported_Extension (406), + Invalid_Attribute_Value (407), + Administratively_Prohibited (501), + Request_Not_Routable_Proxy (502), + Session_Context_Not_Found (503), + Session_Context_Not_Removable (504), + Other_Proxy_Processing_Error (505), + Resources_Unavailable (506), + Request_Initiated (507), + Multiple_Session_Selection_Unsupported (508) +} diff --git a/src/Extensions_IETF_RFC2869.rdf b/src/Extensions_IETF_RFC2869.rdf new file mode 100644 index 0000000..355e7fe --- /dev/null +++ b/src/Extensions_IETF_RFC2869.rdf @@ -0,0 +1,125 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Extensions_IETF_RFC2869.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2869(RADIUS Extensions) +// +// +// + + +// APPLICATION-NAME: Ext +// APPLICATION-REVISION: RFC2869 + +// RFC 2869 +// Attrib: Acct-Input-Gigawords (52) +type Attrib_Value Acct_Input_Gigawords; + +// RFC 2869 +// Attrib: Acct-Output-Gigawords (53) +type Attrib_Value Acct_Output_Gigawords; + +// RFC 2869 +// Attrib: Event-Timestamp (55) +type Attrib_Value Event_Timestamp; + +// RFC 2869 +// Attrib: ARAP-Password (70) +type record ARAP_Password +{ + Attrib_Value Value1, + Attrib_Value Value2, + Attrib_Value Value3, + Attrib_Value Value4 +} + +// RFC 2869 +// Attrib: ARAP-Features (71) +type record ARAP_Features +{ + UINT8 variable_password, + UINT8 password_length, + Attrib_Time creation_time, + Attrib_Value expiration_time, + Attrib_Time radius_time +} + +// RFC 2869 +// Attrib: ARAP-Zone-Access (72) +type enumerated ARAP_Zone_Access +{ + To_default_zone (1), + Use_zone_filter_inclusively (2), + Use_zone_filter_exclusively (3) +} + +// RFC 2869 +// Attrib: ARAP-Security (73) +type Attrib_Value ARAP_Security; + +// RFC 2869 +// Attrib: ARAP-Security-Data (74) +type Attrib_String ARAP_Security_Data; + +// RFC 2869 +// Attrib: Password-Retry (75) +type Attrib_Value Password_Retry; + +// RFC 2869 +// Attrib: Prompt (76) +type enumerated Prompt +{ + No_Echo (0), + Echo (1) +} + +// RFC 2869 +// Attrib: Connect-Info (77) +type Attrib_Text Connect_Info; + +// RFC 2869 +// Attrib: Configuration-Token (78) +type Attrib_String Configuration_Token; + +// RFC 2869 +// Attrib: EAP-Message (79) +type Attrib_String EAP_Message; + +// RFC 2869 +// Attrib: Message-Authenticator (80) +type Attrib_String Message_Authenticator; + +// RFC 2869 +// Attrib: ARAP-Challenge-Response (84) +type UINT64 ARAP_Challenge_Response; + +// RFC 2869 +// Attrib: Acct-Interim-Interval (85) +type Attrib_Value Acct_Interim_Interval; + +// RFC 2869 +// Attrib: NAS-Port-Id (87) +type Attrib_Text NAS_Port_Id; + +// RFC 2869 +// Attrib: Framed-Pool (88) +type Attrib_String Framed_Pool; + + diff --git a/src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf b/src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf new file mode 100644 index 0000000..a7e6c85 --- /dev/null +++ b/src/GGSN_FS_46_15517_CSA113_35_4RevB.rdf @@ -0,0 +1,55 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: GGSN_FS_46_15517_CSA113_4RevB.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: GGSN Functional Specification: RADIUS +// 46/155 17-CSA 113 35/4 Uen Rev B +// +// + + +// APPLICATION-NAME: Ggsn +// APPLICATION-REVISION: VB + +// Attrib: Imsi (224) +type Attrib_Text Imsi; + +// Attrib: Charging-Id (225) +type Attrib_Value Charging_Id; + +// Attrib: Imsi-Mcc-Mnc (226) +type Attrib_Text Imsi_Mcc_Mnc; + +// Attrib: Sgsn-IP-Address (228) +type Attrib_Address Sgsn_IP_Address; + +// Attrib: Selection-Mode (229) +type Attrib_Text Selection_Mode; + +// Attrib: Ggsn-Gtp-IP-Address (230) +type Attrib_Address Ggsn_Gtp_IP_Address; + +// Attrib: Primary-Dns-Server (135) +type Attrib_Address Primary_Dns_Server; + +// Attrib: Secondary-Dns-Server (136) +type Attrib_Address Secondary_Dns_Server; + + diff --git a/src/IPv6_IETF_RFC3162.rdf b/src/IPv6_IETF_RFC3162.rdf new file mode 100644 index 0000000..393b958 --- /dev/null +++ b/src/IPv6_IETF_RFC3162.rdf @@ -0,0 +1,64 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: IPv6_IETF_RFC3162.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 3162(RADIUS and IPv6) +// +// +// + + +// APPLICATION-NAME: IPv6 +// APPLICATION-REVISION: RFC3162 + +// RFC 3162 +// Attrib: NAS-IPv6-Address (95) +type OCTET16 NAS_IPv6_Address; + +// RFC 3162 +// Attrib: Framed-Interface-Id (96) +type OCTET8 Framed_Interface_Id; + +// RFC 3162 +// Attrib: Framed-IPv6-Prefix (97) +type record Framed_IPv6_Prefix +{ + OCTET1 reserved, + UINT8 prefix_length, + bitstring prefixValue, + bitstring prefixPadding +} with { + variant (prefix_length) "LENGTHTO(prefixValue)"; + variant (prefix_length) "UNIT(bits)"; + variant (prefixValue) "BYTEORDER(last)"; + variant "FIELDORDER(msb)"; + } + +// RFC 3162 +// Attrib: Login-IPv6-Host (98) +type OCTET16 Login_IPv6_Host; + +// RFC 3162 +// Attrib: Framed-IPv6-Route (99) +type Attrib_Text Framed_IPv6_Route; + +// RFC 3162 +// Attrib: Framed-IPv6-Pool (100) +type Attrib_String Framed_IPv6_Pool; diff --git a/src/Juniper.rdf b/src/Juniper.rdf new file mode 100644 index 0000000..e4e3e9c --- /dev/null +++ b/src/Juniper.rdf @@ -0,0 +1,185 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Juniper.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: juniper (4874) + +type record juniper_type +{ + juniper_type_enum f_juniper_type, + UINT8 attrib_length_spec, + vendor_specific_value string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_juniper_type, attrib_length_spec, string_val)" + variant (string_val) "CROSSTAG( + unsalted_string, {f_juniper_type=li_action, + f_juniper_type=med_port_number, + f_juniper_type=med_dev_handle, + f_juniper_type=med_ip_address + }; + integer_val, { f_juniper_type=ingress_statistics, + f_juniper_type=egress_statistics, + f_juniper_type=service_category, + f_juniper_type=pcr, + f_juniper_type=scr_or_cbr_bit_rate, + f_juniper_type=mbs, + f_juniper_type=allow_all_vr_access, + f_juniper_type=sa_validate, + f_juniper_type=lgmp_enable, + f_juniper_type=pppoe_max_sessions, + f_juniper_type=qos_profile_interface_type, + f_juniper_type=tunnel_nas_port_method, + f_juniper_type=tunnel_tos, + f_juniper_type=tunnel_max_sessions, + f_juniper_type=framed_ip_route_tag, + f_juniper_type=ppp_protocol, + f_juniper_type=tunnel_min_bps, + f_juniper_type=tunnel_max_bps, + f_juniper_type=tunnel_bearer_type, + f_juniper_type=input_gigapackets, + f_juniper_type=output_gigapackets, + f_juniper_type=df_bit, + f_juniper_type=mld_version, + f_juniper_type=igmp_version, + f_juniper_type=ip_mcast_adm_bw_limit, + f_juniper_type=ip6_mcast_adm_bw_limit, + f_juniper_type=igmp_query_interval, + f_juniper_type=igmp_max_resp_time, + f_juniper_type=igmp_immediate_leave, + f_juniper_type=mld_query_interval, + f_juniper_type=mld_max_resp_time, + f_juniper_type=mld_immediate_leave, + f_juniper_type=service_interim_acct_interval, + f_juniper_type=downstream_calculated_qos_rate, + f_juniper_type=upstream_calculated_qos_rate + }; + tagged_integer, {f_juniper_type=juniper_service_volume, + f_juniper_type=juniper_service_timeout, + f_juniper_type=juniper_service_stats + }; + tagged_text, f_juniper_type=juniper_service_activate; + + string_val, OTHERWISE + )" +} + +type set of juniper_type juniper_subattr_list; + +type enum_8 juniper_type_enum +{ + virtual_router (1), + local_address_pool (2), + local_interface (3), + primary_dns (4), + secondary_dns (5), + primary_wins (6), + secondary_wins (7), + tunnel_virtual_router (8), + tunnel_password (9), + ingress_policy_name (10), + egress_policy_name (11), + ingress_statistics (12), + egress_statistics (13), + service_category (14), + pcr (15), + scr_or_cbr_bit_rate (16), + mbs (17), + init_cli_access_level (18), + allow_all_vr_access (19), + alt_cli_access_level (20), + alt_cli_vrouter_name (21), + sa_validate (22), + lgmp_enable (23), + pppoe_description (24), + redirect_vr_name (25), + qos_profile_name (26), + pppoe_max_sessions (27), + pppoe_url (28), + qos_profile_interface_type (29), + tunnel_nas_port_method (30), + service_bundle (31), + tunnel_tos (32), + tunnel_max_sessions (33), + framed_ip_route_tag (34), + tunnel_dialout_number (35), + ppp_username (36), + ppp_password (37), + ppp_protocol (38), + tunnel_min_bps (39), + tunnel_max_bps (40), + tunnel_bearer_type (41), + input_gigapackets (42), + output_gigapackets (43), + tunnel_interface_id (44), + ipv6_virtual_router (45), + ipv6_local_interfaces (46), + ipv6_primary_dns (47), + ipv6_secondary_dns (48), + sdx_service_name (49), + sdx_session_volume_quota (50), + disconnect_cause (51), + radius_client_address (52), + service_description (53), + dhcp_options (55), + dhcp_mac_addr (56), + dhcp_gi_address (57), + li_action (58), + med_dev_handle (59), + med_ip_address (60), + med_port_number (61), + mlppp_bundle_name (62), + interface_desc (63), + tunnel_group (64), + juniper_service_activate (65), + juniper_service_deactivate (66), + juniper_service_volume (67), + juniper_service_timeout (68), + juniper_service_stats (69), + df_bit (70), + igmp_access_name (71), + igmp_access_src_name (72), + igmp_oif_map_name (73), + mld_access_name (74), + mld_access_src_name (75), + mld_oif_map_name (76), + mld_version (77), + igmp_version (78), + ip_mcast_adm_bw_limit (79), + ip6_mcast_adm_bw_limit (80), + qos_parameters (82), + service_session (83), + igmp_query_interval (95), + igmp_max_resp_time (96), + igmp_immediate_leave (97), + mld_query_interval (98), + mld_max_resp_time (99), + mld_immediate_leave (100), + service_interim_acct_interval (140), + downstream_calculated_qos_rate (141), + upstream_calculated_qos_rate (142) +} + + + + diff --git a/src/RADIUS_EncDec.cc b/src/RADIUS_EncDec.cc new file mode 100644 index 0000000..009202e --- /dev/null +++ b/src/RADIUS_EncDec.cc @@ -0,0 +1,299 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RADIUS_EncDec.cc +// Description: Encoder/Decoder and external functions for RPMG +// Rev: R12A +// Prodnr: CNL 113 600 +// Reference: RFC 2865(RADIUS), 2866(RADIUS Accounting), +// +// +// + +#include "RADIUS_Types.hh" + +#include <openssl/md5.h> + +namespace RADIUS__Types{ + + +// calculates 16 bit MD5 message digest +OCTETSTRING f__calc__MD5(const OCTETSTRING& input) + { + unsigned char output[16]; + MD5(input,(size_t) input.lengthof(),output); //error check! + OCTETSTRING MD5_Value(16,output); + + return MD5_Value; + } + +// copied from Radius Test Port ( secret CHARSTRING -> OCTETSTRING +OCTETSTRING f__crypt__password (const OCTETSTRING& P, const OCTETSTRING& req__auth, const OCTETSTRING& salt,const BOOLEAN& decrypt, const CHARSTRING& secret) { + + const unsigned char* P_p = (const unsigned char*)P; + int P_num = P.lengthof() / 16; + + if (P.lengthof() % 16 != 0) + TTCN_warning("Length of P should be multiple of 16"); + + unsigned char b[16]; + + const OCTETSTRING& SRA = char2oct(secret) + req__auth + salt; + + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("SRA: "); + SRA.log(); + TTCN_Logger::end_event(); + + MD5((const unsigned char*)SRA, SRA.lengthof(), b); + + unsigned char* C = new unsigned char [P_num * 16]; // output buffer + + for (int j = 0; j < 16; j++) { + C[j] = P_p[j] ^ b[j]; + } + + unsigned int S_len = secret.lengthof(); + + unsigned char* Sc = new unsigned char[S_len + 16]; + memcpy(Sc, (const unsigned char*)(const char*)secret, S_len); + + for (int i = 1; i < P_num; i++) { + if (decrypt) + memcpy(Sc + S_len, P_p + (i-1)*16, 16); + else + memcpy(Sc + S_len, C + (i-1)*16, 16); + + MD5(Sc, S_len + 16, b); + for (int j = 0; j < 16; j++) { + C[(i*16 + j)] = P_p[(i*16 +j)] ^ b[j]; + } + } + + OCTETSTRING result = OCTETSTRING(P_num*16, (const unsigned char*)C); + delete [] C; + delete [] Sc; + + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("Result of hashing: "); + result.log(); + TTCN_Logger::end_event(); + + return result; + +} // crypt_password + +OCTETSTRING f__crypt__s__key(const OCTETSTRING& pl_s_key, const OCTETSTRING& pl_req_auth, const CHARSTRING& secret,const BOOLEAN& decrypt) +{ + if (decrypt) + { + const OCTETSTRING& salt = substr(pl_s_key, 0, 2); + const OCTETSTRING& decrypted = f__crypt__password(substr(pl_s_key, 2, pl_s_key.lengthof() - 2),pl_req_auth, salt, true, secret); + int key_len = *((const unsigned char*)decrypted); // first byte + if (key_len > decrypted.lengthof() - 1) { + TTCN_warning("Invalid key length in \'S\' key."); + key_len = decrypted.lengthof() - 1; + } + const OCTETSTRING& key_length_and_key = substr(decrypted, 0, key_len + 1); + OCTETSTRING result = salt + key_length_and_key; + return result; + } // decrypt_s_key + else + { + if (pl_s_key.lengthof() < 3) + TTCN_warning("string_val in \'S\' key must be at least 3 octets long."); + const OCTETSTRING& salt = OCTETSTRING(2, (const unsigned char*)pl_s_key); + const int key_len = *((const unsigned char*)pl_s_key + 2); + const OCTETSTRING& key = OCTETSTRING(pl_s_key.lengthof() - 3, (const unsigned char*)pl_s_key + 3); + int calc_key_len; + if (key_len == 0) + calc_key_len = key.lengthof(); + else { + if (key_len != key.lengthof()) + TTCN_warning("Invalid key length in \'S\' key."); + calc_key_len = key_len; + } + int padding_len = (16 - ((key.lengthof() + 1) % 16)) % 16; // +1 for the key length + const OCTETSTRING& P = int2oct(calc_key_len, 1) + key + OCTETSTRING(padding_len, (const unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + OCTETSTRING result = salt + f__crypt__password(P, pl_req_auth, salt, false, secret); + return result; + } +} // crypt_s_key + +OCTETSTRING f__crypt__tunnel__password(const OCTETSTRING& pl_password, const OCTETSTRING& req_auth, const OCTETSTRING& salt, const CHARSTRING& secret,const BOOLEAN& decrypt) { + if (decrypt) + { + const OCTETSTRING& plain = f__crypt__password(pl_password, req_auth, salt, true, secret); + OCTETSTRING password; + password = OCTETSTRING(plain.lengthof(), (const unsigned char*)plain + 1); + return password; + } + else + { + int data_len=pl_password.lengthof(); + // the following line pads P to be multiple of 16 octets + const OCTETSTRING& P = int2oct(data_len, 1) + pl_password + OCTETSTRING( + (16-((pl_password.lengthof() + 1) % 16)) % 16, (const unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + return f__crypt__password(P, req_auth, salt, false, secret); + } +} // encrypt_tunnel_password + + +OCTETSTRING f__RADIUS__Enc(const PDU__RADIUS& pdu) +{ + PDU__RADIUS* par=NULL; + + TTCN_Buffer buf; + TTCN_EncDec::error_type_t err; + buf.clear(); + TTCN_EncDec::clear_error(); + TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); + if(par) + par->encode(PDU__RADIUS_descr_, buf, TTCN_EncDec::CT_RAW); + else + pdu.encode(PDU__RADIUS_descr_, buf, TTCN_EncDec::CT_RAW); + err = TTCN_EncDec::get_last_error_type(); + if(err != TTCN_EncDec::ET_NONE) + TTCN_warning("Encoding error: %s\n", TTCN_EncDec::get_error_str()); + delete par; + return OCTETSTRING(buf.get_len(), buf.get_data()); +} + +PDU__RADIUS f__RADIUS__Dec(const OCTETSTRING& stream) +{ + PDU__RADIUS pdu; + TTCN_Buffer buf; + TTCN_EncDec::error_type_t err; + TTCN_EncDec::clear_error(); + buf.clear(); + buf.put_os(stream); + TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); + pdu.decode(PDU__RADIUS_descr_, buf, TTCN_EncDec::CT_RAW); + err = TTCN_EncDec::get_last_error_type(); + if(err != TTCN_EncDec::ET_NONE) + TTCN_warning("Decoding error: %s\n", TTCN_EncDec::get_error_str()); + return pdu; +} + +BOOLEAN f__salt__value(vendor__specific__value& pdu, const OCTETSTRING& req_auth, const CHARSTRING& secret, const BOOLEAN& decrypt){ + OCTETSTRING salt; + OCTETSTRING key; + switch(pdu.get_selection()){ + case vendor__specific__value::ALT_unsalted__integer: + { + salt = pdu.unsalted__integer().salt(); + key = int2oct(pdu.unsalted__integer().unsalted__value(),4); + break; + } + case vendor__specific__value::ALT_unsalted__text: + { + salt = pdu.unsalted__text().salt(); + key = char2oct(pdu.unsalted__text().unsalted__value()); + break; + } + case vendor__specific__value::ALT_unsalted__string: + { + salt = pdu.unsalted__string().salt(); + key = pdu.unsalted__string().unsalted__value(); + break; + } + case vendor__specific__value::ALT_string__val: + { + salt =OCTETSTRING(0, (const unsigned char*)"\0"); + key = pdu.string__val(); + break; + } + default: + return false; + } + OCTETSTRING string_val; + if(decrypt){ + string_val = f__crypt__password (key,req_auth , salt, decrypt, secret); + int key_len = *((const unsigned char*)string_val); // first byte + + if (key_len > string_val.lengthof() - 1) { + TTCN_warning("Invalid key length"); + key_len = string_val.lengthof() - 1; + } + string_val = substr(string_val, 1, key_len); + } else { + const int key_len = key.lengthof(); + int padding_len = (16 - ((key_len + 1) % 16)) % 16; // +1 for the key length + const OCTETSTRING& P = int2oct(key.lengthof(), 1) + key + OCTETSTRING(padding_len, (const unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + string_val = f__crypt__password (P,req_auth , salt, decrypt, secret); + + } + + if(salt.lengthof()!=0){ + pdu.unsalted__string().salt()=salt; + pdu.unsalted__string().unsalted__value()=string_val; + } else { + pdu.string__val()=string_val; + } + return true; +} + +bool f_convert_string_to_text(const OCTETSTRING& in, CHARSTRING& out){ + const unsigned char * key_ptr = (const unsigned char *)in; + for (int i = 0; i<(in.lengthof());i++){ + if (key_ptr[i] & 0x80) { + return false; + } + } + out = oct2char(in); + return true; + +} + +BOOLEAN f__convert__string__to__text(vendor__specific__value& pdu){ + CHARSTRING chr; + switch(pdu.get_selection()){ + case vendor__specific__value::ALT_string__val: + { + if(f_convert_string_to_text( pdu.string__val(),chr)){ + pdu.text__val()=chr; + } else { return false; } + break; + } + case vendor__specific__value::ALT_unsalted__string: + { + if(f_convert_string_to_text( pdu.unsalted__string().unsalted__value(),chr)){ + OCTETSTRING salt=pdu.unsalted__string().salt(); + pdu.unsalted__text().unsalted__value()=chr; + pdu.unsalted__text().salt()=salt; + } else { return false; } + break; + } + case vendor__specific__value::ALT_tagged__string: + { + if(f_convert_string_to_text( pdu.tagged__string().untagged__value(),chr)){ + OCTETSTRING tag=pdu.tagged__string().tag(); + pdu.tagged__text().untagged__value()=chr; + pdu.tagged__text().tag()=tag; + } else { return false; } + break; + } + default: + return false; + } + return true; +} + + +} +TTCN_Module RADIUS_EncDec("RADIUS_EncDec", __DATE__, __TIME__); diff --git a/src/Scap.rdf b/src/Scap.rdf new file mode 100644 index 0000000..55ede9f --- /dev/null +++ b/src/Scap.rdf @@ -0,0 +1,161 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Scap.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: scap (10923) + + +type enum_8 scap_type_enum +{ + requested_service_unit (1), + used_service_unit (2), + granted_service_unit (3), + unit_type (4), + unit_value (5), + value_digits (6), + exponent (7), + currency_code (8), + subscription_id (9), + additional_subscription_id (10), + subscription_id_type (11), + subscription_id_data (12), + event_timestamp (13), + accounting_record_number (14), + result_code (15), + accounting_interim_interval (16), + origin_state_id (17), + suggested_primary_rulespace (30), + suggested_secondary_rulespace (31), + access_control_group_id (33), + authorization_code (34), + mobile_assisted_service_classification (35) +} + + +type enum_8 scap_unit_type_enum { + SERVICE_CREDIT_TIME (0), + SERVICE_CREDIT_VOLUME (1), + SERVICE_CREDIT_EVENT (2), + SERVICE_CREDIT_MONEY (3) +} + + +type enum_8 scap_subsription_id_type_enum { + END_USER_MSISDN (0), + END_USER_IMSI (1), + END_USER_SIP_URL (2), + END_USER_NAI (3), + END_USER_PRIVATE (4) +} + +type record scap_unit_type_t { + scap_type_enum scap_type, + UINT8 scap_length, + INT32 scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)" +} + +type set of scap_unit_type_t unit_value_list; + +type union unit_value_t +{ + octetstring string_val, + scap_unit_type_enum unit_type_val, + scap_subsription_id_type_enum subsription_id_type_val, + unit_value_list unit_type_list, + INT32 integer_val, + charstring unichar_val +} + + +type record service_unit_t { + scap_type_enum scap_type, + UINT8 scap_length, + unit_value_t scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)"; + variant (scap_val) "CROSSTAG( + unit_type_val, scap_type=unit_type; + unit_type_list, scap_type=unit_value; + integer_val, scap_type=value_digits; + integer_val, scap_type=exponent; + integer_val, scap_type=currency_code; + unit_type_list, scap_type=subscription_id; + integer_val, scap_type=additional_subscription_id; + subsription_id_type_val, scap_type=subscription_id_type; + unichar_val, scap_type=subscription_id_data; + integer_val, scap_type=event_timestamp; + integer_val, scap_type=accounting_record_number; + integer_val, scap_type=result_code; + integer_val, scap_type=accounting_interim_interval; + integer_val, scap_type=origin_state_id)" + } + + +type set of service_unit_t service_unit_list; + + +type union scap_value { + octetstring string_val, + scap_unit_type_enum unit_type_val, + unit_value_list unit_type_list, + service_unit_list f_service_unit_list, + scap_subsription_id_type_enum subscription_id_type_val, + INT32 integer_val, + charstring unichar_val, + charstring charstring_val +} + + +type record scap_subattr_t { + scap_type_enum scap_type, + UINT8 scap_length, + scap_value scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)"; + variant (scap_val) "CROSSTAG( + f_service_unit_list, scap_type=requested_service_unit; + f_service_unit_list, scap_type=used_service_unit; + f_service_unit_list, scap_type=granted_service_unit; + unit_type_val, scap_type=unit_type; + unit_type_list, scap_type=unit_value; + integer_val, scap_type=value_digits; + integer_val, scap_type=exponent; + integer_val, scap_type=currency_code; + f_service_unit_list, scap_type=subscription_id; + integer_val, scap_type=additional_subscription_id; + subscription_id_type_val, scap_type=subscription_id_type; + unichar_val, scap_type=subscription_id_data; + integer_val, scap_type=event_timestamp; + integer_val, scap_type=accounting_record_number; + integer_val, scap_type=result_code; + integer_val, scap_type=accounting_interim_interval; + integer_val, scap_type=origin_state_id; + charstring_val, scap_type=suggested_primary_rulespace; + charstring_val, scap_type=suggested_secondary_rulespace)" + } + +type set of scap_subattr_t scap_subattr_list; + diff --git a/src/Smartedge.rdf b/src/Smartedge.rdf new file mode 100644 index 0000000..70b9489 --- /dev/null +++ b/src/Smartedge.rdf @@ -0,0 +1,138 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Smartedge.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: smartedge (2352) + +type record smartedge_type +{ + smartedge_type_enum f_smartedge_type, + UINT8 attrib_length_spec, + vendor_specific_value string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_smartedge_type, attrib_length_spec, string_val)" + variant (string_val) "CROSSTAG( + integer_val, { f_smartedge_type=rb_medium_type, + f_smartedge_type=rb_nas_real_port, + f_smartedge_type=rb_platform_type, + f_smartedge_type=rb_service_error_cause, + f_smartedge_type=rb_mcast_maxgroups, + f_smartedge_type=rb_mcast_send, + f_smartedge_type=rb_mcast_receive, + f_smartedge_type=rb_acct_reason, + f_smartedge_type=rb_acct_mcast_in_packets, + f_smartedge_type=rb_acct_mcast_out_packets, + f_smartedge_type=rb_session_error_code, + f_smartedge_type=rb_acct_mcast_in_octets, + f_smartedge_type=rb_acct_mcast_out_octets, + f_smartedge_type=rb_dhcp_max_leases, + f_smartedge_type=rb_offload_indication, + f_smartedge_type=rb_vcpe_id + }; + integer64_val, { f_smartedge_type=rb_acct_input_octets_64, + f_smartedge_type=rb_acct_output_octets_64, + f_smartedge_type=rb_acct_input_packets_64, + f_smartedge_type=rb_acct_output_packets_64, + f_smartedge_type=rb_acct_mcast_in_octets_64, + f_smartedge_type=rb_acct_mcast_out_octets_64, + f_smartedge_type=rb_acct_mcast_in_packets_64, + f_smartedge_type=rb_acct_mcast_out_packets_64 + }; + tagged_integer, f_smartedge_type=rb_service_options; + tagged_text, { f_smartedge_type=rb_deactivate_service_name, + f_smartedge_type=rb_service_name, + f_smartedge_type=rb_service_parameter}; + + string_val, OTHERWISE + )" +} + +type set of smartedge_type smartedge_subattr_list; + +type enum_8 smartedge_type_enum +{ + rb_dhcp_max_leases (3), + rb_context_name (4), + rb_mcast_send (33), + rb_mcast_receive (34), + rb_mcast_maxgroups (35), + rb_medium_type (38), + rb_nas_real_port (62), + rb_pppoe_ip_route_add (71), + rb_qos_policing_profile_name (87), + rb_qos_metering_profile_name (88), + rb_qos_queuing_profile_name (89), + rb_igmp_service_profile_name (90), + rb_forward_policy (92), + rb_agent_remote_id (96), + rb_agent_circuit_id (97), + rb_platform_type (98), + rb_atm_profile_name (101), + rb_nat_profile_name (105), + rb_http_redirect_profile_name (107), + rb_os_version (112), + rb_session_traffic_limit (113), + + rb_acct_input_octets_64 (128), + rb_acct_output_octets_64 (129), + rb_acct_input_packets_64 (130), + rb_acct_output_packets_64 (131), + rb_assigned_ip_address (132), + rb_acct_mcast_in_octets_64 (133), + rb_acct_mcast_out_octets_64 (134), + rb_acct_mcast_in_packets_64 (135), + rb_acct_mcast_out_packets_64 (136), + + rb_session_error_code (142), + rb_session_msg (143), + + rb_acct_reason (144), + rb_mac_address (145), + rb_acct_mcast_in_octets (147), + rb_acct_mcast_out_octets (148), + rb_acct_mcast_in_packets (149), + rb_acct_mcast_out_packets (150), + + rb_qos_rate_inbound (156), + rb_qos_rate_outbound (157), + rb_http_redirect_url (165), + rb_service_name (190), + rb_service_options (191), + rb_service_parameter (192), + rb_service_error_cause (193), + rb_deactivate_service_name (194), + rb_dynamic_qos_param (196), + rb_reauth_service_name (204), + rb_ipv6_dns (207), + rb_ipv6_profile (209), + + rb_offload_indication (224), + rb_gtp_tunnel_data (225), + + rb_vcpe_id (232), + rb_vcpe_profile (233), + rb_vcpe_transport_policy (234), + rb_vcpe_device_policy (235), + rb_vcpe_mac_ip_pair (236) +} diff --git a/src/TunnelAuthentication_IETF_RFC2868.rdf b/src/TunnelAuthentication_IETF_RFC2868.rdf new file mode 100644 index 0000000..748bdcf --- /dev/null +++ b/src/TunnelAuthentication_IETF_RFC2868.rdf @@ -0,0 +1,166 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: TunnelAuthenticationIETF_RFC2868.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2868(RADIUS Attributes for Tunnel Protocol Support) +// +// +// + + +// APPLICATION-NAME: Auth +// APPLICATION-REVISION: RFC2868 + + +type enum_24 Tunnel_Type_Value +{ + PPTP (1), + L2F (2), + L2TP (3), + ATMP (4), + VTP (5), + AH (6), + IP_IP (7), + MIN_IP_IP (8), + ESP (9), + GRE (10), + DVS (11), + IP_IP_Tunneling (12) +} + +// RFC 2868 +// Attrib: Tunnel-Type (64) +type record Tunnel_Type +{ + OCTET1 Tag, + Tunnel_Type_Value Value +} + + +type enum_24 Tunnel_Medium_Type_Value +{ + IPv4 (1), + IPv6 (2), + NSAP (3), + HDLC (4), + BBN_1822 (5), + media_plus_Ethernet_802 (6), + Epoint163 (7), + Epoint164 (8), + Fpoint69 (9), + Xpoint121 (10), + IPX (11), + Appletalk (12), + Decnet_IV (13), + Banyan_Vines (14), + Epoint164_with_NSAP_subaddress (15) +} + + +// RFC 2868 +// Attrib: Tunnel-Medium-Type (65) +type record Tunnel_Medium_Type +{ + OCTET1 Tag, + Tunnel_Medium_Type_Value Value +} + + +// RFC 2868 +// Attrib: Tunnel-Client-Endpoint (66) +type record Tunnel_Client_Endpoint +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Server-Endpoint (67) +type record Tunnel_Server_Endpoint +{ + OCTET1 Tag, + Attrib_String String +} + +type union Tunnel_Password_String{ + Tunnel_Password_String_Encrypted encrypted_passwd, + Tunnel_Password_String_Plaintext plain_text_passwd +} + +type octetstring Tunnel_Password_String_Encrypted + +type record Tunnel_Password_String_Plaintext +{ + UINT8 Data_Length, + Attrib_String Password, + octetstring Padding_Sub_Field +} with { + variant (Data_Length) "LENGTHTO(Password)" +} + +// RFC 2868 +// Attrib: Tunnel-Password (69) +type record Tunnel_Password +{ + OCTET1 Tag, + OCTET2 Salt, + Tunnel_Password_String String +} + +// RFC 2868 +// Attrib: Tunnel-Private-Group-ID (81) +type record Tunnel_Private_Group_ID +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Assignment-ID (82) +type record Tunnel_Assignment_ID +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Preference (83) +type record Tunnel_Preference +{ + OCTET1 Tag, + UINT24 Value +} + +// RFC 2868 +// Attrib: Tunnel-Client-Auth-ID (90) +type record Tunnel_Client_Auth_ID +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Server-Auth-ID (91) +type record Tunnel_Server_Auth_ID +{ + OCTET1 Tag, + Attrib_String String +} + diff --git a/src/Vendor.rdf b/src/Vendor.rdf new file mode 100644 index 0000000..925e80c --- /dev/null +++ b/src/Vendor.rdf @@ -0,0 +1,326 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Vendor.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: ericsson (193) + +type enum_8 ericsson_type_enum +{ + product_profile (1), + digest_response (14), + digest_attributes (15), + pmk (17), + layer_identity (34), + major_protocol_version (35), + minor_protocol_version (36), + ipt_timestamp (126), + master_session_id (200), + message_from_sn (202), + requested_url (203), + authorization_result_code (204), + cds_uid (205), + msisdn (206), + authentication_type (207), + timestamp_created (208), + timestamp_used (209), + access_type (210), + requested_service_id (211), + user_alias (212), + service_session_id (213) +} + +type record ericsson_type +{ + ericsson_type_enum f_ericsson_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_ericsson_type, attrib_length_spec, string_val)" + } + +type set of ericsson_type ericsson_subattr_list; + +// Vendor: acc (5) +type enum_8 acc_type_enum +{ + acc_error_message (1), + acc_ccp_option (2), + acc_customer_id (6), + acc_tunnel_secret (14), + acc_service_profile (17), + acc_request_type (18), + acc_dns_server_pri (23), + acc_dns_server_sec (24), + acc_nbns_server_pri (25), + acc_nbns_server_sec (26), + acc_dial_port_index (27), + acc_mn_ha_shared_secret (73), + acc_mip_spi (74) +} + +type record acc_type +{ + acc_type_enum f_acc_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_acc_type, attrib_length_spec, string_val)" + } + +type set of acc_type acc_subattr_list; + +// Vendor: microsoft (311) + +type enum_8 microsoft_type_enum +{ + microsoft_chap_mppe_keys (12), + microsoft_mppe_send_key (16), + microsoft_mppe_recv_key (17), + microsoft_primary_dns_server (28), + microsoft_secondary_dns_server (29), + microsoft_primary_nbns_server (30), + microsoft_secondary_nbns_server (31) +} + +type record microsoft_type +{ + microsoft_type_enum f_microsoft_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_microsoft_type, attrib_length_spec, string_val)" + } + +type set of microsoft_type microsoft_subattr_list; + +// Vendor: cdma2000 (5535) + +type enum_8 cdma2000_type_enum +{ + ike_pre_shared_secret_request (1), + security_level (2), + pre_shared_secret (3), + reverse_tunnel_specification (4), + differentiated_services_class (5), + container (6), + home_agent (7), + key_id (8), + pcf_ip_addr (9), + bs_msc_addr (10), + userid (11), + forward_mux (12), + reverse_mux (13), + forward_fundamental_rate (14), + reverse_fundamental_rate (15), + service_option (16), + forward_traffic_type (17), + reverse_traffic_type (18), + fundamental_frame_size (19), + forward_fundamental_rc (20), + reverse_fundamental_rc (21), + ip_technology (22), + compulsory_tunnel_indicator (23), + release_indicator (24), + bad_frame_count (25), + num_active (30), + sdb_input_octects (31), + sdb_output_octects (32), + numsdb_input (33), + numsdb_output (34), + ip_QoS (36), + air_QoS (39), + airlink_record_type (40), + rp_session_id (41), + airlink_secuence_number (42), + num_bytes_received_total (43), + + correlation_id (44), + mo_mt_indicator (45), + mobile_ip_sig_inbound_count (46), + mobile_ip_sig_outbound_count (47), + session_cont (48), + active_time (49), + dcch_frame_format (50), + ESN (52), + s_key (54), + s_request (55), + s_lifetime (56), + mn_ha_shared_secret_request (57), + mn_ha_shared_secret (58), + remote_ipv4_address (59), + hrpd_access_authentication (60), + + remote_ipv6_address (70), + remote_address_table_index (71), + remote_address_octet_count (72), + always_on (78), + last_user_activity_time (80), + + session_termination_capability (88), + prepaid_accounting_quota (90), + prepaid_accounting_capability (91), + mip_rrq_lifetime (92), + service_reference_id (94), + disconnect_reason (96), + cdma2000_error_cause (255) // WARNING: temporary type number, not yet standardized 2003-06-17 tmptso +} + +type record cdma2000_type +{ + cdma2000_type_enum f_cdma2000_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_cdma2000_type, attrib_length_spec,string_val)" + } + +type set of cdma2000_type cdma2000_subattr_list; + +// Vendor: threegpp (10415) + +type enum_8 threegpp_type_enum +{ + threegpp_imsi (1), + threegpp_charging_id (2), + threegpp_pdp_type (3), + threegpp_charging_gateway_address (4), + threegpp_gprs_negotiated_qos_profile (5), + threegpp_sgsn_ip_address (6), + threegpp_ggsn_ip_address (7), + threegpp_imsi_mcc_mnc (8), + threegpp_ggsn_mcc_mnc (9), + threegpp_nsapi (10), + threegpp_session_stop_indicator (11), + threegpp_selection_mode (12), + threegpp_charging_characteristics (13), + threegpp_cg_ipv6_address (14), + threegpp_sgsn_ipv6_address (15), + threegpp_ggsn_ipv6_address (16), + threegpp_ipv6_dns_servers (17), + threegpp_sgsn_mcc_mnc (18), + threegpp_teardown_indicator (19), + threegpp_imeisv (20), + threegpp_rat_type (21), + threegpp_user_location_info (22), + threegpp_ms_timezone (23), + threegpp_camel_charging_info (24), + threegpp_packet_filter (25), + threegpp_negotiated_dscp (26), + threegpp_allocate_ip_type (27), + threegpp_chargeable_user_identity (89) // FIXME no standard reference available ETIBSZA +} + + +type record threegpp_type +{ + threegpp_type_enum f_threegpp_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_threegpp_type, attrib_length_spec, string_val)" + } + +type set of threegpp_type threegpp_subattr_list; + +// Vendor: servicefactory (5556) + +type enum_8 servicefactory_type_enum +{ + servicefactory_product_profile_id (1), + servicefactory_access_point_id (7), + servicefactory_apn (14) // FIXME no standard reference available ETIBSZA +} + +type record servicefactory_type +{ + servicefactory_type_enum f_servicefactory_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_servicefactory_type, attrib_length_spec, string_val)" + } + +type set of servicefactory_type servicefactory_subattr_list; + +// Vendor: adslforum (3561) + +type enum_8 adslforum_type_enum +{ + adslforum_agent_circuit_id (1) +} + + +type record adslforum_type +{ + adslforum_type_enum f_adslforum_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_adslforum_type, attrib_length_spec, string_val)" + } + +type set of adslforum_type adslforum_subattr_list; + +// Vendor: wispr (14122) +type enum_8 wispr_type_enum +{ + wispr_location_id (1), + wispr_location_name(2) +} + + +type record wispr_type +{ + wispr_type_enum f_wispr_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_wispr_type, attrib_length_spec, string_val)" + } + +type set of wispr_type wispr_subattr_list; + + +// Vendor: chinatel (20942) + +type enum_8 chinatel_type_enum +{ + chinatel_served_mdn (100) +} + + +type record chinatel_type +{ + chinatel_type_enum f_chinatel_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_chinatel_type, attrib_length_spec, string_val)" + } + +type set of chinatel_type chinatel_subattr_list; + + + + diff --git a/src/Vendor_detailed_ericsson.rdf b/src/Vendor_detailed_ericsson.rdf new file mode 100644 index 0000000..d7b033f --- /dev/null +++ b/src/Vendor_detailed_ericsson.rdf @@ -0,0 +1,334 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: Vendor_detailed_ericcson.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: ericsson (193) + + +type enum_8 ericsson_type_enum +{ + product_profile (1), + digest_response (14), + digest_attributes (15), + pmk (17), + layer_identity (34), + major_protocol_version (35), + minor_protocol_version (36), + ipt_timestamp (126), + master_session_id (200), + message_from_sn (202), + requested_url (203), + authorization_result_code (204), + cds_uid (205), + msisdn (206), + authentication_type (207), + timestamp_created (208), + timestamp_used (209), + access_type (210), + requested_service_id (211), + user_alias (212), + service_session_id (213), + offload_indication (225), + gtp_tunnel_data (226), + gtpv1_tunnel_data (227) +} + +type record ericsson_type +{ + ericsson_type_enum f_ericsson_type, + UINT8 attrib_length_spec, + vendor_specific_value string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_ericsson_type, attrib_length_spec, string_val)" + variant (string_val) "CROSSTAG( + integer_val, f_ericsson_type=offload_indication; + string_val, OTHERWISE + )" + } + +type set of ericsson_type ericsson_subattr_list; + +// Vendor: acc (5) +type enum_8 acc_type_enum +{ + acc_error_message (1), + acc_ccp_option (2), + acc_customer_id (6), + acc_tunnel_secret (14), + acc_service_profile (17), + acc_request_type (18), + acc_dns_server_pri (23), + acc_dns_server_sec (24), + acc_nbns_server_pri (25), + acc_nbns_server_sec (26), + acc_dial_port_index (27), + acc_mn_ha_shared_secret (73), + acc_mip_spi (74) +} + +type record acc_type +{ + acc_type_enum f_acc_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_acc_type, attrib_length_spec, string_val)" + } + +type set of acc_type acc_subattr_list; + +// Vendor: microsoft (311) + +type enum_8 microsoft_type_enum +{ + microsoft_chap_mppe_keys (12), + microsoft_mppe_send_key (16), + microsoft_mppe_recv_key (17), + microsoft_primary_dns_server (28), + microsoft_secondary_dns_server (29), + microsoft_primary_nbns_server (30), + microsoft_secondary_nbns_server (31) +} + +type record microsoft_type +{ + microsoft_type_enum f_microsoft_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_microsoft_type, attrib_length_spec, string_val)" + } + +type set of microsoft_type microsoft_subattr_list; + +// Vendor: cdma2000 (5535) + +type enum_8 cdma2000_type_enum +{ + ike_pre_shared_secret_request (1), + security_level (2), + pre_shared_secret (3), + reverse_tunnel_specification (4), + differentiated_services_class (5), + container (6), + home_agent (7), + key_id (8), + pcf_ip_addr (9), + bs_msc_addr (10), + userid (11), + forward_mux (12), + reverse_mux (13), + forward_fundamental_rate (14), + reverse_fundamental_rate (15), + service_option (16), + forward_traffic_type (17), + reverse_traffic_type (18), + fundamental_frame_size (19), + forward_fundamental_rc (20), + reverse_fundamental_rc (21), + ip_technology (22), + compulsory_tunnel_indicator (23), + release_indicator (24), + bad_frame_count (25), + num_active (30), + sdb_input_octects (31), + sdb_output_octects (32), + numsdb_input (33), + numsdb_output (34), + ip_QoS (36), + air_QoS (39), + airlink_record_type (40), + rp_session_id (41), + airlink_secuence_number (42), + num_bytes_received_total (43), + + correlation_id (44), + mo_mt_indicator (45), + mobile_ip_sig_inbound_count (46), + mobile_ip_sig_outbound_count (47), + session_cont (48), + active_time (49), + dcch_frame_format (50), + ESN (52), + s_key (54), + s_request (55), + s_lifetime (56), + mn_ha_shared_secret_request (57), + mn_ha_shared_secret (58), + remote_ipv4_address (59), + hrpd_access_authentication (60), + + remote_ipv6_address (70), + remote_address_table_index (71), + remote_address_octet_count (72), + always_on (78), + last_user_activity_time (80), + + session_termination_capability (88), + prepaid_accounting_quota (90), + prepaid_accounting_capability (91), + mip_rrq_lifetime (92), + service_reference_id (94), + disconnect_reason (96), + cdma2000_error_cause (255) // WARNING: temporary type number, not yet standardized 2003-06-17 tmptso +} + +type record cdma2000_type +{ + cdma2000_type_enum f_cdma2000_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_cdma2000_type, attrib_length_spec,string_val)" + } + +type set of cdma2000_type cdma2000_subattr_list; + +// Vendor: threegpp (10415) + +type enum_8 threegpp_type_enum +{ + threegpp_imsi (1), + threegpp_charging_id (2), + threegpp_pdp_type (3), + threegpp_charging_gateway_address (4), + threegpp_gprs_negotiated_qos_profile (5), + threegpp_sgsn_ip_address (6), + threegpp_ggsn_ip_address (7), + threegpp_imsi_mcc_mnc (8), + threegpp_ggsn_mcc_mnc (9), + threegpp_nsapi (10), + threegpp_session_stop_indicator (11), + threegpp_selection_mode (12), + threegpp_charging_characteristics (13), + threegpp_cg_ipv6_address (14), + threegpp_sgsn_ipv6_address (15), + threegpp_ggsn_ipv6_address (16), + threegpp_ipv6_dns_servers (17), + threegpp_sgsn_mcc_mnc (18), + threegpp_teardown_indicator (19), + threegpp_imeisv (20), + threegpp_rat_type (21), + threegpp_user_location_info (22), + threegpp_ms_timezone (23), + threegpp_camel_charging_info (24), + threegpp_packet_filter (25), + threegpp_negotiated_dscp (26), + threegpp_allocate_ip_type (27), + threegpp_chargeable_user_identity (89) // FIXME no standard reference available ETIBSZA +} + + +type record threegpp_type +{ + threegpp_type_enum f_threegpp_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_threegpp_type, attrib_length_spec, string_val)" + } + +type set of threegpp_type threegpp_subattr_list; + +// Vendor: servicefactory (5556) + +type enum_8 servicefactory_type_enum +{ + servicefactory_product_profile_id (1), + servicefactory_access_point_id (7), + servicefactory_apn (14) // FIXME no standard reference available ETIBSZA +} + +type record servicefactory_type +{ + servicefactory_type_enum f_servicefactory_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_servicefactory_type, attrib_length_spec, string_val)" + } + +type set of servicefactory_type servicefactory_subattr_list; + +// Vendor: adslforum (3561) + +type enum_8 adslforum_type_enum +{ + adslforum_agent_circuit_id (1) +} + + +type record adslforum_type +{ + adslforum_type_enum f_adslforum_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_adslforum_type, attrib_length_spec, string_val)" + } + +type set of adslforum_type adslforum_subattr_list; + +// Vendor: wispr (14122) +type enum_8 wispr_type_enum +{ + wispr_location_id (1), + wispr_location_name(2) +} + + +type record wispr_type +{ + wispr_type_enum f_wispr_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_wispr_type, attrib_length_spec, string_val)" + } + +type set of wispr_type wispr_subattr_list; + + +// Vendor: chinatel (20942) + +type enum_8 chinatel_type_enum +{ + chinatel_served_mdn (100) +} + + +type record chinatel_type +{ + chinatel_type_enum f_chinatel_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_chinatel_type, attrib_length_spec, string_val)" + } + +type set of chinatel_type chinatel_subattr_list; + + + + diff --git a/src/obsolete/RadiusAccountingAttributes.rdf b/src/obsolete/RadiusAccountingAttributes.rdf new file mode 100644 index 0000000..fdcb867 --- /dev/null +++ b/src/obsolete/RadiusAccountingAttributes.rdf @@ -0,0 +1,114 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusAccountingAttributes.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2866(RADIUS Accounting) +// +// +// + + +// APPLICATION-NAME: Acc + + +// Packet-Type: Accounting_Request (4) + +// Packet-Type: Accounting_Response (5) + + +// RFC 2866 +// Attrib: Acct-Status-Type (40) +type enumerated Acct_Status_Type +{ + Start (1), + Stop (2), + Interim_Update (3), + Accounting_On (7), + Accounting_Off (8) +} + +// RFC 2866 +// Attrib: Acct-Delay-Type (41) +type Attrib_Value Acct_Delay_Type; + +// RFC 2866 +// Attrib: Acct-Input-Octets (42) +type Attrib_Value Acct_Input_Octets; + +// RFC 2866 +// Attrib: Acct-Output-Octets (43) +type Attrib_Value Acct_Output_Octets; + +// RFC 2866 +// Attrib: Acct-Session-Id (44) +type Attrib_Text Acct_Session_Id; + +// RFC 2866 +// Attrib: Acct-Authentic (45) +type enumerated Acct_Authentic +{ + RADIUS (1), + Local (2), + Remote (3) +} + +// RFC 2866 +// Attrib: Acct-Session-Time (46) +type Attrib_Value Acct_Session_Time; + +// RFC 2866 +// Attrib: Acct-Input-Packets (47) +type Attrib_Value Acct_Input_Packets; + +// RFC 2866 +// Attrib: Acct-Output-Packets (48) +type Attrib_Value Acct_Output_Packets; + +// RFC 2866 +// Attrib: Acct-Terminate-Cause (49) +type enumerated Acct_Terminate_Cause +{ + User_Request (1), + Lost_Carrier (2), + Lost_Service (3), + Idle_Timeout (4), + Session_Timeout (5), + Admin_Reset (6), + Admin_Reboot (7), + Port_Error (8), + NAS_Error (9), + NAS_Request (10), + NAS_Reboot (11), + Port_Unneeded (12), + Port_Preempted (13), + Port_Suspended (14), + Service_Unavailable (15), + Callback (16), + User_Error (17), + Host_Request (18) +} + +// RFC 2866 +// Attrib: Acct-Multi-Session-Id (50) +type Attrib_String Acct_Multi_Session_Id; + +// RFC 2866 +// Attrib: Acct-Link-Count (51) +type Attrib_Value Acct_Link_Count; diff --git a/src/obsolete/RadiusAndIPv6.rdf b/src/obsolete/RadiusAndIPv6.rdf new file mode 100644 index 0000000..e246e2f --- /dev/null +++ b/src/obsolete/RadiusAndIPv6.rdf @@ -0,0 +1,63 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusAndIPv6.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 3162(RADIUS and IPv6) +// +// +// + + +// APPLICATION-NAME: IPv6 + +// RFC 3162 +// Attrib: NAS-IPv6-Address (95) +type OCTET16 NAS_IPv6_Address; + +// RFC 3162 +// Attrib: Framed-Interface-Id (96) +type OCTET8 Framed_Interface_Id; + +// RFC 3162 +// Attrib: Framed-IPv6-Prefix (97) +type record Framed_IPv6_Prefix +{ + OCTET1 reserved, + UINT8 prefix_length, + bitstring prefixValue, + bitstring prefixPadding +} with { + variant (prefix_length) "LENGTHTO(prefixValue)"; + variant (prefix_length) "UNIT(bits)"; + variant (prefixValue) "BYTEORDER(last)"; + variant "FIELDORDER(msb)"; + } + +// RFC 3162 +// Attrib: Login-IPv6-Host (98) +type OCTET16 Login_IPv6_Host; + +// RFC 3162 +// Attrib: Framed-IPv6-Route (99) +type Attrib_Text Framed_IPv6_Route; + +// RFC 3162 +// Attrib: Framed-IPv6-Pool (100) +type Attrib_String Framed_IPv6_Pool; diff --git a/src/obsolete/RadiusAuthExtensions.rdf b/src/obsolete/RadiusAuthExtensions.rdf new file mode 100644 index 0000000..dacbc16 --- /dev/null +++ b/src/obsolete/RadiusAuthExtensions.rdf @@ -0,0 +1,63 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusAuthExtensions.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 3576(RADIUS Authorization Extensions) +// +// +// + + +// APPLICATION-NAME: AuthExt + + +// Packet-Type: Disconnect-Request (40) + +// Packet-Type: Disconnect-ACK (41) + +// Packet-Type: Disconnect-NAK (42) + +// Packet-Type: CoA-Request (43) + +// Packet-Type: CoA-ACK (44) + +// Packet-Type: CoA-NAK (45) + + +// RFC 3576 +// Attrib: Error-Cause (101) +type enumerated Error_Cause +{ + Residual_Session_Context_Removed (201), + Invalid_EAP_Packet (202), + Unsupported_Attribute (401), + Missing_Attribute (402), + NAS_Identification_Mismatch (403), + Invalid_Request (404), + Unsupported_Service (405), + Unsupported_Extension (406), + Administratively_Prohibited (501), + Request_Not_Routable_Proxy (502), + Session_Context_Not_Found (503), + Session_Context_Not_Removable (504), + Other_Proxy_Processing_Error (505), + Resources_Unavailable (506), + Request_Initiated (507) +} diff --git a/src/obsolete/RadiusBaseAttributes.rdf b/src/obsolete/RadiusBaseAttributes.rdf new file mode 100644 index 0000000..0de0562 --- /dev/null +++ b/src/obsolete/RadiusBaseAttributes.rdf @@ -0,0 +1,772 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusBaseAttributes.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2865(RADIUS) +// +// +// + + +// APPLICATION-NAME: Base + + + +// Packet-Type: Access-Request (1) + +// Packet-Type: Access_Accept (2) + +// Packet-Type: Access_Reject (3) + +// Packet-Type: Accounting_Request (4) + +// Packet-Type: Accounting_Response (5) + +// Packet-Type: Access_Challenge (11) + +// Packet-Type: Status_Server (12) + +// Packet-Type: Status_Client (13) + +// Packet-Type: Reserved (255) + + + + +// RFC 2865 +// Attrib: User-Name (1) +type Attrib_String User_Name; + +// RFC 2865 +// Attrib: User-Password (2) +type Attrib_String User_Password; + +// RFC 2865 +// Attrib: CHAP-Password (3) +type record CHAP_Password +{ + UINT8 CHAP_Ident, + Attrib_String String length(16) +} + +// RFC 2865 +// Attrib: NAS-IP-Address (4) +type Attrib_Address NAS_IP_Address; + +// RFC 2865 +// Attrib: NAS-Port (5) +type Attrib_Value NAS_Port; + +// RFC 2865 +// Attrib: Service-Type (6) +type enumerated Service_Type +{ + Login (1), + Framed (2), + Callback_Login (3), + Callback_Framed (4), + Outbound (5), + Administrative (6), + NAS_Prompt (7), + Authenticate_Only (8), + Callback_NAS_Prompt (9), + Call_Check (10), + Callback_Administrative (11) +} + + +// RFC 2865 +// Attrib: Framed-Protocol (7) +type enumerated Framed_Protocol +{ + PPP (1), + SLIP (2), + Appletalk_Remote_Access_Protocol (3), + Gandalf_proprietary_protocol (4), + Xylogics_proprietary (5), + Xpoint75_Syncronous (6), + GPRS_PDP_Context (7) +} + + +// RFC 2865 +// Attrib: Framed-IP-Address (8) +type Attrib_Address Framed_IP_Address; + +// RFC 2865 +// Attrib: Framed-IP-Netmask (9) +type Attrib_Address Framed_IP_Netmask; + +// RFC 2865 +// Attrib: Framed-Routing (10) +type enumerated Framed_Routing +{ + None (0), + Send_routing_pacets (1), + Listen_for_routing_pacets (2), + Send_and_Listen (3) +} + +// RFC 2865 +// Attrib: Filter-Id (11) +type Attrib_Text Filter_Id; + +// RFC 2865 +// Attrib: Framed-MTU (12) +type Attrib_Value Framed_MTU (64..65535); + +// RFC 2865 +// Attrib: Framed-Compression (13) +type enumerated Framed_Compression +{ + None (0), + VJ_TCP_IP_header_compression (1), + IPX_header_compression (2), + STAC_LZS_compression (3) +} + +// RFC 2865 +// Attrib: Login-IP-Host (14) +type Attrib_Address Login_IP_Host; + +// RFC 2865 +// Attrib: Login-Service (15) +type enumerated Login_Service +{ + Telnet (0), + Rlogin (1), + TCP_Clear (2), + Port_Master (3), + LAT (4), + X25_PAD (5), + X25_T3POS (6), + TCP_Clear_Quiet (7) +} + +// RFC 2865 +// Attrib: Login-TCP-Port (16) +type Attrib_Value Login_TCP_Port (0..65535); + +// RFC 2865 +// Attrib: Reply-Message (18) +type Attrib_Text Reply_Message; + +// RFC 2865 +// Attrib: Callback-Number (19) +type Attrib_String Callback_Number; + +// RFC 2865 +// Attrib: Callback-Id (20) +type Attrib_String Callback_Id; + +// RFC 2865 +// Attrib: Framed-Route (22) +type Attrib_Text Framed_Route; + +// RFC 2865 +// Attrib: Framed-IPX-Network (23) +type Attrib_Value Framed_IPX_Network; + +// RFC 2865 +// Attrib: State (24) +type Attrib_String State; + +// RFC 2865 +// Attrib: Class (25) +type Attrib_String Class; + + +// RFC 2865 +// Attrib: Session-Timeout (27) +type Attrib_Value Session_Timeout; + +// RFC 2865 +// Attrib: Idle-Timeout (28) +type Attrib_Value Idle_Timeout; + +// RFC 2865 +// Attrib: Termination-Action (29) +type enumerated Termination_Action +{ + Default (0), + RADIUS_Request (1) +} + +// RFC 2865 +// Attrib: Called-Station-Id (30) +type Attrib_String Called_Station_Id; + +// RFC 2865 +// Attrib: Calling-Station-Id (31) +type Attrib_String Calling_Station_Id; + +// RFC 2865 +// Attrib: NAS-Identifier (32) +type Attrib_String NAS_Identifier; + +// RFC 2865 +// Attrib: Proxy-State (33) +type Attrib_String Proxy_State; + +// RFC 2865 +// Attrib: Login-LAT-Service (34) +type Attrib_String Login_LAT_Service; + +// RFC 2865 +// Attrib: Login-LAT-Node (35) +type Attrib_String Login_LAT_Node; + +// RFC 2865 +// Attrib: Login-LAT-Group (36) +type Attrib_String Login_LAT_Group; + +// RFC 2865 +// Attrib: Framed-AppleTalk-Link (37) +type Attrib_Value Framed_AppleTalk_Link (0..65535); + +// RFC 2865 +// Attrib: Framed-AppleTalk-Network (38) +type Attrib_Value Framed_AppleTalk_Network (0..65535); + +// RFC 2865 +// Attrib: Framed-AppleTalk-Zone (39) +type Attrib_String Framed_AppleTalk_Zone; + +// RFC 2865 +// Attrib: CHAP-Challenge (60) +type Attrib_String CHAP_Challenge; + +// RFC 2865 +// Attrib: NAS-Port-Type (61) +type enumerated NAS_Port_Type +{ + Async (0), + Sync (1), + ISDN_Sync (2), + ISDN_Async_v120 (3), + ISDN_Async_v110 (4), + Virtual (5), + PIAFS (6), + HDLC_Clear_Channel (7), + X25 (8), + X75 (9), + G3_Fax (10), + SDSL_Symmetric_DSL (11), + ADSL_CAP_Asymmetric_DSL (12), + ADSL_DMT_Asymmetric_DSL (13), + ISDL_ISDN_Digital_Subscriber_Line (14), + Ethernet (15), + xDSL (16), + Cable (17), + Wireless_Other (18), + Wireless_IEEE_80211 (19) +} + + +// RFC 2865 +// Attrib: Port-Limit (62) +type Attrib_Value Port_Limit; + +// RFC 2865 +// Attrib: Login-LAT-Port (63) +type Attrib_String Login_LAT_Port; + + + +// RFC 2865 +// Attrib: Vendor-Specific (26) +type record Vendor_Specific +{ + vendor_id_enum vendor_id, + string_val_spec attrib_value +} with { + variant (attrib_value) "CROSSTAG(f_scap_subattr_list, vendor_id=scap; + f_acc_subattr_list, vendor_id=acc; + f_cisco_subattr_list, vendor_id=cisco; + f_ericsson_subattr_list, vendor_id=ericsson; + f_microsoft_subattr_list, vendor_id=microsoft; + f_adslforum_subattr_list, vendor_id=adslforum; + f_cdma2000_subattr_list, vendor_id=cdma2000 ; + f_servicefactory_subattr_list, vendor_id=servicefactory; + f_threegpp_subattr_list, vendor_id=threegpp; + f_wispr_subattr_list, vendor_id=wispr)" + } + + +type enum_32 vendor_id_enum +{ + acc (5), + cisco (9), + ericsson (193), + microsoft (311), + adslforum (3561), + cdma2000 (5535), + servicefactory (5556), + threegpp (10415), + scap (10923), + wispr (14122) +} + + +type enum_8 acc_type_enum +{ + acc_error_message (1), + acc_ccp_option (2), + acc_customer_id (6), + acc_tunnel_secret (14), + acc_service_profile (17), + acc_request_type (18), + acc_dns_server_pri (23), + acc_dns_server_sec (24), + acc_nbns_server_pri (25), + acc_nbns_server_sec (26), + acc_dial_port_index (27), + acc_mn_ha_shared_secret (73), + acc_mip_spi (74) +} + + +type enum_8 cisco_type_enum +{ + cisco_access_control_list (1), + cisco_nas_port (2), + cisco_info_service (250), + cisco_service_list (251), + cisco_n_service_info (252), + cisco_byte_count (253) +} + + +type enum_8 ericsson_type_enum +{ + product_profile (1), + digest_response (14), + digest_attributes (15), + pmk (17), + layer_identity (34), + major_protocol_version (35), + minor_protocol_version (36), + ipt_timestamp (126), + master_session_id (200), + message_from_sn (202), + requested_url (203), + authorization_result_code (204), + cds_uid (205), + msisdn (206), + authentication_type (207), + timestamp_created (208), + timestamp_used (209), + access_type (210), + requested_service_id (211), + user_alias (212), + service_session_id (213) +} + + +type enum_8 cdma2000_type_enum +{ + ike_pre_shared_secret_request (1), + security_level (2), + pre_shared_secret (3), + reverse_tunnel_specification (4), + differentiated_services_class (5), + container (6), + home_agent (7), + key_id (8), + pcf_ip_addr (9), + bs_msc_addr (10), + userid (11), + forward_mux (12), + reverse_mux (13), + forward_fundamental_rate (14), + reverse_fundamental_rate (15), + service_option (16), + forward_traffic_type (17), + reverse_traffic_type (18), + fundamental_frame_size (19), + forward_fundamental_rc (20), + reverse_fundamental_rc (21), + ip_technology (22), + compulsory_tunnel_indicator (23), + release_indicator (24), + bad_frame_count (25), + num_active (30), + sdb_input_octects (31), + sdb_output_octects (32), + numsdb_input (33), + numsdb_output (34), + ip_QoS (36), + air_QoS (39), + airlink_record_type (40), + rp_session_id (41), + airlink_secuence_number (42), + num_bytes_received_total (43), + + correlation_id (44), + mo_mt_indicator (45), + mobile_ip_sig_inbound_count (46), + mobile_ip_sig_outbound_count (47), + session_cont (48), + active_time (49), + dcch_frame_format (50), + ESN (52), + s_key (54), + s_request (55), + s_lifetime (56), + mn_ha_shared_secret_request (57), + mn_ha_shared_secret (58), + remote_ipv4_address (59), + hrpd_access_authentication (60), + + remote_ipv6_address (70), + remote_address_table_index (71), + remote_address_octet_count (72), + always_on (78), + last_user_activity_time (80), + + session_termination_capability (88), + prepaid_accounting_quota (90), + prepaid_accounting_capability (91), + mip_rrq_lifetime (92), + service_reference_id (94), + disconnect_reason (96), + cdma2000_error_cause (255) // WARNING: temporary type number, not yet standardized 2003-06-17 tmptso +} + + +type enum_8 threegpp_type_enum +{ + threegpp_imsi (1), + threegpp_charging_id (2), + threegpp_pdp_type (3), + threegpp_charging_gateway_address (4), + threegpp_gprs_negotiated_qos_profile (5), + threegpp_sgsn_ip_address (6), + threegpp_ggsn_ip_address (7), + threegpp_imsi_mcc_mnc (8), + threegpp_ggsn_mcc_mnc (9), + threegpp_nsapi (10), + threegpp_session_stop_indicator (11), + threegpp_selection_mode (12), + threegpp_charging_characteristics (13), + threegpp_cg_ipv6_address (14), + threegpp_sgsn_ipv6_address (15), + threegpp_ggsn_ipv6_address (16), + threegpp_ipv6_dns_servers (17), + threegpp_sgsn_mcc_mnc (18), + threegpp_teardown_indicator (19), + threegpp_imeisv (20), + threegpp_rat_type (21), + threegpp_user_location_info (22), + threegpp_ms_timezone (23), + threegpp_camel_charging_info (24), + threegpp_packet_filter (25), + threegpp_negotiated_dscp (26), + threegpp_chargeable_user_identity (89) // FIXME no standard reference available ETIBSZA +} + + +type enum_8 servicefactory_type_enum +{ + servicefactory_product_profile_id (1), + servicefactory_access_point_id (7), + servicefactory_apn (14) // FIXME no standard reference available ETIBSZA +} + + +type enum_8 microsoft_type_enum +{ + microsoft_chap_mppe_keys (12), + microsoft_mppe_send_key (16), + microsoft_mppe_recv_key (17), + microsoft_primary_dns_server (28), + microsoft_secondary_dns_server (29), + microsoft_primary_nbns_server (30), + microsoft_secondary_nbns_server (31) +} + +type enum_8 adslforum_type_enum +{ + adslforum_agent_circuit_id (1) +} + + +type enum_8 wispr_type_enum +{ + wispr_location_id (1), + wispr_location_name(2) +} + +type enum_8 scap_type_enum +{ + requested_service_unit (1), + used_service_unit (2), + granted_service_unit (3), + unit_type (4), + unit_value (5), + value_digits (6), + exponent (7), + currency_code (8), + subscription_id (9), + additional_subscription_id (10), + subscription_id_type (11), + subscription_id_data (12), + event_timestamp (13), + accounting_record_number (14), + result_code (15), + accounting_interim_interval (16), + origin_state_id (17), + suggested_primary_rulespace (30), + suggested_secondary_rulespace (31) +} + + +type enum_8 scap_unit_type_enum { + SERVICE_CREDIT_TIME (0), + SERVICE_CREDIT_VOLUME (1), + SERVICE_CREDIT_EVENT (2), + SERVICE_CREDIT_MONEY (3) +} + + +type enum_8 scap_subsription_id_type_enum { + END_USER_MSISDN (0), + END_USER_IMSI (1), + END_USER_SIP_URL (2), + END_USER_NAI (3), + END_USER_PRIVATE (4) +} + +type record scap_unit_type_t { + scap_type_enum scap_type, + UINT8 scap_length, + INT32 scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)" +} + +type set of scap_unit_type_t unit_value_list; + +type union unit_value_t +{ + octetstring string_val, + scap_unit_type_enum unit_type_val, + scap_subsription_id_type_enum subsription_id_type_val, + unit_value_list unit_type_list, + INT32 integer_val, + charstring unichar_val +} + + +type record service_unit_t { + scap_type_enum scap_type, + UINT8 scap_length, + unit_value_t scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)"; + variant (scap_val) "CROSSTAG( + unit_type_val, scap_type=unit_type; + unit_type_list, scap_type=unit_value; + integer_val, scap_type=value_digits; + integer_val, scap_type=exponent; + integer_val, scap_type=currency_code; + unit_type_list, scap_type=subscription_id; + integer_val, scap_type=additional_subscription_id; + subsription_id_type_val, scap_type=subscription_id_type; + unichar_val, scap_type=subscription_id_data; + integer_val, scap_type=event_timestamp; + integer_val, scap_type=accounting_record_number; + integer_val, scap_type=result_code; + integer_val, scap_type=accounting_interim_interval; + integer_val, scap_type=origin_state_id)" + } + + +type set of service_unit_t service_unit_list; + + +type union scap_value { + octetstring string_val, + scap_unit_type_enum unit_type_val, + unit_value_list unit_type_list, + service_unit_list f_service_unit_list, + scap_subsription_id_type_enum subscription_id_type_val, + INT32 integer_val, + charstring unichar_val, + charstring charstring_val +} + + +type record scap_subattr_t { + scap_type_enum scap_type, + UINT8 scap_length, + scap_value scap_val +} with { + variant (scap_length) "LENGTHTO(scap_type, scap_length, scap_val)"; + variant (scap_val) "CROSSTAG( + f_service_unit_list, scap_type=requested_service_unit; + f_service_unit_list, scap_type=used_service_unit; + f_service_unit_list, scap_type=granted_service_unit; + unit_type_val, scap_type=unit_type; + unit_type_list, scap_type=unit_value; + integer_val, scap_type=value_digits; + integer_val, scap_type=exponent; + integer_val, scap_type=currency_code; + f_service_unit_list, scap_type=subscription_id; + integer_val, scap_type=additional_subscription_id; + subscription_id_type_val, scap_type=subscription_id_type; + unichar_val, scap_type=subscription_id_data; + integer_val, scap_type=event_timestamp; + integer_val, scap_type=accounting_record_number; + integer_val, scap_type=result_code; + integer_val, scap_type=accounting_interim_interval; + integer_val, scap_type=origin_state_id; + charstring_val, scap_type=suggested_primary_rulespace; + charstring_val, scap_type=suggested_secondary_rulespace)" + } + +type set of scap_subattr_t scap_subattr_list; + + + + + +type record acc_type +{ + acc_type_enum f_acc_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_acc_type, attrib_length_spec, string_val)" + } + +type set of acc_type acc_subattr_list; + +type record cisco_type +{ + cisco_type_enum f_cisco_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_cisco_type, attrib_length_spec, string_val)" + } + +type set of cisco_type cisco_subattr_list; + + +type record ericsson_type +{ + ericsson_type_enum f_ericsson_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_ericsson_type, attrib_length_spec, string_val)" + } + +type set of ericsson_type ericsson_subattr_list; + + +type record cdma2000_type +{ + cdma2000_type_enum f_cdma2000_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_cdma2000_type, attrib_length_spec,string_val)" + } + +type set of cdma2000_type cdma2000_subattr_list; + + +type record threegpp_type +{ + threegpp_type_enum f_threegpp_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_threegpp_type, attrib_length_spec, string_val)" + } + +type set of threegpp_type threegpp_subattr_list; + +type record microsoft_type +{ + microsoft_type_enum f_microsoft_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_microsoft_type, attrib_length_spec, string_val)" + } + +type set of microsoft_type microsoft_subattr_list; + +type record servicefactory_type +{ + servicefactory_type_enum f_servicefactory_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_servicefactory_type, attrib_length_spec, string_val)" + } + +type set of servicefactory_type servicefactory_subattr_list; + +type record adslforum_type +{ + adslforum_type_enum f_adslforum_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_adslforum_type, attrib_length_spec, string_val)" + } + +type set of adslforum_type adslforum_subattr_list; + + +type record wispr_type +{ + wispr_type_enum f_wispr_type, + UINT8 attrib_length_spec, + octetstring string_val +} with { + variant (attrib_length_spec) "LENGTHTO(f_wispr_type, attrib_length_spec, string_val)" + } + +type set of wispr_type wispr_subattr_list; + + + +type union string_val_spec +{ + acc_subattr_list f_acc_subattr_list, + cisco_subattr_list f_cisco_subattr_list, + ericsson_subattr_list f_ericsson_subattr_list, + cdma2000_subattr_list f_cdma2000_subattr_list, + threegpp_subattr_list f_threegpp_subattr_list, + microsoft_subattr_list f_microsoft_subattr_list, + servicefactory_subattr_list f_servicefactory_subattr_list, + adslforum_subattr_list f_adslforum_subattr_list, + wispr_subattr_list f_wispr_subattr_list, + scap_subattr_list f_scap_subattr_list, + octetstring f_string_val +} + + + diff --git a/src/obsolete/RadiusBaseTypes.rdf b/src/obsolete/RadiusBaseTypes.rdf new file mode 100644 index 0000000..94a3872 --- /dev/null +++ b/src/obsolete/RadiusBaseTypes.rdf @@ -0,0 +1,92 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusBaseTypes.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2865(RADIUS) +// +// +// + + +// +// External functions for encoding and decoding +// + +external function f_RADIUS_Enc(in PDU_RADIUS pdu) return octetstring; +external function f_RADIUS_Dec(in octetstring stream) return PDU_RADIUS; +external function crypt_password(in octetstring P,in octetstring req_auth,in octetstring salt,in boolean decrypt,in charstring secret) return octetstring; +external function f_calc_MD5(in octetstring input) return octetstring; + + + +// +// Basic type definitions +// + +type integer UINT8 (0..255) with { +variant "FIELDLENGTH(8)" +variant "BYTEORDER(last)" +} + +type integer UINT16 (0..65535) with { +variant "FIELDLENGTH(16)" +variant "BYTEORDER(last)" +} + +type integer UINT24 (0..16777215) with { +variant "FIELDLENGTH(24)" +variant "BYTEORDER(last)" +} + +type integer UINT32 (0..4294967296) with { +variant "FIELDLENGTH(32)" +variant "BYTEORDER(last)" +} + +type integer UINT64 with { +variant "FIELDLENGTH(64)" +variant "BYTEORDER(last)" +} + +type integer INT32 with { +variant "FIELDLENGTH(32)" +variant "BYTEORDER(last)" +variant "COMP(2scompl)" +} + +type octetstring OCTET1 length(1) +type octetstring OCTET2 length(2) +type octetstring OCTET3 length(3) +type octetstring OCTET4 length(4) +type octetstring OCTET8 length(8) +type octetstring OCTET16 length(16) + +// +// Basic Attribute Data Formats +// + +type charstring Attrib_Text length(1..253) with { variant "PADDING(yes)"}; +type octetstring Attrib_String length(1..253); +type OCTET4 Attrib_Address; +type OCTET4 Attrib_Time; +type UINT32 Attrib_Value; + + + diff --git a/src/obsolete/RadiusExtensions.rdf b/src/obsolete/RadiusExtensions.rdf new file mode 100644 index 0000000..ab4c0e1 --- /dev/null +++ b/src/obsolete/RadiusExtensions.rdf @@ -0,0 +1,124 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusExtensions.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2866(RADIUS Extensions) +// +// +// + + +// APPLICATION-NAME: Ext + +// RFC 2869 +// Attrib: Acct-Input-Gigawords (52) +type Attrib_Value Acct_Input_Gigawords; + +// RFC 2869 +// Attrib: Acct-Output-Gigawords (53) +type Attrib_Value Acct_Output_Gigawords; + +// RFC 2869 +// Attrib: Event-Timestamp (55) +type Attrib_Value Event_Timestamp; + +// RFC 2869 +// Attrib: ARAP-Password (70) +type record ARAP_Password +{ + Attrib_Value Value1, + Attrib_Value Value2, + Attrib_Value Value3, + Attrib_Value Value4 +} + +// RFC 2869 +// Attrib: ARAP-Features (71) +type record ARAP_Features +{ + UINT8 variable_password, + UINT8 password_length, + Attrib_Time creation_time, + Attrib_Value expiration_time, + Attrib_Time radius_time +} + +// RFC 2869 +// Attrib: ARAP-Zone-Access (72) +type enumerated ARAP_Zone_Access +{ + To_default_zone (1), + Use_zone_filter_inclusively (2), + Use_zone_filter_exclusively (3) +} + +// RFC 2869 +// Attrib: ARAP-Security (73) +type Attrib_Value ARAP_Security; + +// RFC 2869 +// Attrib: ARAP-Security-Data (74) +type Attrib_String ARAP_Security_Data; + +// RFC 2869 +// Attrib: Password-Retry (75) +type Attrib_Value Password_Retry; + +// RFC 2869 +// Attrib: Prompt (76) +type enumerated Prompt +{ + No_Echo (0), + Echo (1) +} + +// RFC 2869 +// Attrib: Connect-Info (77) +type Attrib_Text Connect_Info; + +// RFC 2869 +// Attrib: Configuration-Token (78) +type Attrib_String Configuration_Token; + +// RFC 2869 +// Attrib: EAP-Message (79) +type Attrib_String EAP_Message; + +// RFC 2869 +// Attrib: Message-Authenticator (80) +type Attrib_String Message_Authenticator; + +// RFC 2869 +// Attrib: ARAP-Challenge-Response (84) +type UINT64 ARAP_Challenge_Response; + +// RFC 2869 +// Attrib: Acct-Interim-Interval (85) +type Attrib_Value Acct_Interim_Interval; + +// RFC 2869 +// Attrib: NAS-Port-Id (87) +type Attrib_Text NAS_Port_Id; + +// RFC 2869 +// Attrib: Framed-Pool (88) +type Attrib_String Framed_Pool; + + diff --git a/src/obsolete/RadiusGGSN.rdf b/src/obsolete/RadiusGGSN.rdf new file mode 100644 index 0000000..6b75e80 --- /dev/null +++ b/src/obsolete/RadiusGGSN.rdf @@ -0,0 +1,54 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: RadiusGGSN.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: GGSN Functional Specification: RADIUS +// 46/155 17-CSA 113 35/4 Uen Rev B +// +// + + +// APPLICATION-NAME: Ggsn + +// Attrib: Imsi (224) +type Attrib_Text Imsi; + +// Attrib: Charging-Id (225) +type Attrib_Value Charging_Id; + +// Attrib: Imsi-Mcc-Mnc (226) +type Attrib_Text Imsi_Mcc_Mnc; + +// Attrib: Sgsn-IP-Address (228) +type Attrib_Address Sgsn_IP_Address; + +// Attrib: Selection-Mode (229) +type Attrib_Text Selection_Mode; + +// Attrib: Ggsn-Gtp-IP-Address (230) +type Attrib_Address Ggsn_Gtp_IP_Address; + +// Attrib: Primary-Dns-Server (135) +type Attrib_Address Primary_Dns_Server; + +// Attrib: Secondary-Dns-Server (136) +type Attrib_Address Secondary_Dns_Server; + + diff --git a/src/obsolete/TunnelAuthenticationAttributes.rdf b/src/obsolete/TunnelAuthenticationAttributes.rdf new file mode 100644 index 0000000..bd880c5 --- /dev/null +++ b/src/obsolete/TunnelAuthenticationAttributes.rdf @@ -0,0 +1,159 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: TunnelAuthenticationAttributes.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: RFC 2868(RADIUS Attributes for Tunnel Protocol Support) +// +// +// + + +// APPLICATION-NAME: Auth + + +type enum_24 Tunnel_Type_Value +{ + PPTP (1), + L2F (2), + L2TP (3), + ATMP (4), + VTP (5), + AH (6), + IP_IP (7), + MIN_IP_IP (8), + ESP (9), + GRE (10), + DVS (11), + IP_IP_Tunneling (12) +} + +// RFC 2868 +// Attrib: Tunnel-Type (64) +type record Tunnel_Type +{ + OCTET1 Tag, + Tunnel_Type_Value Value +} + + +type enum_24 Tunnel_Medium_Type_Value +{ + IPv4 (1), + IPv6 (2), + NSAP (3), + HDLC (4), + BBN_1822 (5), + media_plus_Ethernet_802 (6), + Epoint163 (7), + Epoint164 (8), + Fpoint69 (9), + Xpoint121 (10), + IPX (11), + Appletalk (12), + Decnet_IV (13), + Banyan_Vines (14), + Epoint164_with_NSAP_subaddress (15) +} + + +// RFC 2868 +// Attrib: Tunnel-Medium-Type (65) +type record Tunnel_Medium_Type +{ + OCTET1 Tag, + Tunnel_Medium_Type_Value Value +} + + +// RFC 2868 +// Attrib: Tunnel-Client-Endpoint (66) +type record Tunnel_Client_Endpoint +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Server-Endpoint (67) +type record Tunnel_Server_Endpoint +{ + OCTET1 Tag, + Attrib_String String +} + +type record Tunnel_Password_String +{ + UINT8 Data_Length, + Attrib_String Password, + octetstring Padding_Sub_Field +} with { + variant (Data_Length) "LENGTHTO(Password)" +} + +// RFC 2868 +// Attrib: Tunnel-Password (69) +type record Tunnel_Password +{ + OCTET1 Tag, + OCTET2 Salt, + Tunnel_Password_String String +} + +// RFC 2868 +// Attrib: Tunnel-Private-Group-ID (81) +type record Tunnel_Private_Group_ID +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Assignment-ID (82) +type record Tunnel_Assignment_ID +{ + OCTET1 Tag, + Attrib_String String +} + + +// RFC 2868 +// Attrib: Tunnel-Preference (83) +type record Tunnel_Preference +{ + OCTET1 Tag, + Attrib_Value Value +} + +// RFC 2868 +// Attrib: Tunnel-Client-Auth-ID (90) +type record Tunnel_Client_Auth_ID +{ + OCTET1 Tag, + Attrib_String String +} + +// RFC 2868 +// Attrib: Tunnel-Server-Auth-ID (91) +type record Tunnel_Server_Auth_ID +{ + OCTET1 Tag, + Attrib_String String +} + diff --git a/src/skt.rdf b/src/skt.rdf new file mode 100644 index 0000000..0197074 --- /dev/null +++ b/src/skt.rdf @@ -0,0 +1,60 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Timea Moder +* Endre Kulcsar +* Gabor Szalai +* Janos Kovesdi +* Kulcsár Endre +* Zoltan Medve +* Tamas Korosi +******************************************************************************/ + +// +// File: skt.rdf +// Rev: <RnXnn> +// Prodnr: CNL 113 600 +// Reference: +// +// + +// Vendor: skt (5806) + + +type enum_8 skt_type_enum +{ + service_key (1), + prepaid_expired (2), + preservation_indicator (17) +} + + + + + +type union skt_value { + octetstring string_val, + UINT32 integer_val, + UINT8 byte_val +} + + +type record skt_subattr_t { + skt_type_enum skt_type, + UINT8 skt_length, + skt_value skt_val +} with { + variant (skt_length) "LENGTHTO(skt_type, skt_length, skt_val)"; + variant (skt_val) "CROSSTAG( + string_val, skt_type=preservation_indicator; + byte_val, skt_type=prepaid_expired; + integer_val, skt_type=service_key)" + } + +type set of skt_subattr_t skt_subattr_list; + -- GitLab