From a47bbbef78ce185d9c795150c8c0f7c1bc31b82d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Radek=20Mat=C4=9Bjka?= Date: Wed, 28 Nov 2012 15:09:21 -0600 Subject: [PATCH] PowerPC benchmark ppc folder was added. ppc folder contains files used for benchmark on PowerPC. (eg. ppc executables, modified sources, results) --- ppc/bench-kernel | 25 ++ ppc/cegw-ppc/Makefile | 5 + ppc/cegw-ppc/cegw | Bin 0 -> 29127 bytes ppc/cegw-ppc/cegw.c | 559 ++++++++++++++++++++++++++++++++++++++ ppc/cesend/Makefile | 3 + ppc/cesend/cesend | Bin 0 -> 7082 bytes ppc/cesend/cesend.c | 145 ++++++++++ ppc/gw-kernel | 8 + ppc/gw-user | 5 + ppc/res/ncrcv | 18 ++ ppc/res/plotres.m | 31 +++ ppc/res/res.tar | Bin 0 -> 20480 bytes ppc/res/res1 | 4 + ppc/res/res2 | 4 + ppc/res/res3 | 4 + ppc/res/res_u1 | 4 + ppc/res/res_u2 | 4 + ppc/res/res_u3 | 4 + ppc/res/result/res1.raw | 4 + ppc/res/result/res2.raw | 2 + ppc/res/result/res3.raw | 2 + ppc/res/result/res_k1.raw | 2 + ppc/res/result/res_u1.raw | 2 + ppc/res/result/res_u2.raw | 2 + ppc/res/result/res_u3.raw | 2 + ppc/shark_home.tar | Bin 0 -> 133120 bytes ppc/test | 26 ++ ppc/user/Makefile | 5 + ppc/user/canethgw | Bin 0 -> 19263 bytes ppc/user/canethgw.c | 279 +++++++++++++++++++ 30 files changed, 1149 insertions(+) create mode 100755 ppc/bench-kernel create mode 100644 ppc/cegw-ppc/Makefile create mode 100755 ppc/cegw-ppc/cegw create mode 100644 ppc/cegw-ppc/cegw.c create mode 100644 ppc/cesend/Makefile create mode 100755 ppc/cesend/cesend create mode 100644 ppc/cesend/cesend.c create mode 100755 ppc/gw-kernel create mode 100755 ppc/gw-user create mode 100755 ppc/res/ncrcv create mode 100644 ppc/res/plotres.m create mode 100644 ppc/res/res.tar create mode 100644 ppc/res/res1 create mode 100644 ppc/res/res2 create mode 100644 ppc/res/res3 create mode 100644 ppc/res/res_u1 create mode 100644 ppc/res/res_u2 create mode 100644 ppc/res/res_u3 create mode 100644 ppc/res/result/res1.raw create mode 100644 ppc/res/result/res2.raw create mode 100644 ppc/res/result/res3.raw create mode 100644 ppc/res/result/res_k1.raw create mode 100644 ppc/res/result/res_u1.raw create mode 100644 ppc/res/result/res_u2.raw create mode 100644 ppc/res/result/res_u3.raw create mode 100644 ppc/shark_home.tar create mode 100755 ppc/test create mode 100644 ppc/user/Makefile create mode 100755 ppc/user/canethgw create mode 100644 ppc/user/canethgw.c diff --git a/ppc/bench-kernel b/ppc/bench-kernel new file mode 100755 index 0000000..22180af --- /dev/null +++ b/ppc/bench-kernel @@ -0,0 +1,25 @@ +#!/bin/sh +N=100 +MODE=oneattime +SLEEP=1 +LOGANDPRINT="tee -a result | cut -c 2-" +RESULTFILE=/dev/null +SENDRES=0 + +if test $# -eq 1; then + RESULTFILE=$1 + SENDRES=1 +fi + +#----------------- +# bench kernel +#----------------- + +sleep $SLEEP +echo "#kernel udp->can: " | tee -a result | cut -c 2- +cegwbench -s udp@127.0.0.1:10501 -d can@vcan0 -n $N -m $MODE -t 1 >> $RESULTFILE + +sleep $SLEEP +echo "#kernel can->udp: " | tee -a result | cut -c 2- +cegwbench -s can@vcan0 -d udp@127.0.0.1:10502 -n $N -m $MODE -t 1 >> $RESULTFILE + diff --git a/ppc/cegw-ppc/Makefile b/ppc/cegw-ppc/Makefile new file mode 100644 index 0000000..b8214a9 --- /dev/null +++ b/ppc/cegw-ppc/Makefile @@ -0,0 +1,5 @@ +all: + powerpc-linux-gnu-gcc -Wall -ggdb -ocegw -I../../kernel cegw.c +install: all + scp cegw glab:/srv/nfs/root-shark/home/matejra4 + diff --git a/ppc/cegw-ppc/cegw b/ppc/cegw-ppc/cegw new file mode 100755 index 0000000000000000000000000000000000000000..5a62abe69442a1afbcb62b75aaadfa14e50c8c1d GIT binary patch literal 29127 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 +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include "canethgw.h" + +/** + * ToDo: + * [ ] print usage, on -h and plain execution + * [ ] start/stop listening + * [ ] split to files + */ + +#define CEGW_CMD_ADD 1 +#define CEGW_CMD_LIST 2 +#define CEGW_CMD_FLUSH 4 +#define CEGW_CMD_LISTEN 8 + +/* PowerPC encore */ +#define RTCAN_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtcanmsg)))) +#define RTCAN_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtcanmsg)) + +/* some netlink helpers stolen from iproute2 package */ +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *)(((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#define AF_CAN 29 + +int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr, "addattr_l: message exceeded bound of %d\n", + maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return 0; +} + +int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u32)); +} + +enum +{ + IF_UNDEF, + IF_CAN, + IF_ETH_UDP +}; + +struct cegw_data +{ + int content; + int src_if, dst_if; + int can_ifidx; + struct in_addr eth_addr; + unsigned short eth_port; + struct in_addr eth_listen_addr; + unsigned short eth_listen_port; +}; + +struct cegw_nlmsg +{ + struct nlmsghdr nh; + struct rtmsg rt; + char buf[768]; /* enough? */ +}; + +struct list_item +{ + int type; + int can; + struct in_addr ip; + unsigned short port; +}; + +unsigned int cegw_errno = 0; + +enum +{ + CEGW_ERR_UNKNOWN, + CEGW_ERR_IF_UNSPEC, + CEGW_ERR_IF_SAME, + CEGW_ERR_IF_TYPE, + CEGW_ERR_IF_CAN, + CEGW_ERR_IF_ETH, + CEGW_ERR_COLON, + CEGW_ERR_ATON, + CEGW_ERR_PORT +}; + +char* cegw_errlist[] = +{ + [ CEGW_ERR_UNKNOWN ] = "", + [ CEGW_ERR_IF_UNSPEC ] = "source or destination not specified", + [ CEGW_ERR_IF_SAME ] = "source and destination have same interface type", + [ CEGW_ERR_IF_TYPE ] = "unknown interface type", + [ CEGW_ERR_IF_CAN ] = "invalid can interface", + [ CEGW_ERR_IF_ETH ] = "invalid eth interface", + [ CEGW_ERR_COLON ] = "expected ':' (:)", + [ CEGW_ERR_ATON ] = "ip address mismatch", + [ CEGW_ERR_PORT ] = "port number" +}; + +static void perr( char* s ) +{ + if( s ) + { + if( cegw_errno == 0 ) + { + fprintf( stderr, "error: %s\n", s ); + + } else + { + fprintf( stderr, "error: %s, %s\n", s, + cegw_errlist[ cegw_errno ] ); + } + return; + } + + fprintf( stderr, "error: %s\n", cegw_errlist[ cegw_errno ] ); +} + +/** + * read_addrport - parses @in for eth address. + * Valid input is e.g. udp@127.0.0.1:10502 or can@vcan0. + * + * @param[in] in string to search in + * @param[out] addr ip address + * @param[out] port transport layer port + * @return 0 on success, -1 otherwise + */ +int read_addrport( char* in, struct in_addr* addr, unsigned short* port ) +{ + char* delim = NULL; + char addrstr[16]; + int addrlen; + + if( (delim = strchr( in, ':' )) == NULL ) + { + cegw_errno = CEGW_ERR_COLON; + return -1; + } + + /* get address */ + /* ToDo: overflow */ + addrlen = delim - in; + memcpy( addrstr, in, addrlen ); + addrstr[addrlen] = '\0'; + if( inet_aton( addrstr, addr ) == 0 ) + { + cegw_errno = CEGW_ERR_ATON; + return -1; + } + + /* get port */ + if( sscanf( delim, ":%hu", port ) != 1 ) /* ToDo: handle overflow */ + { + cegw_errno = CEGW_ERR_PORT; + return -1; + } + + return 0; +} + +/** + * read_iftype - reads @in for iftype + * Iftype type is e.g. "can@" or "udp@". + * + * @param[in] in string to search in + * @param[out] iftype iftype detected + * @return pointer to @in after iftype on success, NULL otherwise + */ +char* read_iftype( char* in, int* iftype ) +{ + char* ret = in+4; + + if( strncmp( "udp@", optarg, 4 ) == 0 ) + { + *iftype = IF_ETH_UDP; + return ret; + } + /* + if( strncmp( "tcp@", optarg, 4 ) == 0 ) + { + return NULL; + } + */ + if( strncmp( "can@", optarg, 4 ) == 0 ) + { + *iftype = IF_CAN; + return ret; + } + + cegw_errno = CEGW_ERR_IF_TYPE; + return NULL; +} + +/* ToDo: move to common */ + +/** + * read_if - reads interface from @in + * Function analyzes @in for interface specification in format + * @:, where is can or udp, is address in dotted + * format + * + * @param[in] in string to search in + * @param[out] iftype interface type (IF_CAN or IF_ETH_UDP) + * @param[out] d ip and port is stored to @d + */ +int read_if( char* in, int* iftype, struct cegw_data* d ) +{ + char* optstr = NULL; + + if( (optstr = read_iftype( in, iftype )) == NULL ) + { + return -1; + } + + switch( *iftype ) + { + case IF_CAN: + d->can_ifidx = if_nametoindex( optstr ); + if( d->can_ifidx == 0 ) + { + cegw_errno = CEGW_ERR_IF_CAN; + return -1; + } + break; + case IF_ETH_UDP: + if( read_addrport( optstr, &d->eth_addr, &d->eth_port ) != 0 ) + { + return -1; + } + break; + default: + return -1; + break; + } + + return 0; +} + +inline static int cegw_add( struct cegw_nlmsg* req, struct cegw_data* d ) +{ + int gwtype = 0; + + req->nh.nlmsg_type = RTM_NEWROUTE; + if( (d->src_if == 0 || d->dst_if == 0) ) + { + cegw_errno = CEGW_ERR_IF_UNSPEC; + return -cegw_errno; + } + + if( d->src_if == d->dst_if ) + { + cegw_errno = CEGW_ERR_IF_SAME; + return -cegw_errno; + } + + gwtype = (d->src_if == IF_CAN) ? CEGW_RULE_CAN_ETH : CEGW_RULE_ETH_CAN; + addattr_l( &req->nh, sizeof(*req), CEGW_CAN_IFINDEX, &d->can_ifidx, sizeof(d->can_ifidx) ); + addattr_l( &req->nh, sizeof(*req), CEGW_ETH_IP, &d->eth_addr, sizeof(d->eth_addr) ); + addattr_l( &req->nh, sizeof(*req), CEGW_ETH_PORT, &d->eth_port, sizeof(d->eth_port) ); + addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, gwtype ); + + return 0; +} + +inline static int cegw_listen( struct cegw_nlmsg* req, struct cegw_data* d ) +{ + req->nh.nlmsg_type = RTM_NEWROUTE; + addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, CEGW_LISTEN ); + addattr_l( &req->nh, sizeof(*req), CEGW_ETH_IP, &d->eth_listen_addr, sizeof(d->eth_listen_addr) ); + addattr_l( &req->nh, sizeof(*req), CEGW_ETH_PORT, &d->eth_listen_port, sizeof(d->eth_listen_port) ); + + return 0; +} + +inline static int cegw_list( struct cegw_nlmsg* req, struct cegw_data* d ) +{ + req->nh.nlmsg_type = RTM_GETROUTE; + req->nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + + return 0; +} + +inline static int cegw_flush( struct cegw_nlmsg* req, struct cegw_data* d ) +{ + addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, CEGW_FLUSH ); + req->nh.nlmsg_type = RTM_DELROUTE; + return 0; +} + +void print_list_item( struct list_item* li ) +{ + char ifname[IF_NAMESIZE]; + const char src_width = 21; + char* dotaddr; + int tmp; + + if( if_indextoname( li->can, ifname ) == NULL ) + { + strncpy( ifname, "unknown", IF_NAMESIZE ); + } + + /* ToDo listening at */ + switch( li->type ) + { + case CEGW_RULE_CAN_ETH: + printf( "can@%-*s -> udp@%s:%hu\n", src_width, ifname, \ + inet_ntoa(li->ip), li->port ); + break; + case CEGW_RULE_ETH_CAN: + dotaddr = inet_ntoa(li->ip); + tmp = src_width - strlen(dotaddr) - 1; + printf( "udp@%s:%-*hu -> can@%s\n", inet_ntoa(li->ip), \ + tmp, li->port, ifname ); + break; + } +} + +int main( int argc, char* argv[] ) +{ + int s; + int tmp = 0; + int cmd = 0; + char* optstr; + char opt; + struct sockaddr_nl nladdr; + int err = 0; + struct cegw_nlmsg req; + struct cegw_data d; + char rxbuf[8192]; /* ToDo: /linux/netlink.h? */ + int rsize = 0; + struct nlmsghdr* nlh; + struct nlmsgerr* rte; + struct rtattr* rta; + int len; + struct list_item li; + + memset( &d, 0, sizeof(d) ); + + struct option long_opt[] = + { + { "add" , 0, NULL, 'A' }, + { "flush" , 0, NULL, 'F' }, + { "list" , 0, NULL, 'L' }, + { "listen", 1, NULL, 'l' }, + { 0, 0, 0, 0 } + }; + + while( 1 ) + { + opt = getopt_long( argc, argv, "AFLl:s:d:", long_opt, NULL ); + if( opt == -1 ) + break; + + //printf( "optarg=%s\n", optarg ); + switch( opt ) + { + case 'A': + cmd |= CEGW_CMD_ADD; + break; + case 'F': + cmd |= CEGW_CMD_FLUSH; + break; + case 'L': + cmd |= CEGW_CMD_LIST; + break; + case 'l': + cmd |= CEGW_CMD_LISTEN; + if( (optstr = read_iftype( optarg, &tmp )) == NULL ) + { + perr( "'--listen'" ); + return -1; + } + if( tmp != IF_ETH_UDP ) + { + perr( "'--listen' expects udp interface" ); + return -1; + } + if( read_addrport( optstr, &d.eth_listen_addr, &d.eth_listen_port ) ) + { + perr( "'--listen'" ); + return -1; + } + break; + case 's': + if( read_if( optarg, &d.src_if, &d ) != 0 ) + { + perr( "'-s'" ); + return -1; + } + break; + case 'd': + if( read_if( optarg, &d.dst_if, &d ) != 0 ) + { + perr( "'-d'" ); + return -1; + } + break; + case '?': + return -1; + break; + default: + //fprintf( stderr, "unknown option: %u\n", opt ); + goto while_break; + //return -1; + break; + } + } + + while_break: + + /* prepare netlink message */ + req.nh.nlmsg_len = NLMSG_LENGTH( sizeof(struct rtmsg) ); + //req.nh.nlmsg_type; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nh.nlmsg_seq = 0; + req.nh.nlmsg_pid = 0; /* ? */ + + memset( &req.rt, 0, sizeof(req.rt) ); + req.rt.rtm_family = AF_CAN; + + switch( cmd ) + { + case 0: + perr( "command not specified" ); + return -1; + break; + case CEGW_CMD_ADD: + if( cegw_add( &req, &d ) != 0 ) + { + perr( "'--add'" ); + return -1; + } + break; + case CEGW_CMD_FLUSH: + cegw_flush( &req, &d ); + break; + case CEGW_CMD_LIST: + cegw_list( &req, &d ); + break; + case CEGW_CMD_LISTEN: + cegw_listen( &req, &d ); + break; + default: + perr( "command mismatch" ); + break; + } + + /* send over netlink socket */ + s = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); /* chck */ + + memset( &nladdr, 0, sizeof(nladdr) ); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pad = 0; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + err = sendto( s, &req, req.nh.nlmsg_len, 0, + (struct sockaddr*)&nladdr, sizeof(nladdr) ); + if( err < 0 ) + { + perror( "netlink sendto" ); + return -1; + } + + /* recv */ + rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 ); + if( rsize < 0 ) + { + perr( "recv" ); + return -1; + } + nlh = (struct nlmsghdr*)rxbuf; + + if( nlh->nlmsg_type == NLMSG_ERROR ) + { + rte = (struct nlmsgerr*)NLMSG_DATA( nlh ); + err = rte->error; + + if( err == 0 ) + { + printf( "%s\n", strerror(abs(err)) ); + return 0; + } else + { + printf( "netlink error: %s\n", strerror(abs(err)) ); + return -1; + } + } + + if( cmd & CEGW_CMD_LIST ) + { + /* ToDo recv while */ + printf( "%10ssource%20sdestination\n", "", "" ); + while( 1 ) + { + if( !NLMSG_OK( nlh, rsize ) ) + { + break; + } + if( nlh->nlmsg_type == NLMSG_DONE ) + { + break; + } + /* ToDo: NLMSG_ERR */ + rta = NLMSG_DATA( nlh ); + len = NLMSG_PAYLOAD( nlh, 0 ); + for( ;RTA_OK(rta, len); rta = RTA_NEXT(rta,len) ) + { + switch( rta->rta_type ) + { + case CEGW_TYPE: + li.type = *(int*)RTA_DATA(rta); + break; + case CEGW_CAN_IFINDEX: + li.can = *(int*)RTA_DATA(rta); + break; + case CEGW_ETH_IP: + li.ip = *(struct in_addr*)RTA_DATA(rta); + break; + case CEGW_ETH_PORT: + li.port = *(unsigned short*)RTA_DATA(rta); + break; + /* case CGW_ETH_PROTO */ + } + } + + print_list_item( &li ); + + nlh = NLMSG_NEXT( nlh, rsize ); + } + } + + return 0; +} + diff --git a/ppc/cesend/Makefile b/ppc/cesend/Makefile new file mode 100644 index 0000000..4e05b6f --- /dev/null +++ b/ppc/cesend/Makefile @@ -0,0 +1,3 @@ +all: + gcc -Wall -ocesend cesend.c + diff --git a/ppc/cesend/cesend b/ppc/cesend/cesend new file mode 100755 index 0000000000000000000000000000000000000000..5480c960ded7f6b577ab79b4d95cbcbb432846a2 GIT binary patch literal 7082 zcmb7Je{ht=8Q!}ba-`7&h#C>`s{~D^@R5WhCN$cF)v@CbMp~zx>F|dg9m*(U197A}of>WbV6@}lG`2|-JF!}^id>&(_rB!I zQJr=(@9jSCKD+P!cz3_u%|pJ{W|zw)?BEtTf=KK4cqn?<_@63O=+5N=foRW8c`Ox7H_ugbayZXs5K4u<=^Ba&n zh!^4v_PDSvaycI8CdOTe%OJUsc@Wz!W9GA*96QZ@9gwJ`0y-;p!~BHVb!V;k&bNC<`wFK9TZxIY#s044jF!!#2K3 z2*c>^iAIdL<&Rm0AuyGloWg2htlJ1}AQUkYaWf#|(aw8KO9ZWGBrZY`(=z->ie57o zi^fFUiiORH=rMcZAfXu4qU-)x$TCG|I2t!aS8ps7vARUuj0CJG%+gZEY>z(_5o=r5 zt!XqWbTwjb%-Y3&E;*Mj%piS>!cY(jVOrhd5e0=8{ksGc$9~R%BNQQ?3%r;yoIqm? zhbd-^fhl1Ohgi-S4qC<-PE^SlPFKSij#S4OPF2qsPT9m5j=5#vgU!iF<^b+dn*s zQBD2id^(-(f7_ZfwglR-1k8_>q0T$Dy*`|-DnQBfvO@f_OnMnx7-Vw%EQ+O{+mexL0EKFj!B# zQ)2cs*h1VUF?$?rBd(X2JrCYNTn3DII+TC7W8nSd=u}(#rl5e|1q<+V+t%RVL63K= z5#&z}%?g>Z+jmntsuYRu9JvGW%VpT5_D?Lw@5wLR$q85OnfQ{yV>FT+a{Zi?bYVZU zCB61cZ0xl;tiY9g)w6B;@St_Q7(8(U`KUiRS#+cl-2NeJ!Ex%4n0MM!OkH~9_2EO3 z<4O6v2Yu)F?K!`4Z$5r&ADWkc%y&LHRyMH`uwE*gZRL#Owj_;F~(#RP1FwVlGFK^5rr28ssMTOyxY3dmLUO#;=8oqF{0; zC;ynJTbc-+_KlH$+BeEl6B|;#(Hx%_nfb2_v4T1b>p|bSeS6O3@5Pqezb?-eoegqt8l@-@5&F_C03Rs5U zf3@XPXnK}q|18V!_^-7*ckfX)Q!E2d>mN!ik!ax5{x_i5C)+rY>5^AgJf?bHx5>IR z<+DL7vDjIzUY3(nJ^uDg^H2LG0mS&v@H10ZPk55PF&7ly_D$sv{>Yh$@ns&z_{^6x zJ)JA(Y2pFQL;kTX=LX(7`MxK$CGTLX+dEyaqv$gi7yS;3rnZcx*5~CPYoG5Ocq@1P zxl9d7-=r%uEpzjK(2l8{a2-ndCI>iU2irWdTgg|;w(ZzXH^Wj(PPQfYc->Yh$H4p2 z5Ek4KZhZr-#omGTVh@|Y4%?CPu3G6`dC4J9N({CamrOIz%KoAJ1Giw9Rq<2D&!8&g z=h1QbA)(_UTd>BzeUVPvypJ8cE3{<+hH^o0&AeDxFz{u zaf|4?0_wSg*dW(T7ydC=UFdg>TMXhC(*?Q*yvxX24Ia{SN>SB?f2Y%3$XrbxN)&R7 z0WLtArzVb`+;)&(!b(!G%Ncwe1%X@9hSmaWA?jPix?h1>Irw~=IYAYxk~>@W{(Ae? z&0`ypxqtX0oPd&(i^nEDOQ#24E`sk4Ciz=>`efSOpSFt2KTY`xU=!;kPc}vFkLkx= zAS?NrtM)?dz2vKlx9u>t52qFv474%!OqLOH@6^cgu;c#E6 z&^k;lZsLgLx6FXn(Wl*@-+%_0dbh4sHIy$cFV`z7R;|)2E32xit8ctfuc^^iYULHH zmNxksn%4My&45BwH8d>MR_1C9<;|;Bk&dz~YL}cYxCwl8U5lALQOneV$zP3gSnXwW*RFaj-k1 zJw0Z`vIp{ih_42RbH}-tcV+<2uN|1juoS`r2zl~uiwq5EJIF&AKsm(bwZP|Ez$>;% zh;3dA()3T(N1qLY*M>BGm4Q4;6Xa9)6?ydO6Pfz5dAvK)ugRmYp9OCUX|@GPSr>hN zD}??|9@oYQ5?m8@AeUhWgnmsPeL8?bynWbqsi)iv;W}WNYvBNR8q!X?fZ_oNkALJn z2i|kwu|0Nu>?;>Q5@PeX_Fe>UCv@a-o!h)ek!D+|=N?dqj54I{Kpw;QAvUiGye4Ff z$Q<=U9);gXo5%MT4U_Yr-8kg2tqebf*gWnzPh-%X7k%6A;S7)cJr3S+@PaIu2{!K+ zz*Li`;ghMMlXf1dcKUgw$-{66ezo{UGreIrc)xM*c&Sm`j)Y7ghw=`@uCE2W7V!RC zf6szPJ=@2FY8!a+qyo%fx8Vb%Szj5I2;@2Ejd>LA`>e|jVetN81H|MoFy@@uArBvo z5g5A$iWLyrrO(ipo%Q{>NQgf;3flF7c2VGdM5THaRQry?ssipW3M&iTM-*1Q=6<0t zcN(=XD6AZt>tA6tn_TA#%Sf(gh1mBlOcUvTBG3ac+Y{Ze5b@YOe8 zVSed_pr0v>NkX7MDU4SbN5~P2ru~3wkN7Cf9&=q1yYPC)D~{bh7ur_>Y`4#a6Gjzq zTV_1mcwxL1SiU+Sc8RORU5NQM!I>luB7WY%clr(O^P5-Vu)iPJ9zPen`iH$|^o%j=A`wZi9UoO4`w#QQwMS?eO0ekes z1+Z5HZ2JT8wam{14Y8hu*8p=L<#_PzaUHPjKMU}(yV1d?ckt=J4#e>+d?*Va$-*xH zpK#ba1#I`H0R4Fr`1*%E-fk>Kw*S4X@>5xO4tVq@)&8r*m5x1t?JEUt&5ZYacaf+D z=F1iPFyFmUGy?Pai+(|So3qLXvhc1fJOFI_a{=b}ap1c%_K2U%%0B}9C-~c@jJ>14 z_rN~ev%r0s7zXA$TpTgm^E<@+4$FM*z@0HGZY8?9^iI6bHnwlvWVEi^+>Tda!)Tg? zZfSI61)@fGINIS48}i_1_!GMY4t2d@6So$ z3=n54myqu}$Xwc-_bZ0za$dm50de%$1amy}ali3}L;~?G`_Q&I9 zTo_%wM(}<_JRqx=?)v(fhi&yd?$liL4DQU7Z|zQndTe)UvL5LTg9qzOdwX&1G!5KN z<#=bVY|g^dulP=-db^*k;oH7b12gfc5%fm_VH2YzeZ!uo>7kPs2Kn~yEUNw|FiWHU zG2m1g25tuSsLP2n<%Pi?@2rS~Iy$7)P<2hU-i`l5^mZCnFcG;|@7OKme-h-hi~j(> Ck?mvv literal 0 HcmV?d00001 diff --git a/ppc/cesend/cesend.c b/ppc/cesend/cesend.c new file mode 100644 index 0000000..fb36d92 --- /dev/null +++ b/ppc/cesend/cesend.c @@ -0,0 +1,145 @@ +/* + * cesend.c - simple command line tool to send CAN-frames via udp + * cesend is a fork of cansend from Socket-CAN project. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define CANID_DELIM '#' +#define DATA_SEPERATOR '.' + +unsigned char asc2nibble(char c) { + + if ((c >= '0') && (c <= '9')) + return c - '0'; + + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + + return 16; /* error */ +} + +int parse_canframe(char *cs, struct can_frame *cf) { + /* documentation see lib.h */ + + int i, idx, dlc, len; + unsigned char tmp; + + len = strlen(cs); + //printf("'%s' len %d\n", cs, len); + + memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */ + + if (len < 4) + return 1; + + if (cs[3] == CANID_DELIM) { /* 3 digits */ + + idx = 4; + for (i=0; i<3; i++){ + if ((tmp = asc2nibble(cs[i])) > 0x0F) + return 1; + cf->can_id |= (tmp << (2-i)*4); + } + + } else if (cs[8] == CANID_DELIM) { /* 8 digits */ + + idx = 9; + for (i=0; i<8; i++){ + if ((tmp = asc2nibble(cs[i])) > 0x0F) + return 1; + cf->can_id |= (tmp << (7-i)*4); + } + if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */ + cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */ + + } else + return 1; + + if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */ + cf->can_id |= CAN_RTR_FLAG; + return 0; + } + + for (i=0, dlc=0; i<8; i++){ + + if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */ + idx++; + + if(idx >= len) /* end of string => end of data */ + break; + + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 1; + cf->data[i] = (tmp << 4); + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 1; + cf->data[i] |= tmp; + dlc++; + } + + cf->can_dlc = dlc; + + return 0; +} + +int main(int argc, char **argv) +{ + int s; /* can raw socket */ + int nbytes; + struct sockaddr_in addr; + struct can_frame frame; + + /* check command line options */ + if (argc != 2) { + fprintf(stderr, "Usage: %s .\n", argv[0]); + return 1; + } + + /* parse CAN frame */ + if (parse_canframe(argv[1], &frame)){ + fprintf(stderr, "\nWrong CAN-frame format!\n\n"); + fprintf(stderr, "Try: #{R|data}\n"); + fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n"); + fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)"); + fprintf(stderr, " be seperated by '.'\n\n"); + fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / "); + fprintf(stderr, "5AA# /\n 1F334455#1122334455667788 / 123#R "); + fprintf(stderr, "for remote transmission request.\n\n"); + return 1; + } + + /* open socket */ + if(( s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) { + perror("socket"); + return 1; + } + + addr.sin_family = AF_INET; + inet_aton( "192.168.2.3", &addr.sin_addr ); + addr.sin_port = htons( 10501 ); + + /* send frame */ + if ((nbytes = sendto(s, &frame, sizeof(frame), 0, (struct sockaddr*)&addr, sizeof(addr))) != sizeof(frame)) { + perror("write"); + return 1; + } + + close(s); + + return 0; +} + diff --git a/ppc/gw-kernel b/ppc/gw-kernel new file mode 100755 index 0000000..96caffe --- /dev/null +++ b/ppc/gw-kernel @@ -0,0 +1,8 @@ +# setup kernel canethgw + +insmod canethgw.ko + +./cegw --listen udp@127.0.0.1:10501 +./cegw --add -s can@can0 -d udp@127.0.0.1:10502 +./cegw --add -s udp@127.0.0.1:10502 -d can@can0 + diff --git a/ppc/gw-user b/ppc/gw-user new file mode 100755 index 0000000..0d54deb --- /dev/null +++ b/ppc/gw-user @@ -0,0 +1,5 @@ +#!/bin/sh + +# user +canethgw -s can@can0 -d udp@127.0.0.1:10502 -l udp@127.0.0.1:10501 + diff --git a/ppc/res/ncrcv b/ppc/res/ncrcv new file mode 100755 index 0000000..f9e39d5 --- /dev/null +++ b/ppc/res/ncrcv @@ -0,0 +1,18 @@ +#!/bin/bash +PORT=10600 +ID=`ls -1 result | tail -1 | grep -o "[0-9]*\." | sed "s/\.//"` +echo -n "nc listening on $PORT: " +nc -l -p $PORT > res + +if [ -z $ID ]; then + let id=1 +else + let id=ID+1 +fi; + +FILENAME=result$id +mv res result/$FILENAME.dat +cd result +sed /^#/d $FILENAME.dat > $FILENAME.raw +echo "done" + diff --git a/ppc/res/plotres.m b/ppc/res/plotres.m new file mode 100644 index 0000000..e256337 --- /dev/null +++ b/ppc/res/plotres.m @@ -0,0 +1,31 @@ +function [] = plotres( filename ) +% plots canethgw benchmark data +data = dlmread( ["result/" filename ".raw"] ); + +figure; +hold on; +semilogy( data(1,:), "r" ); +semilogy( data(2,:), "g" ); +semilogy( data(3,:), "b" ); +semilogy( data(4,:), "m" ); +axis tight; + +title( 'can-eth-gw performance' ); +legend( "kernel udp->can", "kernel can->udp", "user udp->can",\ + "user can->udp"); +xlabel( "can frame [id]" ); +ylabel( "transmission duration [ns]" ); + +kern_udp_can_mean = mean( data(1,:), 2 ); +kern_can_udp_mean = mean( data(2,:), 2 ); +user_udp_can_mean = mean( data(3,:), 2 ); +user_can_udp_mean = mean( data(4,:), 2 ); +printf( "kern_udp_can_mean/user_udp_can_mean=%f\n", kern_udp_can_mean/user_udp_can_mean ); +printf( "kern_can_udp_mean/user_can_udp_mean=%f\n", kern_can_udp_mean/user_can_udp_mean ); + +kern_mean = mean( [data(1,:) data(2,:)], 2 ) +user_mean = mean( [data(3,:) data(4,:)], 2 ) +printf( "kern_mean/user_mean=%f\n", kern_mean/user_mean ); + +end + diff --git a/ppc/res/res.tar b/ppc/res/res.tar new file mode 100644 index 0000000000000000000000000000000000000000..b01f8ed9e31d565751076d49333856b1edb47700 GIT binary patch literal 20480 zcmeI3*^XVe5k>no`icwqxfRZX9}NFVpxBK}mJ(<{em{#>KHU2_vSA^&1qHYg1cA*% z7FlFf?b^kD`}FR^PwyX|^-thWE9HUzVsF>~L;ToYU7^c=z=7-LG~2|Ni`&e>}Z?^Yqi@!;k-Z{O*TW zZ@#^}IDSOy@jHHQKl&=Z`YIOj*~8IKmPFamw*5H>CF#+y*$2Ke&G8!)63Y#%k(mT8$%88^7!M03;#X;!sYSJ zrIpL$>&rjiJiU7V{%^0JE|2do@$#a!iQ|5`PCJA@lu|>QyA@hUZMSOZDeqQHvuj+) zsn^{XN}hXMo})GUveq)}%b0dwO%oYMUnQ(WttG{pZ5)%RFBD`P<4Q<96}3upd7;{z zAtPjeIon8aw_?fG3T0&5Uo0u@FGK0RmX2kpulHfAE~EIk+Qa^mP+FzknsZTK>>+D^ zF^*wtDWjRZ$eHaqLrU61p1sYj-NG3qnx@F?tdCi^a?|fwsaj`=ea^l`ra*isbTMd`^g18R{i3awk(tV@oLxTbN#*AbovcD z4sn=ug2?igQI=t8Pn8wul&~tZ|C+n)ca$FXS(nBR)hbx0%@U`be62a|-6K8OovgVQ zX}jiz-#WYxMs3o2;IH~d^l`CelU|}rFT>7-t2}gLK&@4KKofP(Qghvqj3eAX|Uv0O}hmTryZqKx0Y~` zSdaQjk>8;2bYf+=K6ADRF{)W0>qQ2mUM;NzG?tA6n%;{GAyivQBldY=E6 zP5y5D*V9M*m+tuQc~0Xz>n~%*|APP0%qPD(%>#$pk}NS2$K(fys6pN&5dLICp*OQV z_yhm4wxBr!vuGT$?Mn<__Eq9=PZNn#@_I35TQ#x3A|Y7VTEu1ZWhuLlh-nyx&AnQ* z3oQxJf}Kt%q%hC+Nuf^jUbJkTp+}3EL~PeYj^@?T^hrA5U`rr^4cj|F!_EQK>x|Gt z+kN01{NA1g44}RO9;)(sWCUFjI0lOpvsWRT!r2-kS~=kM)$6tx>fnaVebV%u@n0I+ zA6U@!Nfg;D%PTDI7U$4i*J)UMV}BNFL!5O>2mefqZ-EV(UV#0k!RTL3;=c3}8enwm z6ZqxGv<{uv+O5Sf5W3cKJN%b=*SdidmUnPpOfzIohL6DZvegAG%*F|gQ|JX)RkV9d z!0>e$BqduHM0Z0Ipk&i1t>$xLE_)mx-D7Xypmrabq2tt$9BE8)6n%*U&>g{}I3mIz zeVwsMdd=iLnuUDKW;vmI^y2y??a?d+^Vh1;Zq^;Cq><{YT#9|`S5{?~TV}91EBU6@ zLc-^LTy#m`ymXo*^PYEBelqrx+hM2Qsz<5Q$@p+La%ZsTW%d=)o~U2V5MpTyck_ z$DS=8kGYv|3AlkhuH;h|imUdR4PuawU@a~kY+-xIq|3)z2w=?+El9@v6?>5XCuC-M zwmb@%=P?WXg0UU&W0vvfKBACfUZHmHoj&8^atFEXJtF)SO;N07=2*Z_73+c`V z;3b64K!e%hRLs#d7-2#red0)^d3?IK0q#pPi6lRR=b>&td7s`=DO;s&9q=2>j0K zB`DN=e_%;YY#>)lR-Gy0YNZ&pq90^cm+s;JoJ}gEV|y3e)@*!LMxJZ{!_u8x?26?; zEX}ZYCzG;Om!`7@a5*Cmw9&bg!o4$ji*Y>83_8bh5@z8n)W?)|54fRfk=^=j0^jaA z*$&*+F-rz$$d2;>SE+BzCJoY;W&gCQWlQwwzH-w%n`o6Z`H;sRhU}RAo%9m9%=(g} z-K*w9YCYChr3w7Jv*jeora>I9pF@8$oXU#|EM2IG$ZK84qA{j(e5zZ#&xwq@kjnwS{;MX(k?L%B13md`N` z66LTq$Okf3wV;!>-(eiJ2J5p5(^a0vwP9XwjWZul1}x7;AGmeTNlUdFJj<|Fn^PVm zcl^NitE}1>G3FfdY*z`}n=lS{B6*|9C*|Swip5fjeV_$e+vBL8#qA$SLc6dpYw6+} zmv^MHzbuj(JuR!%<_3nfwX7=L@g?;N<61eRYO_G?2>XJ3DSIB{Xc>0~_M~9B`yiG~ zXNVUawi?(D$yoJC zp;2Is*GGwWim%+yBzBH*h6A|SUA0>#@n`R#(PJEp_!O48YEUPLCWMkR zY_*WhRfF=UTwb9GW^vw$J(%U9YoWTe2eE-TEq<_9#?wo)+(DKl%SD2)8X6>DI>xOz zm8Y_nY2IgWDE1|`YPx0*TLK|~h3+{!6%89lq1wh(<7lb0B)=i>R%NtHXD6$&O#e&czh|!g zekT6=SpUuO{{HvYQ16rT-4y>VifY?4kzYJHIEUiN?pt}1Y?jAzW?w{NLv>h?ED@UA z>YM~gQ01PJeB6*51wHdnxH6NDyK+y83)~)&cPL`d;;N$GQbeNx}qFlI(%%ZC9+O2GEt;`rd^dj%GZlrla_;@?{K^4;XU|fA!zY?QW!wHLBUDAax zkxubrubQmG{4lR#Gz(MMD-w{+2`%xYSay73CRq!faZA7&ebo?^l8#o)`z$U}R(3iu z2-9YM1Eg(xm;iWN3yj}xLDkuP$rCbA8YCxIyr9oskJ5sz(;o1PTG@ouS06{K`-!f3 zD`?{wc(l+5{`;B#Yj^(dlYs5U zKfEFSD}Xx3aky%EZeC7XOd*OH7XnLeOd43m;xgQzqnFd`4!C{e4XC}DcgFj>bRHP_ zS|Go+B~n#UZDH|o#&7UO%+}H=i`lqEVrZ6WZ~Z~3P;k2srob|3P>A7MI5+cwXvv}^ z8NT^I3aKuAI^O`pXt9quEh>Xdtp(F+{+MxwG&mJy=ZiZtuf8zQ_Q3Fe_AV0c?8N)> ziw%kttLVACC3Awy553_3d7gc=(2>0xVov9F{)>;32VT1Mv*mTRG~cN4+NybnX)Tcc zK0neCSWK;jvgTgr;s#aiV(*l0^d;p=-z}e7pS=czm4*6MA281L&b?D?fZt%y~2X2d`x|0A6u+r;;)p5~1J0Zbu6=!2=1k0E&B0iwSkS!h0_J62^aj z30AY;KA}ZPNOMv&+xuN#nk7+(GtPE!yY@QaVN3$1iFnP)^D&nIai~7-xz3E|T$XRn z1u2DGeBcQI+!!XmZ=0Le+$n7?i>FDFi#_g4t(7vXGW;9DE#Spnu?FGk_< zcru_>H{Kr}EsP&Hf3#L**ecq{GcUxk2kVt|-B1Q-mMSByHOA^VO$qmLf zNHFL^!IlVasiK0lmbTi`m2LS|eioHltL!e_viqY-Te{LN3foebR@z$c@B5vXdrvO$ zrLX_bZ~vWS?#wgu%rnnC^UTYcnRBMCJ`%pItG;Ne_{*7KFjz2S+B5+-f5!A8y21P+ z<h511d%r7X&&lk?LzZ^?(%01nY`Yy*2ZCViVn4!L&?r>N4(4hYb zkSX@mhH%pzf1v`gg5SITX9V%5>%X8dh>8#97Y1h(3Mcp%;%5li|DV_Y+REzrmdA>V z#3M2QSOMX$gIgrT;{7tRNI1eTa>XPu5pWXY0@?x{prql0$A+ZREUw< zn+kVSJUHe{*1i4B`E@ja+lb?YuT6C%18f2>AQs*%05*U^*J+ zMP8UU^CVB?*OZ;Svg}!3`+D}hSz90Y=2z3pibveNFMr^+`%CwJt^895USIgsuS*x@ z?T`LuZdSfGFKg3VC0G92SCX@~KJ)PCb-(TU+E+bKT=@25Pk;J1Po`wuIqUhp9iIq% zHGS?sjkvpK@V>c~PxL)}-L{PNr=u6Iy6S(ePF-<5@=7!@SvV@@3WK2G&j!R5b*PS3 zRvg?E!2R$XRj~LR;GKYvX!sj|52LydX}AD!G-czJdkXPq;C)BO-xd(gZooE#4mnx5 zh(8W^zlyg40Wr28aKFaC6R-n#vWAZatcf{*nV!1zW5iR=vvvF)z;%H4X?mHUzX$Mk z9lrtbLFB9R6W;^9T*Pa77KmL@gLqrxzYP2`SNbml-ih)y>-c`apl>y5_yxdBFBKo@ zs$gk~wLG2${VjmEX#D$u575d`uyq08P6X`M@xKL3d?i1$&8CKiP`7HGp-@v>M|+54 zd?XYSp=(!%7KfW!x+CGPd9C%`-QjK#3U%p_(8{j*ws5GWePsti8^gnegM0%?PZyyD z*Mn|jOM3`YgGSNa(Xc8U5#5ol_J+1j(b67{gz6(5?V>Z>)z#6Z0@@=T^$Ml)PSM#D z=_b$`ZWnFgwr-^E3OB5#zX8$R-3|5aD@8{qcy9t8_~{Z&;RpgktsU)6qGe^M9sEW* zTG|`Ky#%EPc_NgA8=AYs%FeEq_Q*=n9d2)obTCx06AG~;S}<+(E$!l(>IGNN3l-!Q z#eDfOUl8Jz#*1Ene;)KU7F?f(O?W)SBV&BBS0bhmb+7^0vJovUZ13pvteFf0%>D&E ziB+Lt;vtQ-2reAi_p$$DxBxy~^q(p|U`^NnKWPf3`y<$=&=0-6Q2Qrr7b27WEy5@4 zK(}N3JCT*~KMp#^zZ)zW|C2&oX8e1=y7BJ?HRIoh?#}ozW+oZ`0d#xDe-PcL@xO%T zY5a%K)Q$fzx=7gQsX~??$h{BV%RYL)96x-{|ts5<3EdG zM*6pni=OH8d!E>0iHxn!3IElP3g6n7JWtI1k+5d{XiR7S714L5_6t$|i11g5OG>MR zHK|HmJlGHXKEL;g0i-D&CjyK5>6?_+TRTonFGhgM!^=EGDXQ|G-OhH z)-0=8H%HiOR$bCL>r^zlcH_CSvK=C~I7L{sDS??=u0ULARoV0K+V6gT8-K-ngNXKOq7KpArez?&>5_&`}R2fz!;>#)4!on@o! zC=bekxQrux#v_jd#9=lUw=x@j^dV_9a`pDrH%lf zLTEnIO<5B2dp}-~{{hA${|d-*cHi8z-YsiI=9WiA)|PJxXUmU8&X%aiT{lKF6xM!7C47SSkZPOcJS^E%`^gf{5)rFk+C?*~n%R@ie8@86RmJb=?(uwXcNu;J!1 zul`3x&YB4ed#gmoJqUYGeo3G4TT)OS=p%XQhb4`5^%zjoge~j%RP>!S^~-x%e?~W{ zlhi*gGe2aO4w(fYvy9@gsQ0zt8(}DKpfAbWTYOyD3#0E2_SKE<{bT5ZFTbw)J}p;= zF!Vq7d^wNXi+ue`&KG?R@?B4ybuANfOj^1nlP0`VD*`juOhUau25TCY>v|e@fa%G% zrqKo(Wq%-zy?wq|`YG=t&*5}17xJ78c?Na8q(h#$#rcd(fQ}s2?Y0OyIN9B9 zQI1Tu1(uch^ruXueu(0haYy@X=;2ObLx%t4E(_9RA#V@c0rK`EtpnLDOGtm*mHxhA z(pw4XGj%z=s+_WYIiT-+K-q@VhghGaW#osPGts`X(58MxURYl8uIneDbs!hz*vs;< z&l;R7a)6Tq9M%K-D*8R}R{*b_iK9ms`zF5V9P z1|PZL+b)?aE+DNnIqVNd{iERn{YDnrfsB*-v2ol<=tiJQjNHYvT3$i$5~NJEyy&Ow z8d2uc8<0=!m?ZYg%!_(688l`82|Abct&(!g-3j@zzwS$g{vl79U(2{NYac%)<+Enx z^4>MqEYW?<$X|l?mf>lR__nU=bdxvR8}fRJ;cJ|eHN`1%Okq18hNlttB=S@eGW?A9 zv%XBf=i;Y+NZLL5&mPfNsYh5*c80&^(4BHyr%;K@$ zTUa;f*92sbHaB9alugR`*(GzcH<#3jnl;%Ad)e;RgqNfKM*L&(*zC>yYqL-GgTBQ5 z;`q&ae8Gd$h^3Un_OZf&e4N^pq&X#%qR$P^%|6#ZHv8OF{i3M+VGHdc``ps20y9-! z*|i+E*R@~{#(p9tyO!f(Uy7U?vAyQj31NZX+=bETdJVIGAso@LN5hR8rY@LqDYs;< z2pSz+82w$Pu0zunIfk)ML?1PN`@-mN(2uhYv(Huu-vQ90&asUeoW~bN&;78(iAGT_ z;_N7y>%9eSFOx3XUKVsBC*Jmcvy1sD9e(#$=bI*gCtRnkDa@!rDmP|6;2 z3Gm(GqSL48yaZluaPbmAILBE-$3G06aV|PVn$BU+Ns04gzZ9ow?}xr*L7ruBeS5}= z`C5Ofv|A1NmZ98oOw+oAHjxH;VhnVlhIN9v_m@8`UZTG?&D4EP?$El=$#vJg=I!Xh z=-X{B-q^;=ST0kiRp@5oWfGk_-5I2t7B7eQ?D^?@YtYuqh6(>R!gGfSXWu{>Q&-L{ zjQ;xHit9uGW%i=|K>t(2c02@=0;7+drR;jRwYv891iKSAj>T36`n1$Ze}z7xwx#nqIj&g&(JE~=?KyS z&J@jOCTL_P(7>4XtKY}v=Gjjg$S(u@WuPy$*_X0Spxta^80#MK?DGTYhh-lFx{9|) zL=pXcDerc!aXh_!DWZn;RwevWpOru5DJ288Cr|Zz;LAEzvd_+;Y}DK)r956rCDnP5B@XAqW-G#<(g{R-f0K6h~(t3khb2KifP8<4LI=UA76 zbe%emeGha)#vwmBSEwb;l1akum-5c;1AbXTSUSf&XBPl7z{8JoR%!4&q97@NpHybIb`gNzUMqvw@H>6 zb0m?u2YL^G7UXR!-C})7*v$Flvkh=D51q*8Y|ee1J|PZ+X9sep9%NyhGj#lGH=*39 zYvLju=D)+H+h_7^2JIp32()X(sCQX6{Yoxb(1~=Gxwzk(g+9qzGjXAQ_B-={3rF|W z6364hx!r}6;iBW!IG%;kGuLSxzboEm{KDuj!&+_*a6V|BeO%8Wa}u9pk#-1e^jTie zPFXh>&qP@GVqGww52)MYiF9@P%XM9Xme+zm$xUnM+)Awj4fm|AX-T~phF{9*CWZr# z?KIORE0?@~VYzU!TsSUy|NMt;{)Sr<(CY$Hm$^=cb*fyhm4WY~t>Z)n*33Lx%dvL# zqm8$0truBX*K+zkKDrlk_nf|mvU}w--2SUjf2Z#onA30fU(ql6E<-;(=91gX?-s#X z$A!4@cwpw*dEf6vc;4E^*Lv69^Lp>BDD_dTVXb}iB-gKw^&`&#^yuZnJXbzyYNtE-~hU)>bl`RbRWyI*}J zy64qX(S5I_MGw4oRrICT7Df-hwkmq`wN26EuYEas^0il@XI?uMJx5xDuSE9^o{H|j zAGr5l6+L+W!stu)uZkYJe^d1E{a=nAx&M{u(fdzDk8Mqh9^ZOZ^u*SM(UV(OMNelN_z3ix^je7yp`UeSE517GXF*WJLq8+_djzU~HJcZ09H!Pnj3>u&Hh0KNvm*8un$ z0AB;(Yk+fo@I{^cbMZy}A#bc7v!?Xt;E{C6r<*R@H`f^1zm-hN*#bRFhfZenr*Q2y z8pT+aHR}ze(K@t#tO_rCBzmSFc+iz}_u8eQCutzw9f$5f8m_~xTQy<(nilo^py3?} z@XiGI@dS8x0{mnGye9$Pn*i@ifcGcB2NK|e3Ghn^@Sz0wZ~}ZJ0X~`lA4`CbC%`8X z;FAgP=>+&p0({oM80YF>Z-HF~TMJtQTMb(U%XN-2*x9hfutl&z*vYV5$H=KeExw;E z?Z;aCsxzWLeZrQKRmaPyJAG+4XRO;iVcVLzn=`PU?z~@m>Z2ZahS^u}Wup1{sC%;i za_u1mtS2z*zaSV8ql;mSghyEQjg9q@NLQ$JrqdSg?yheNJK^4jaJVtt=&b1IX>W8o zRyq?JQ&A*ox;uKh8p2LTm(v*Tj&(MCv+N`1>>Cdp0*X?E+KdDW;zqP zQPP-yvVvz$XzpR*dm1~-=z<^VYQ7~rVai9kohfr1;!Nmfid2bD|CEn3_b`s>m;o3O zD_eWIn?b7;`=+Ex7kic>AjUg{wJ8UjV*t4G0Z(?pIBzk&2rzbkq-oV|%qgE=-8!>- zW+OKRubeVPWpkz5kNT$Ay2<(waRR>^n8ak5y_8gieIAM958HK8Eb?NS}YMWbhmV9TP>pYK;L{l@duKsh+?%zc(GwYPb2Tii zk1xjNO1U*UT~XAj&nfLZQ8*zi1)NfZ!c55OLTeF^pu>|xj= zut#B!!5)V_0ecemG%WHRdlvQ_>^qPN3h6*5jvp4Xassd!usHAGWHBGOpyhxTHY~-s zAZ!(E9c(Y`HrUSRo1y91JzHK ztieo!mvS0==T(XEBfo0mF{WU@C^3H2%dvQ*w~o8wB_DxW6YnoW9Ob#5t_yFR#oz9K_fR>}bh@UJwC zxYR}Ryax_l|Dvu}TA`Mju#-K23ntoS?0 z%tFb`l?<5L+|d@E+SxL-v#aAajv+Y3*WS}Rbwy80Yva_;jyu9#oedas7}mtIF;h|I zsSRC`mb@kJnYg>FK_O2m$eY0g0u99}U*Z(x=il)g^eUlvm885%QYx^?t3>2gBC?f;yh=n~Eg}ecyO$5J^(6X$mnwJ< zqzPv;LXva6pMtl;XD27w$yDXXR91JRW_%^veN#Z71wET*s*N+CLfq`h7VPLAw&l5) z9iD8Pu@~DGk0%23157TkEuLHim=4gt)3!1d7y#&f%9eG6*bIR7G26Oa#byGuN^PlW zh|L1%X|yeNP5>RI{f%v1p}-u*PPZ+d1w(8uz~nO9auhfjpl_pXjR(>fJlR2j;+wXW z1Mn$Nb`jH#x2=f?MTxN3CTwK%5e3d>>@M4y4DjQg>@tF#wiN_8$CF(F&^l>b`2edu z+4Bi{YzuAE^Ry@X8i00{ZA}OGf+xF*X+LjUbAi0slU)Na8Kl?^J?P0^M(_^XTA;vN z0Q$aVTh}VEjm0ssT>$WH$q}TWxvb2}NjS?9;YYgZ#eh$?oLn=DWh) zi)!@VkZyky!C$~Ymwbu+485pDK;CEU{eU14o6t|~1E39JenD06bV`NzVmbmJ1Ng!S zc+fk^xE2%o0~vay3jHz8CyK`;!keRzby7+oX%#33nf1#_t)TJ)m38u6N$hiw8M97K zO2WYE4I=9R=FKAMb`_T{$%>nC9L#sW?Y{~*O&5a5W(&W`|LMW6zrl-N?=3uiXeayd zo3tpEEiCzw=ALySGWP;lIxRSw?uWJwlhr`(;_85i$4~ z36CO8t38FYggNkfzmP(m4uZV>W_s#4IG3;_*QJh+llR!E*%Ck7gE-Htsn9>~i>l1l zl++0d@^cDde?E{p2~G@2%84 z1*Mauzc(Xw1xVgc#5t)A-~{p(fwt}@k=jUxK~h{~r;S3=t(07E0Ke8f{7w4g1^D&t zypaCm7va}mz!R4~@5T7F$6dnTt(gpY=Q8|yXI##ZUuWSr>Ew9q= zev`AtZ}w`UroQ^7N`_{uKQBM&;qxdNqjOq+mY7 zUo60{I9tTP(oQR(eeD`yAq1LOvm2$3Q{49 zeRkR!IQttNblNQIV8;oIL&TdN=s5j{uJ)1W>{*Dz{I8gxg@P>4x^vD@yR!)?NE@H(6+Qk6hzgx7o|O_ARi!4TG~zpv3C7gX}c7Z49I&Z?Q?+GNT`cR z>(V)63BqeFAF+{4vCj9~BR0X`%LL&Oo8esy22sl+QOik>qR_r-S@d;mL%t{3hOE!A z4f#h<8Af9GOybdG??|F0ohDk+-xCdoI`M0Lg-y--oKIw6G_${AO@bqCR^wNi13ygi zwHLPw3j=NPwVuIc7#i%46N3H?-a_dA7^n`AzlMHlS01ds zv@23CtgAq?#xqzYdj|Uw_BFn(y&686D;<5yK9nUk~ zENd}x?+vs!3u_4oqbZ93rh`^3=1!g!dglsrqZ38e$AFQ(>nuV#N&t@0On&C`uy@UJK%BJSu=pZxyLzZ=; zE(RClGFy@1G)(KS7zZLdE$gEo0x>QFnEZkS)2~2D#-d8)!}iVg;EsJJ2PmIFz)l1- zw4tm@1?|D@`__`DLzdLS9roZhVBnlPFrbOzF?(=}#PEeJDx>#%_Tb~dz=I4hKBkCn zMnG5ib_9gL_SN>_9t1FtI&k)Fd+^Y+%)^>tS@mE)#~wT_1H^Ndg)x(CZ9szdRpfHlzsCN_EpPv6CY zEw`*ypfJlj_|9G9QRCf~^|gSwXq%et?9gpBeVS~mW2368d0&jh|8cKlDTbTRN0e(zYXd+h9w6;RcZwbzK>ZJW{k3`RP|mBa`q*bRiw#X zhGm4yt3dA4AaO*KD|C|sAjwHazG+#Lb;`@JXmI&vr2Hlxc1G%ySGiLHh^6#iWm)4* z%FXHt$oeT#R_T=E+$jO5lsORie&1Gz`(v zH184XrQrMm82$-X2SOqeW5PQ?zypg1)KD?8z+h zZ(&c26r;e4z{@enQnDa_RKgROVEfNlQxNw9%L0(%wWcZnzv5ns##>I&_`c3k1jLv_ zcogogUyW7i`15dU{hdu+TzDV$p?XS7Ve$0DC+miWp&?V6+I#pu9p2d)=Gj?2#(S5N zlcX+i=KRr*@$GT8&szid;Kz9D0&Bv^i_*L!M~}R~y3h(Fp%!vPTG|{0K~&m{db5=m zf-Ay|YG&H3v;`NUNQoaQj6@!gbLm4`xV~~n5>6W$NBBmHI4xCN} z$&rfXQ4_&r0LXq-9wJ|056R@hTx603<--&qo^?i^H8)*J;mY&{7g2I$NzCD5yf>tY zQ8bqT)UqOYDMaUr&6MTwnetpFxr5v;&jSk#y)r#c84D_IQduz$d~U2UI)BK78D60i zX>hF0UxSXDhPxEwG}{_)e5w}o1<=-P%^b3IC&`JkH#dDYTI>XO0C^c!8{+!qHPy$O zHrfEi@a2iPsHHeSD=EhL5E&)A#0^FE$60{3q(K`mL;+H@5TG0$AmN!&X;-?^i4jIw zMveo|qb|0tOlQRgd{W6Th?7*sR9a8UL-aneC4f{m`yMgIwthEq1jaB6tO!^OJ83PE zyaqthsKv%5=b`;k{R6hi)H)wC6F&6Vem_Q%aWLcgGj5#60xvSgsq+Rc1|dd;3j1c+ zU#>i#nV#;hVY)l?byMY9`qULI?Njse4FEd>s&(N_)5h@1Jj{cI;0{AKyl9dbqgy)Q^$Na=YP{-wR2_^rV7X19@YVaU z%8yypl-AbiMSw7E(c7#5(1~|NhJf;g+6bbMO-nmmbUk=H#qK%SYZjb+$yS(h+M8=V zI`^sdb9xpo?0K~Gj==%%0TF4MQ@zcf`BQKD%7KFQrR58oZdzShc7N&IQg2$MXU@*j zik?>turQYe0)dlz8w#$Fpz<|Htj@45O3Z{8emfia~fA)3P zU03>*(m8WV=X|BKY`^^Xj+h;sIyKl7{6Xp5^`&JkEiL8EH%&#z{yC*(1HcU4j0A&o zpDDZUo@Z|@UGBeb`SRu7u4Uc~|66lTmU>@Z6X^+-t}k8QT)KP^W_79e;z&)%AuR95oVUCq zo$RI?$4v=hwM+82Px6Qr_QYP>J!@p;$=Vxz+FKy|Q1+v7-QGs$+ zJZdT7#A))8RP0WWL86>71GAd(gu|6pK2harxETJu;HM&`TvR>csoP;cEVyA=!9RMuX%w7Pb|yz(Wr==UX~$a=y2(9%T}mGkj6 zhMxTCk}fdgbT#+Y3l=SupIIO)+;(PV1pRhKVWVxaPQwF|CaBtokr^($J#6f8f`K-7xLYLx+s)mh&NGHs#m zh7KGKW4WZ<@v#Mg{c;fRK;g0f5?a|>--K^Xu;BF#t9m-)We2(1`3tIRD;Jxr4QRw9 zsWtR;g&I0qd)nIFH7bt;EV+K(!qAf1#g*mPK~lH(;J5&Eprf_X%{2t43&^29B)O6q zQlhG?CTqDmx?56HIZvsS zJ~Kx7A;ZPjFRiUKxhr9^ux<5Sn2!iqp2Zc{iEgE_Qlzm15URD|s~$L)XVx92VvaBc ziaw?3j;WoU*t$m%r@%wS!6^#TzM~7rAwp~rp>C;zAz6g$%9qIsRQ01jwjncYfu44D zbW3famgpH0X<;2CtSV56zVe2e@_7p@b?Z^b<#b6YKb1j!TTAPmL*z5B9QxIYS(8M- zxr9guYFM`E5LZ8y(t!Q84ov30=4KY>e)?5}0dKgn1 zCWGNcz})8>r4=&)2Z~lw7EG>}ncH z&=4L@mC71y#F-n@pRiS{{-iP7+R|on(k)G%B-A}aHx{j>8fhIO=SZz&9FyMCMGF^Q zf1|48tIL;EiXL?Mg#{3>#*dejrC3lS5)T43u*G1QkphSsygU=aEUm8K9iY3G-E z3e2~3Kwve#nj^oK6U%Sj_0{OzjLxfyskmk_de#^USXxqkU8Rx&+EqRBmysM`On)N9 zA?1X+j!7Fst?UrA#{Zd9cg%KoF845PDbro$9MWz$TIol4Ddn zxj8F_X%yyFaw(hBs|?}2{Q$!WJIVUq>; zjR7od#R42*@78qT5xzva2*56_qzgy*4g>ixD8VC=E5HN+V-O&ct0XcUk-SXUw{Lj~ zvG8#_(*CrB3_9oKBiBoGIASFDB+qcgsCS0)3>cGji3&#qa8UMkN4g?#%TTca7J)j2 zS_d!I03>QN{CFUBR|a4acwC`A4)0!#x>xZ0wvvEi$h8{BZX ziDTUsi-U|+Y^`*J*eSTH7Be~)JK!=c7;25h3DF4u9>Gl@W%#^BAD8-Iu~*~N!S<`z z_!(rxmBH5XoF^=5TA6YnxDkvobeoM2Jv9y&iaeY}59gI% zy(>#0;jLvNh%(Np?AX&h$+8{wd?A-FYS9AkO z{_xa1$B?|n@QR)$H2wPaCVWCogPlDq*qO#)`5`rfx&j0DYJ-V&udwmUkFFVj^AMc^ z^9SQK*-&I0zFSuGM3BuNV6dAmYYI!dvYROa%&jtG><;7C;^Za&U~{~9jnVZTUPaSSli(h!H1dzsj9As$w~q_qyigXJ&D zH*o^6^I(YpJR9+}a+@7N(wK5AH0ROPS#)_G9ft#A`Ere&b{X*ArJrZmksYk4gJr&q zXTCH|u=Eq}AfjRAxqWvz@GLEEcj27`9<1dcjCedDN*cub1T1;Q*?gYomS?)z;*B95 z%{o|vR|h=UOa#RYWkU0Juo};)6KKnTi(!p1^zK6d@lX!7Wm+%#shBZ%4S?A<$H}GJ^aUBLn(ndXre}UEXCTzg&6|B@tIMOg* z+SRZI4>FeTSJWZQ7{lKY1Q@(?z=IXJ1_`dgdli1>5B?@PLeR$I;Enl@!*B3%G~RIZ zehNHOc6cSdyWla##Qhur#t-kro%q=UYYg+E`8}))@5&m$EQ>KZ&SIbA!s9D=fgc;B zc$_>h?ZPX$5=Czs1`pwGdb2-;YW&qOc!fjp=B-CE>Y6cH&Q=)$m~T);R2E}L5ORze z#=*)n$}avEVYc9*4jQB5@3c>vxg}*bLY2BoUTkj+?5l{6(|!_` z`T!W)!V=y|7jOn$)z3)yVg<{-gz-2N$9UOi5azf+n7TtaQ^6A*4fE6#;wR>4_;R|& z0H0%j%mB`c0q_7GlK|tmRNNq*Ywj@v*ogt~03MeBk57QJ6JW`w2}Ak`@W=Gb7SUe< zmUT=V4NDoi;44s{>j^{ISf4nvlv3e>uLoS`f|mn6?1FK2EN25@WX$?pi~8W0M40t? zpQ%s4tj~u4%lZUNUT~6h;$*nQr@X%bIOu}E4YQzhiQO7*k(tHwi}gu5|GV`&gu?Przpd>kkCZnA!18=C0p1UIH)#SN z?Zf&uc zU&HH$enZ;x0OH?q;qL-`+C}dvoKc&9Y$0AMX2?`5F34=~?|ApVtrHv`t?_flRgpO%*w z^2%xk%(o+mkM=nFEMP5vFWTc6wig3KUSnzjYk7I^09*`Mm)Cm_{L(n`*Sk$YNTA@| z>O8fj>)VS{dt>$>%H)3#=KEgJrr84mzsJn%w)vcR{gZ|^za?*x2A z;oE6|Nq@VB#~{Ba0c-y4tMsYuV~7VGdj{w+Ud!8_2R}{Oca$F!aOyO?Y1~;?E&o%hQLoiLCvA4L@4|Hv-o6;lp9} ztO#JO&pzl&)?~n@JbR&^q*tc-Jz)A5)CbG+Pbja0_*xzR8sH4Tx;^{Qe~)<_FyHGz zefxd|nEivUuOu(>+YVUwUrD1-evmfbq)(cN_#=RI{UjA2-T^!r^k9-I00$v2UEfJJ z0e?0k41O5-?FF2v@=xjp+zVLqn*{wCTLxI`YtmMv-wjyvoAfB~>i}!{B|W9*6Z)I? zN#8>H8sslDKODa(Ka>BD0VCejN78=*pY--={3!Axtm`Wo?I(-)MT+0#O98(G*stMi z&-brKPXN~POuoj{*99KdS8^@J56W8rMv~-u;FF#%Z*m*zyBP3Z zO>Yh29l%&b$M|bPmF#C@N5C;J%hUfXVAf}qF3%z47X<9r@KMAs1FZWCKl~5?J1D zMo%BQqQmuDoWtX>sYuVtmGI&wijGiIYsZTE){tDV4b}JbV)wSSH8gyby2YZgr>*Ty zh2{;3Xhd`402j3JUcdvOCKy4=*<_bs}8yC24#a%Yu<>H3b_cP*Ezpbjt*ore2vU?nn6&kKM#$wIrot$9ic~ z4#Q!-Tm9fSvS+x-Cm+0oupg^64kWO{yz)F&WkyoD3~|#On5k5Qp?5~bDY)A(D=o%G zK}>Zebq;lLwq#|SyiBDrFWE!JXqYOLf=02JLi$lGd5k0$pd%%TB6(j{oJCg?WRo?r zVgGMrHpGuUBZi~<4_Sml)eX0Go<~|nyQ)`>-==(MQo1vC^#vvRx~?I#3_I*8!g5Pp z&PmXUa5^;3tnMpiVcA60F&-m}0`SbqhdDMEYK@l%g#Tz0zyH&`Ww9!DM&geqnvjt9 ze@<8Ty$*B#Yr*vV{6eAbf6Xr}EW$mp`9+1(ivD*0XM!02BH-G@`#&wYKZ9j)V=k_f zK0f{6`3#dKU;rw?5p*M^fy0kJak&_JCwdv z&--%l;Ei3Ysr`cAWM7X5S8Hw^79$Z>+>gT$4`Jhf7C!m#MUk=gbEkSqqkoLpM*q4} ztE^ER5L*DRnWVpkY;gL7jr1Og-zUEXZ}s=_8~#X-IO%=@50QZRu)HNp_+itFk#|4t zcj7llp88E2^BTNL#`y>Ft@5p(6X{!D;Jqxun))a< zX5Rc=FTT%vhjWpsYNwXS@t{?vSNKg!+@ zsY|i%;P+!yr#LBk=Bj>?hC2zMi_teBkIoG??zyOo?nE0I0~ys_b*~s*_Hgt>@#9$N zc@b_s>ZKq0eq8CZl4bPZx^cK)0XhXans4WOA%`b%C($(W2HF|3;TAXOc7Xi)@eOh6 zKI&P1Cpu^#0sMf^J+8Ey<7ur!Y$K=}fB#0*=T32$ak#hWPJ9c#6EeV^glIzt$YZj)vxwj0 ze^K-o?~F!g9Y;TwhW=!nx+h}~z6;Lu#o~-uJHR_M-fbj~E5BP@e7M6aAfL0UZmi;g zdxcHBffLB9K^*+t=h4sI`+D!%6TjBfek{6=X}7*B(~7N+2=Vl@ z!awVE(2%- z8&Z#hHtx2<9h}gWSqIK2{Tet^hI=M?A5nivHtw1bRk=a%-zOGKDSIq>7Wwkt7K^l) zuDBtk*U(}3T9rN>_n91%JR%J79_B0Mpwlx>!r)h?({e&T8U=jBq>ZH;9`8x=0lnHl z8tBvaYk04ut@A+m<2wAfJDjr8>DH@wk1U(a8$7=U?y~ogi=4Zd`quPhA6g6^WBLYN zdJlao(|!5DXUoL~)>lax>M8~0vqUcRst&prC0Mj-{odjO zsH@{5uodG~i9lOJe@GcX=K`G9-1Yi1QkMtbLZA64^i9nNdIzGQ2N?Z9>$(J}^wXuF-Pd3pw|q{ZfX-l(&@aXpsqi zif3Y6o(2B5j7EP`j{8B-&fxd2z5n%I$kGpg`pk&1A=_N|12cajYVnCX;$+Nn#2D0v z=*O%ZZJy)c@CVs7YT518vg?KH_6#Gt*j(saD0jbC z)MEVa-4#}MJFc4`?0z3)wob}0eQ=xzpnm-*Kj%tMpbpO>%@)k3H}l>k$Yxa8|BjwS z|G+!;SSA7e6VyG{cb^)cUSj{PaqQyfM5fkBQN9DT=0JZ{yagJJ=bbWsj6;$J`%B<8 zyYSf85-%_eUYQGz{jLXi{$cPkiD$ymUvPfGJ1@7Bm%jC9g4)J7^dN`B$uc_?#$zIC{GHSj*K=q&CRmrH#;uJhT6JQ(+R?|#H(79UW0OrB=P;{u4g%pIrOoV-s1yad?ZT3Z^z z?cL$hYig=RW4IG*Y~7^-FPOB|H?=gB7UmV@6-+6d5u8ytr71tZWO{u=fz#O)4!3ni z9K3mo*XCL~>Kh%5^)u#}Z*k0YVsE_hm1?I&URBZEf>+jC+8y~Kaq3Wf{rY5mS2u3$ z=<4d|N{Gir3^IA_{SIekN0-V)y}Fqi`w)nL8N$o3X(fa17i3eu3!XxwITgr2gVLY!!nUBix{JhL% zBST~jxfQzVfj42O7hjzQEJ(^LPFB|AO<8ph$`D)@^TXo0=;A9yjjUNi_PuDHhc{zR zq?wDP-A;X17=>rk}B zr=_3kPPFtp+QL!BD5!z|=Kh5w@FDJnC`Z<=cjP?p_l}%=H;(Uj$?x$`!3PM`t8VJ8 zHu=_DxEG(Malu>;*D$&%^|G0I@s01`<>wVC5}{CA1HMs+SF`y-nR!Y|rE%-Gsj2$#Aq-xGkl3`dxGw#68Omxlo3hxf8hG@&QqL3@*V zFfJW-4y=pbNVGoz+?X*mIE6BPc*keqX9q0lG2GBw1iy>kDDWpX!y02~EI@$q!#jQ- zes;r>9?NFv-2^}BX}OF#0sl3y#uyqa5J0>F6%m+>Bvl3pF7X&|-c8c<9_rq%bGTuwCzM=87US$*mb{o>5`3G3~KL~IChs1js zct+;%%6xO+F~-Dwf9N|x8Mgo-V36P%yw|l~%RQsjg+s5w!%;6I69!AX|E5nHgGbl2 zNqBQ07yB?gm%*AgMm|ztwT$5tlOQASJo>aT^bo#K4uS~30-`kScs%@?XX`)Hr-^wZi!8;%V_Re;fxo6vH_d=fQ(?Mm~IZ!N|nZ8&B&2 zKPE5EF^tT;(1#M8ulEtCv6i#O;s>DvmuP(YLEqrp#c}%f z{Tlxqa3EVrpMJ>rB!|;yRNAIT{^HV!2RuD+u>C#gFu(jE3i=yW{*MeKO8Z63T95n1r&McAbQ> z$N1Uj;^$cxKahjb;iS`XemEyKdYg>;GBlIHv(fEj)Qh2?ToCEY8?8HxNwfS=>JUP zQ&x~I+p8p3K+dhfGnQq$B<5aXP%##*7gujw|iNIL(w? zS9n#tzEYrvrtPFa4`p7c&y<^WUi9DM%Bw%F&nbV8@_;v*6qo!{zJh#B_&4J`q-F^* zP3t7D#4%${>f=IOYr^-%`QdY$uO zcwT9czbQMPS502&z@Mu5Nr#@48voI_e+2R~;Ugg1n7@!;iK=KXqI<%1<5S^CH9L z+6nTLcSSH?(2w~+Q~KeOX3P&d(hrw(Vt$l=258b)%|aAvzX}=d7n9&2IDkEFJivAW z3^~UQ;>mN&0Os5}W&oQyl3{>RzPJGl-H02&lwZsM=G;GK07HM`25{_sWrhN#tYQYR zd}rMR0EW)R%dFqoW+RtI!>rqbKnp+^lt;FT6`cSmk12>d0y|sB&(iU{w~z9vR61%o zI(~`LM{l);>jATzPih$F_&8VdkUswTEtS;cF8ZH>SbG6C>-dKtM(CAQtKlyq4Gq6Y z%li0V5(2M)DQ}cT^38a{{|A=&8~9E5K`#cI?>jI(@!o}HxixHY?SuIkm~}$B1|9=H z(;4_9@UvbF%u|q*G4ltWRR%xJK~*045i%K|-^s26K>8`bN4^%H_gSw68eRv#G|Uw7 z_elpo8vd+;txhNt^v(K0Li{rc@OL!aiGrcr*1spjA4`Bw4TU|dLz>M<4}I{&bX@V{ zxk5!7{yez}aA^X(FaiE(0*t;*8BITSE>y#P3Go97@a6>gO9}9E3GhEBz&}oae>W87 z9T>_eet7%T5O{0?oR0k;9fnJ0RAv}bn7%GHV zfjYpoIZq6BeCC~5Uo2IK)fE9czw5Q$B0yYh8)=2q)|Oc#XZ|}NIIkeDaAtmRS};G3g_r%DDcvMdCi9=tn2@4CrYJZs#ZbB$%RzEODs{-y z!~eJ{{euc*)P5@3KUMq>O8g;_sU`2%{tF7t`#(j6(+i8x{tKrS&iGsV|B&MSlhCrq z$xEoZoBz}npPKDZf7lvzAM&AEuQR1Jp;?=b;BSrePpa4tnK;(|BOfxsAA#m-|MYSm zfFU03+!(y`r{4c7D434-MuYkJ(+j8nmD_(;N5}h$;D6}&KkT4fFe5LBzkEF;|E(qd z5la96NRn9l$8#=UzWz%XHuLu$|MRC!pH>i?|L5bqYK;Fy`G1@L|0Sy8Jeu&#=W3;F>{oP!0XsJoR*7?pV4wLnsG(_z=1suKP`^w%LQGmhs!I_GuGLD zS}vy3a|w;gPDTQ}uOjnhJQqTXfnSU`+QWcpxkxS- zl;P$AKNoq^Rsg0oaX0)l(g^T8W75m}I9nU>oYLOYo7dfuSD?}&Ysov`d8Q#BOv8mo z($0Wo*%^QDe9vbd@#envg|(0T*IlLIoiiW&-G4KV;!K0(!gFi^6Mh;a7t$gw<$+?# zLxEiEWk1Y~5R)%m#xtFio#Pn~uMB%~;p+!V-rB_V_aVmQ!9WL=i{8et9E%J9moPR6 zVuo-q2C4Y61b9*c99v{XIMZK~5Z{mh-;w~gB*56v6Z<#Wa?=(UDGSy_%_9cJk*v_r z@A&XzAFM)r7GmhfU%2Xp3%!~n9qrxf<3#oF>W|6juaxLd-Dpv{$-Nx?;Leq}g<#RAqFblofQLm`gYQ zbjiSJ`y{hpzV3z7km{zb@8H6Wd;T@zJIQT^lRe1(WDqo$E&uKd(P;ssj84eFFVjRP zki%wr-#E^THYSkMX2!j7Si!Ypxf4dF5gv*gXo2nPYfjhX!a`q;*w z44gPqQ@glXK<}CZ__^Vu&G&7v{U_%E`RtYJyK zckzUP%Pvc7s!V6>7{m^&IpbZMx(`|+-WUrNMZ$pt-cer{v$K0zzEgRU_}{5K!BnRf zZK^!st@I;u)UyXjU^c|Mq4MqiHE)kvt!calN+7=}FzV~KzP*nf-&K_-o;&W@_@j-_ zeg9`0&!jxh%mV|JC#-=rCp>pO`Nl5b$XrQycJ`=y?nMA{hTgw-&d-DOgq-V#XsQTGkHBOzbLQN~AqA1`ULtfx~SM?H-C z`qH;Ie($-T*qfH7Z>aY8V{~0fA3i_nTqNDJ^u(s?(no#0_5%OL@1`mgn+ML`N2DrTEz^L`tLd+`p^ZSm16ynpVxEx5R zxQG^{_@BRvMh)J7yYTq66F1(sTzKi5fPT&qbm_PlXysx z!7c`H0DjJzn78b95T8pTn~*PS@Bt(QTn!$o1CfhB?{d<97QsrvFEE&=7(`OCXG`o~ zZ~W+zlh-41-3!0OjAh_-*2z=nqS5=F$%O9SH^ARX-+3Kbv2_>cwFBp(k&B+8Z{?POQ+D+5 zCNF||&JM^*~8NA`lj$qXF|6#8|!ZBwx>Bbf|Yt> z7w?b7+h|kd=Rf&29iH{ZVePxN>&}@9yQOhX_9qti@tag@Fb^Ps7P(CBG~=6GPN9># zWd8g~4&K8nc5*A}Z4UQ3ym+=7=<*|%!0dLgInV(VL{3><-`W%Ib|TI7a@)YkRre!e zFY(Sv!dVfSSPo-?gHKRZ7kAN4H63yDS3rcIwdV@6(a zu`|`lFDT5es4TCzy0UUUK%C4gFVA+SraCnF^YO_jpd&4lnv}7Gi-FG<3A@5=xP8mP z&INWR_^M$C-uMgO4qhX9U_s9YUE2{tP4-Ysfx47)0^>4_-3Aqt8kw=)_H!P-1KkD( zwpKiI{Oa9k$9}k+mmj_x^EbH10aI?@{h)dd+n~8ZJ#!)Z}N~hTf58B>BPaXrQp}SoiXo8360o7{<|L!*T*bJo#*k z2nT*+;<0TUhKFs!7~<0K021|@c+}}eB;wPD$(P}@ zt6w4JeGGK@b&?(nF+NqcuxRkF!3A=nGOnR;)rVed*CM?#349pag8R{VYu+V z;lkrX&E)sMd)9@=hnJ%F$oB={Q4GviuK56u@?-tdkU#Qq2-fh&XJ$X1l@0HRl77P9 zbK$YiO$Xj=B4|S#+E-x>y(-{U0dKhS9tR%7$sZ@GHNcZI6~Huxho8bvdO-%l5YJt2 zjH6}0Pg=&b0`KPrfJ+=2x~wx}(lKZpMrJ%HIR%#aQfH{kZhFTuh4^PzLPHN|=Na}# z3{|p{?-k6E7;7wg z%=GFWn|iF`If5&FRj?ZAsh0}o1YeE$3g$?Ulk~B8R1ysJiLO_^Zb+XpUVMnrU2nGd zWt1gmyCep0s^BAz;m-npxquCS7G@aJ0M}@FcyNSuAz-=c0M|l(H^b%H1Z$FTGu%Bc z{KWhth|hK9zYegGp9QV{G+=lBIB+aFwfvd?*8m&C@_Z8j+b6>;&!w`>oAU9>qMsn# z4W9*U<}jA$VtFZ_k*9;B!F=Kt$d8(MA@a)vZ1jQfSjKDPz|Bj5uLjJ1l=9%(;{w1& ze=fwz?)5HwY6q7Nj3L~e0OLD5F~j&>3GmZ^_q+0Y9xz0dwVwOkUu*NX!Gwf{3J#Z|zsST$`dHyZJdl#-<9a^l9iOy@S@9xI2&(O-wQ1cyda5z@4 zbh|%ojDxf|9_9`?ZyDSjDc9QF0ldheqstwVut-1T%j)s~E{`Tld4Je%pr8M}@?pL} z{@z~>kBd&7@aEdTn_;ylFeD`LbKLk+wd-r$>J!)MJJ9vr4F&BjD^|#3-7V9Lr|04D zc&HO6lAH1Am%J6`BhWHyYW1Jrxb}aW?pP6SZ)pDW=kfmgzlFg9ocU7cKZ^2ks8F8& zoSy$zKL23^@m|IMAA0`dz4m{1ep2oK?$K{i{3Z8)U&17qR?ZMH?c%T{!=AMLFTox| zKtK9+Ib%dTyy6(}k1-DRIAB`Fb8Mr{MH=~xjQM8;U|JLR*VzC4#isnC!>jY>erf8m ztCQyJTQe?P@epT_IhqeX^N)w+tdGwC*{}{Q2QSV%IXmS1jnBKB*KtmdeK=Y6*o!TI zKdj+wSNHud;aSj~H$`}Wp9s|H7{x1^XPbR?cCcu0_%owI` zOo0E{M8akKtqJfI3HV&kFoyW63;>t#XA)pOmm9yE=%C=o`m?%C%_E}@HY}*Ujn^r5MTXSGcOH@?*KmV6$4);4gfyx zf(5qPyCU4x=XEt7IElf2J>I^-$Qo&B3p4G9I1nJO=4tD69SjJCTChl5QW8>^rO4YT z_`}t3A>Tbh4p{8g*P&px6yc(>43Tfr;ANSH)hoL?+VmX}=2XGZdvwep0~|(Z(I*YS z3$7MQJaE8JFnHdC3$szY@`O@$s#lCCrl8P3=(dg)oN>@EAE_6FV&IDUt}eXK7P_Mz zuecc;6DX%3iGht+J@4wcGj`OWAm+=D`GPUu3{<0DukfNTR)0S9+Qv`Uhd%`;$HM(F zpN;;7vFvB~r}|0*^R?=5r2d(3Urh% zI?iKsF_0aniw^n(T?`5*>7t`PO&6W{8M^4u&(cMQd5$iYINqVl4jTC-qf@u(fCF(v?LdiCR6LY475_X>{p`_hsN+@ynnG#CAxs2)6nG)83`%DRI z!hNRX|F(BF@Kqhxfxk~5APE^{2ivm2=3$E%5)kkE0}O~59J$60wQ=j#-ii+iq#y)A zk}D@77KSvY*eU*K>rEU78vk6UbsKhA z|Cu{;=e&m?kU)~|?>!jZd+yAfIdkUBnRDmPoRJpsYf46ENXvAul>Bk|kTgSDs9P%Z zdXs^rrMfo>Y(6;6kQVD668Jci+oLn2<+?`%K4M^L!R~tmK4f5N$?jbOA2hJEX!pYc z?=`TrZ1-+~cN`(|_Qdr!he=z$ z{zjhp^*8N%;-8mKys^Ox_Ox&(U#PFdvf8oq=&{Qu{YC9eo=y6TgYwllis$3F#BbYj zbac?J5|Q-@eDH3ngB$Vzype430bFb|u4efHi!=oL4!E&n>6_cOycrDG+|Np?nwHsQ zI{Fj~BHWS@5fgF?5`*1djo~HOn|N^F(!=2=ZG(JSgnV>RKCLfjygoXfhvBF7m89Nw zux=;hAK%kPaXW80{`9x2V}}F<$)$j!Lr}1%hRAJiRSh;ex~|}NyzXx}J%#EalA|A+})0 zm#c4)1Us5^5n=8H!Hb`q|Iy{;5hp2Y$I`c5L2pwKS<4D~?=6xbEQr$H+!@S*lDg88 z!$)D&!bHU{PkQ9wq(47s7BXymqp+4mRaLA8Y825zCT?Lh$l4uC|AB>1!bNFYvDQU$ zkhN&}#*HMiqI2imJqMBe9bewxOB1`*GFRA4GCB(0uaaTEsI6nm?_2ts6PZw6-joEr zB%p&t$aX1Y)60;JM98YCxvt7(RHcp{Aq7a$LN|R#=w_@5j{cr3I|)VJ)4fj>RZjPX zQBfzMdmk7z-G>#ja=M?F)h&hzitd@v#yB4w{cToiJh${sZi8cp?VGGtt41W7_Wv+M zY1T1iL9uP=n=IFQbNH?^ZTkl8Y#St|Vwd4v^k_P-el2koM*#fBxHjABFj ziIwI(cBRCg=VOImtV$cdUzo`1KK|OC_1f{RZyW@At~Q_>%Jb)HrK=jQ*NWB&pEbF= zB`vp41~CP!G%-tBI_u9Q_E+L9(jwkY1>== zkYpnV%w=@&!aYLQwj;6a2Pb_@Uf5p0gFlnL6eintbkVlAvcLJ{&YF)M1>NY8F!l3Q zpOsvDjv&y&iOB%M!heT>MI*~Hr52JO{Q!iWlO1N+F?VfSSRQH#pP+5!;R#*IiJy+}6l$D7h&95Iv zI$mD|*+wOQ?BHE3kb9ft{A(=KV?z8L0v!Yjb9{*$AvH&;WYL|x!CAOQV0i=FBixtq zu)&UuRRiy_&#IzlA(i(E_SF&gm4aQW{PdA(VZo*!z=9>f`r&Qzu#JZzQ%1MZ;1nB; zfA4_}#5IaUNSYOVN#JVI+_$~uUXmLAg2$0M(0ptal|3lr{0#}i%6<*(g1~eQ5J+Dl zl~G8w6hdP^!6RAiw(PQCPc!AA7?-nLZ5dJ0=bqc%a)67Bvd2~mstE#0P5@Adeemq| zmWR012z|mNun&uZhgTBKXfNzq0){=(7CTq844*LK{}!@qz7VSv zKq?_vu>Z=Nh6j5APc$4}CsOE@ah%J}3q?fa0fXZ2q!DC==)8~+Y2^DJYPm24}b)0z=v0`+pu{CVyTy+X)M0tmGNECsNmfLU*d3Gv+0# zYqBs71B@QKlN37xsm^#TW>~lxr!OM^M;aT*Z%-P$8Is{ zb~b)&gal9hnM+FZG?pd*3rYU&lH?I)-I~8cI`%Ed56+!@J?@1}P{?}R&;PTm$CWjY z_idBEKYl%~q&nq#T=~uruE&+T(^`*v&twd>dm&w~$6bTJDDxR@9?MJD+!2>K$IdwZ zpy-t5Yv(-K?tb!97*0%6eyT!*hcBT&7LQ6(j)x_~!K(gMn}Usf92;TgM)@Awv#~S4 zb4ORuKd*D%hIxJS2Id7<&FQ}?n9~`UdTm&>dA%G4A&KJlfQn#7Z)YGFsArtjwR}tC zJK|My`mT!icW)f*Wvy>loCU$+ENCE}Yz?F2%n%N1W~OuVoiYJr%8BzNe$|{#owKuN z?b@!*U3~+bErJiDwfNyT-bf^q&^BhCF1}fJb+!gG*2?FNVB!Ncbz7J-_(clM_y2f$ zevLGr8YA7`QkMffpSiy8Mmet}5U(e)g1b#>%UY9-gPUO!E1zYOwx=&V7=-n-@%~L+ zYs7I`r%NLo*NM#9@BURAy2{v%U#j(exVtKU+|$RRZ@X?hY9MCL!>72D@fm`yAxf9U z-&f7MDn9e-o=pqqUA<}J=7EK?0vyh)>g?pOWOI~EC_)ky?;G5(8pkBIXUt&fd2~CQ zh3_)joqUb9=x7Nt7c5tq({1G1&AO5ExX$LqN>r&^v)#^mGz`yRAL~eDfExgo623q_ z`F_?!aNog1;U8pHPpr+i2gx=epcoxVi)Yr;1P-zB_5n7E^+?s7saVIkp0!fz1z2p=VUg77HePYGWl{59d5 zgzpmGAxz|3@a2S7!a~B0gx?_a5k5-z1i{g8rq{1Csvai1O_sjU%!PJRy)TsqN- zv-#FD)x?BRZYB2fO1_mXaf!Ib?fnt1Qohh9hWKNo z)A-^%m)~~?g3rl_q@ya)PvRuV41?fuzk{Uvt^>GA8u`gpiBYh!1sQ=UGP^OCAoUQL z5n0ywHocerD+8zfIeZS**PnJxx#$bQSIxI#`H5bTYqe?7u>Xf}*qUx^t+tXS{W**` zrlIM#AspHg(mz93G*8$MLs%>a`U?Fmgr(=A7wq^~%^FnsN&k^+wOLgY_LC3}dzFAuO6Hl&27u z6-EAcvNh$>FC~>*Q!f24gu^xEjy|`h{E+2`TT^bnq?!ETnsWKxCUWG~lqc+(UP-Uz zM%I82knSr{c^3p*fgS(cnsQzKr-%sh`4qeY|HrcQ&j365l{M`zmc{>F z8T`+{hr$0*i~s*hJd;baxt!06wI2ygeRtaU$cwdsgFu`ExS!Cw2>8?RV;%QG-*sj2 zYk=i*W@u|)609$a9|j&lzEE3~-yF!A^JR)Z50|BX0@$^etf~JqV3`~X`FTn3m%tBw zg7M$d^VPEa|FaB!vkV@Gl00bTUHH+gl%~}8J!S9>W$*^z7w)U6d&!o+1-KJ@fUL=H z4t^V0zHW!`yMo^bmQUorZqxrEu=`1QUnqlLD1%=vgTGe>R|{k8Pw-t>2G0b3%+e=o z`ZHzm*OtL6f!pD?pp^7oW$}Y$@Xj*$QQ%+sefFl3U*zR+;3JCP`+@)H-kLhu+ad8U z0&Dud1}xKFT#USaLvHL(>UX>huA<}0bhk_20Q^JvEm>qw!gOF+n;<8lNO|uD7CX+w z%bVxFy*&wbLW^w)a+YV$T5e>Pi8=`ucFNZ!=0L#7~P)*)bxT!+lyi7OzM-}!_r=QrCS?Akva5&8ns zPlRI~J!{2xZqR9*3!S)PPp5Yb(97<8d@7{T%+HlB8}w+^!r9cg^c;%()G8h$AKaFkBd^pPaZUgRLZMHr=Vy zl(WJvHuOnSCoEEwm5Vx_Ik6IYsZ{^Qj&3Hr%#MpCD?V^jhuf(m>q0w3z`~V|#<`Qn zl`u;@H7pA>HC(dF)JLSkMV$UY!mjWvd2;G4BcUgDox$-YYzH61dRTGdhiLZuhY7V7 zwdCo*=028?>PJ>w?Fv;LBkeCUhaLTctHobF0u=6H5mnHEQ1xv@IKu_5I$yX?$+`ueUl-5YrnzvA{pI(=I@wc!KTU(rzC)!W~7 zVq|i|wTrJ?M)caA`B7}2%bVD6MZ*?c(YunajL#u1D(S`rEy?)}YkMHf6xkQQVuks< zxh~FkMytTCuqQ&8&(-3D9))q@K@)LxAOwZPTW*Zc*${6L2E^y^kvjhFh4HzZy)*a2 zU7I&LKEzuVjZw7G1(ZK8enQbiwGk3hS}7UPxfEwobV<{l6(H*WjQ`2Ag7HKoKW6+- z=Td6_FOJ{o{~Q!k>HjBk^6WpkGIRicW_=}>k-ieCiLk#kWD|vKqSz{}ok-Mks86nd z7kLL26ACIMQ^kUc%cqkb%B8Z|2+Ak2$&81R$-GKg%p~wsZ%fE0^9i3aM|lb=&^XiCj4B~nP@Kr6vx!I|)46O3o$0))EsR%f3zyOnWew$hxqR?}GWi!Cn6_!*o>q{u4QyJd}3h6{Hq6|9{;qoP9c(L>lO2o@nA(ho7r1M4J@`V(A z(C6cLG8I?SBZ}Ef-qV>cWHO4DOfjpMmCX1DS2n)S3N49;?>Ye zc)F0!D2#g|VMl%+v7Wfh={F(* zYNQu+tZD?4R7>a5svQ6_DlVJ!nj1})S0fX)p)L=**pCh9L*4FKhC4@@*xJe>$z?G4 zTpU($MoBBypwD;q?7srDa8ZeHP_;GoiE2Tt@E6Pm z^n$k73pu5Si@bnESU^!!y}FPpv6c!LYrech#`i#IK{NWeBxYm;L5qK%PQw+YeF|u% zh!dqPmPsUYN^f9kt2z`h;1w;Yl-HS=R7%N9x|k{`jmA5H$|?@VM39u=Wr;TO((`k(|I(*n zFZ?7)&dmM`=l@dK%KYC?!s|25a~AEt3`U){<51OpY{-?2DU4!jE+n64iXrM5xguk+ zg7VsWVStI^GMp9cH8%>rptLjEUzeUQYU`zdMEVjqYr<=`d<1o*n^3wT4O6QYF z44<+{1tX}CU<%Gd>706#&haMg<8m@=MJeHu9y5#RC>58}r5E*l12c?j>;tD7m9b0} z#7wKw$K+F%2Cd@X&aq{*R)_DpZF$S~e92`?=6zGl%Xq4@X*D)5Q|Cul^gsSSead7} z@r*Mel_t%V&&PQUEWFiio95-h<4lxVwE7J^hov92AFm@hjU}T;80_bwq7&mR%Ew$? zrlhtc^`&Pq>mn%6Oo58Sj8ixLfFv+FnT{m1Hw7qekLFmRBi{Gn-Vpp^zE*w*G zjxpga4GfYJUeo=(^cHd)YU6S8nxo3&d>lm?_N~gN-wNms38g^`bU?+WT*kkd()lsx zeR;wr5Aiui(Sj1waaz}+&$Ld#GW9$weeW+&qN1AjjEFK`=5>E8Bw>Z8g{gXlvjCw! z4ntUR2@5R32`6&;U4oA!s`QfC3f>5my$RoaFT<)!l+G#ocNe4wv(?jr&h(`hndwz= zCEtsfq4jP1^RfT>7v>7Y3fmMk%+=Q4*TOvKuPg5p_8i32f*xG4l8FrlwdJNWP13g!pkbo?RA~&nDgk zo=cnrp-YzL6Jkp!-vr>e4JNL0;5*CN(RQfG2I6Epi3Arf+i}MF8T|Hq;LrhWm`d^q z{V{hoF!!<(MA8dh+32OW`X`&l+%6W;MUqeO3LSNIRc#~Ru4$`l z{A|36^NwP{^pUE%mYJRR1WoLNkB71nrg!y_ItU$tOX8(m`8isIJ}EPzW$J^!`^9Y^ zd|*M-6My#0`~Jh?PaORF>z^F{y^k&$e(2x-{r_2TW9xy@e_b>+S=~By=l2T3kF4Bs z)qnrf@l&?`aPxooeAVL@{NNA%)1*)S=JKg`&j0f8BOht{eB+|8PI>lEzJ1=^gS#fp z|Kx4=En51A!=Juku@F%9b95PDA&woA;V&LuzTXsFBDaTagSpQoZC9B1*k!~gxZQ5! zj{t81e%rzyYzn5d1J}S%X~&VK;L_zZ>r@;6Inp2J`RovmO#ogAe89%PP5LIuXW=`E z-|N!{Uu}v_lWj_ZUwHYSNFV3=noa+8((eYo+TyPPZUcVU#y<#r5PDpB&w}p&@ebd| zh#wKyrvEG8L%=ToW0aRbbh>T)PT)51bz1n-q$hdA56+go~)4{KvV8?i#{L za(H+&OWb80JsvOY-iM&SXIVr)idwV1A(EW_JYs)-Ahx;TtdO5f; zDBa$1N>9)yx_}OkE_4S_XCe>G+AFhREq|)%>*9`C945=ZT6+zl@+Xp3noRz#Bs3A) z&gBtkybCvv}%OuG2fb?=j=Y;Xd9eN@rID=58&odig zLwUTw-J?%0H5*`g9!G_^`xf%L`-LF8kyZc*F@$UY1)S|mz$#CHAJ5l%Uz8h8H?t2+7-2Eno z2X{Y!S~m9&O&>izTvzq@E;iym_;gVBzRv`;cRgSA_@ZwHvH9P;I5Beh=-YEgf?)BZ zL0x-r{w3`}Y({&~v~`5^!*$h=?VmMaXvOp(2V;T|f3@JppGs5k zu_vY!z!T^B5h?esr;zvf0fGa4@YCb-9hpAW7)hnBV!kWt)sn;dY9D5i#s9(!AXft($ z4(i#w4O*ycT0(+*0Rh3&#u z>PG!W>MxHMdM=M!eotKx51^Ah^dX&%t}f-}or)IWv+!_u(S)I0cLjA}In#Ep2*wwr z9C+I#?X+uJK>dTZt&4)Xtv$3A^b}`Jdt#(M2)3-R8d7l0mX(3YJIqm1D}vE?Rs`b~ zO8ybTaCP<2)>ZhfI5ztBmQ}Y62|rw0OB*{{EFF(Y`ogrJZn%c)?x3kXn3Odz H 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 Chx_*c literal 0 HcmV?d00001 diff --git a/ppc/test b/ppc/test new file mode 100755 index 0000000..ef70399 --- /dev/null +++ b/ppc/test @@ -0,0 +1,26 @@ +#!/bin/sh +N=10 +MODE=oneattime + +evalmsg() +{ + if test $1 -eq 0; then + echo -e "\033[32mOK" + else + echo -e "\033[31mFAIL" + fi; + echo -ne "\033[0m" +} + +if test $# -ne 0; then + N=$1; +fi + +echo -n "Testing eth->can: " +cegwbench -s udp@192.168.2.3:10501 -d can@can0 -n $N -m $MODE -t 1 &> /dev/zero +evalmsg $? + +echo -n "Testing can->eth: " +cegwbench -s can@vcan0 -d udp@127.0.0.1:10502 -n $N -m $MODE -t 1 &> /dev/zero +evalmsg $? + diff --git a/ppc/user/Makefile b/ppc/user/Makefile new file mode 100644 index 0000000..4d1b6d2 --- /dev/null +++ b/ppc/user/Makefile @@ -0,0 +1,5 @@ +PROGRAM=canethgw + +all: + powerpc-linux-gnu-gcc -Wall -o${PROGRAM} -I../../utils/common/include/ canethgw.c ../../utils/common/cegwerr.c ../../utils/common/readif.c + diff --git a/ppc/user/canethgw b/ppc/user/canethgw new file mode 100755 index 0000000000000000000000000000000000000000..75fe397d7d5a2e26c91f94cce07b5f53971833b6 GIT binary patch literal 19263 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 bB{xQHA@nT{MgA?7+>*k0cwUklA-eisr+{I_ literal 0 HcmV?d00001 diff --git a/ppc/user/canethgw.c b/ppc/user/canethgw.c new file mode 100644 index 0000000..09cae5c --- /dev/null +++ b/ppc/user/canethgw.c @@ -0,0 +1,279 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "readif.h" +#include "cegwerr.h" + +/** + * ToDo: + * [ ] print usage + */ +//#define GW_DEBUG + +/* powerpc encore */ +#define AF_CAN 29 +#define PF_CAN AF_CAN + +#ifdef GW_DEBUG +#define printdbg(x) printf(x) +#else +#define printdbg(x) +#endif + +#define GW_POLL_ETH 0 +#define GW_POLL_CAN 1 + +#define GW_FLAG_SRC 1 +#define GW_FLAG_DST 2 +#define GW_FLAG_LISTEN 4 +#define GW_FLAG_FILTER 8 + +unsigned int opt_flag = 0; +int sock_udp; +int sock_can; +struct can_filter flt; +struct sockaddr_in udp_dest; + +/** + * filter_check + * @return true if frame should be dropped + */ +bool filter_check( struct can_frame* cf ) +{ + if( !(opt_flag & GW_FLAG_FILTER) ) + return false; + + return ( (cf->can_id & flt.can_mask) == (flt.can_id & flt.can_mask) ); +} + +void send_to_can() +{ + struct can_frame cf; + + read( sock_udp, &cf, sizeof(cf) ); + + if( filter_check( &cf ) ) + { + printdbg( "filter: drop\n" ); + return; + } + + write( sock_can, &cf, sizeof(cf) ); + + printdbg( "eth -> can\n" ); +} + +void send_to_eth() +{ + struct can_frame cf; + + read( sock_can, &cf, sizeof(cf) ); + + if( filter_check( &cf ) ) + { + printdbg( "filter: drop\n" ); + return; + } + + sendto( sock_udp, &cf, sizeof(cf), 0, (struct sockaddr*) &udp_dest, sizeof(udp_dest) ); + + printdbg( "can -> eth\n" ); +} + +void signal_exit( int sig ) +{ + close( sock_udp ); + close( sock_can ); + printf( "exiting\n" ); + + exit( 0 ); +} + +int main( int argc, char* argv[] ) +{ + struct sockaddr_in udp_addr; + struct sockaddr_can can_addr; + struct pollfd pfd[2]; + int polret; + int opt; + struct cegw_if ceif[2], iflisten; + struct cegw_if* ifcan,* ifeth; + + flt.can_id = 0; + flt.can_mask = 0; + + struct option longopt[] = + { + {"listen", 1, NULL, 'l'}, + { 0, 0, 0, 0 } + }; + + while( (opt = getopt_long( argc, argv, "s:d:l:f:i:", longopt, NULL )) != -1 ) + { + switch( opt ) + { + case 's': + if( read_if(optarg, &ceif[0]) != 0 ) + { + perr( "'-s'" ); + return -1; + } + opt_flag |= GW_FLAG_SRC; + break; + case 'd': + if( read_if(optarg, &ceif[1]) != 0 ) + { + perr( "'-d'" ); + return -1; + } + opt_flag |= GW_FLAG_DST; + break; + case 'l': + if( read_if(optarg, &iflisten) != 0 ) + { + perr( "'-l'" ); + return -1; + } + if( iflisten.type != IF_ETH_UDP ) + { + perr( "'-l' udp interface expected" ); + return -1; + } + opt_flag |= GW_FLAG_LISTEN; + break; + case 'f': + if( sscanf( optarg, "%x:%x", &flt.can_id, + &flt.can_mask ) != 2 ) + { + perr( "bad filter format"); + return -1; + } + opt_flag |= GW_FLAG_FILTER; + break; + case '?': + return -1; + break; + } + } + + if( !((opt_flag & GW_FLAG_SRC) && (opt_flag & GW_FLAG_DST) + && (opt_flag & GW_FLAG_LISTEN)) ) + { + perr( "'s', 'd' and 'l' are mandatory" ); + /* ToDo: usage? */ + return -1; + } + + if( !(ceif[0].type == IF_CAN && ceif[1].type == IF_ETH_UDP) && + !(ceif[0].type == IF_ETH_UDP && ceif[1].type == IF_CAN ) ) + { + perr( "'-s' and '-d' should be different interface type" ); + return -1; + } + + if( ceif[0].type == IF_CAN ) + { + ifcan = &ceif[0]; + ifeth = &ceif[1]; + } else + { + ifcan = &ceif[1]; + ifeth = &ceif[0]; + } + + signal( SIGINT, signal_exit ); + + /* prepare udp destination */ + udp_dest.sin_family = AF_INET; + udp_dest.sin_port = htons(ifeth->eth.port); + udp_dest.sin_addr = ifeth->eth.ip; + + /* udp socket */ + sock_udp = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( sock_udp < 0 ) + { + perr( "udp socket creation failed" ); + return -1; + } + + udp_addr.sin_family = AF_INET; + udp_addr.sin_port = htons(iflisten.eth.port); + udp_addr.sin_addr = iflisten.eth.ip; + + if( bind( sock_udp, (struct sockaddr*) &udp_addr, sizeof(udp_addr) ) < 0 ) + { + perr( "udp socket binding failed" ); + close( sock_udp ); + return -1; + } + + /* can socket */ + sock_can = socket( PF_CAN, SOCK_RAW, CAN_RAW ); + if( sock_can < 0 ) + { + perr( "can socket creation failed"); + close( sock_can ); + return -1; + } + + can_addr.can_family = AF_CAN; + can_addr.can_ifindex = ifcan->can.ifindex; + + if( bind( sock_can, (struct sockaddr*) &can_addr, sizeof(can_addr) ) < 0 ) + { + perr( "can socket binding failed" ); + return -1; + } + + /* poll */ + pfd[GW_POLL_ETH].fd = sock_udp; + pfd[GW_POLL_ETH].events = POLLIN | POLLPRI; + pfd[GW_POLL_ETH].revents = 0; + + pfd[GW_POLL_CAN].fd = sock_can; + pfd[GW_POLL_CAN].events = POLLIN | POLLPRI; + pfd[GW_POLL_CAN].revents = 0; + + printf( "canethgw is running\n" ); + + while( 1 ) + { + printdbg( "polling\n" ); + polret = poll( pfd, 2, -1 ); + if( polret < 0 ) + { + perr( "poll(..) failed" ); + close( sock_udp ); + close( sock_can ); + return -1; + } + + if( pfd[GW_POLL_ETH].revents != 0 ) + { + send_to_can(); + } + if( pfd[GW_POLL_CAN].revents != 0 ) + { + send_to_eth(); + } + + pfd[GW_POLL_ETH].revents = 0; + pfd[GW_POLL_CAN].revents = 0; + } + + return 0; +} + -- 2.39.2