Merge "Initial version vCPE TOSCA infra template"
authorMarco Platania <platania@research.att.com>
Fri, 22 Sep 2017 17:22:37 +0000 (17:22 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 22 Sep 2017 17:22:37 +0000 (17:22 +0000)
144 files changed:
boot/aai2_vm_init.sh [deleted file]
boot/aai_install.sh
boot/aai_vm_init.sh
boot/appc_install.sh
boot/appc_vm_init.sh
boot/bind_zones
boot/clamp_install.sh [moved from boot/mso_install.sh with 81% similarity]
boot/clamp_serv.sh [moved from boot/asdc_serv.sh with 98% similarity]
boot/clamp_vm_init.sh [new file with mode: 0644]
boot/cli_install.sh [new file with mode: 0644]
boot/db_openecomp_org [deleted file]
boot/db_simpledemo_openecomp_org
boot/dcae_install.sh
boot/dns_install.sh
boot/mr_install.sh
boot/msb_vm_init.sh [new file with mode: 0644]
boot/mvim_vm_init.sh [new file with mode: 0755]
boot/openo_all_serv.sh [new file with mode: 0644]
boot/openo_install.sh [new file with mode: 0644]
boot/openo_serv.sh [new file with mode: 0644]
boot/policy_install.sh
boot/portal_install.sh
boot/portal_vm_init.sh
boot/robot_install.sh
boot/robot_vm_init.sh
boot/sdc_ext_volume_partitions.txt [moved from boot/asdc_ext_volume_partitions.txt with 100% similarity]
boot/sdc_install.sh [moved from boot/asdc_install.sh with 80% similarity]
boot/sdc_serv.sh [moved from boot/mso_serv.sh with 98% similarity]
boot/sdc_vm_init.sh [moved from boot/asdc_vm_init.sh with 100% similarity]
boot/sdnc_install.sh
boot/sdnc_vm_init.sh
boot/so_install.sh [moved from boot/aai2_install.sh with 60% similarity]
boot/so_serv.sh [moved from boot/aai2_serv.sh with 98% similarity]
boot/so_vm_init.sh [moved from boot/mso_vm_init.sh with 97% similarity]
boot/uui_vm_init.sh [new file with mode: 0755]
boot/vfc_vm_init.sh [new file with mode: 0755]
boot/vid_install.sh
boot/vnfsdk_vm_init.sh [new file with mode: 0755]
heat/ONAP/onap_openstack.env
heat/ONAP/onap_openstack.yaml
heat/ONAP/onap_openstack_float.env
heat/ONAP/onap_openstack_float.yaml
heat/ONAP/onap_openstack_nofloat.env
heat/ONAP/onap_openstack_nofloat.yaml
heat/ONAP/onap_rackspace.env
heat/ONAP/onap_rackspace.yaml
heat/vCPE/infra/base_vcpe_infra_rackspace.env
heat/vCPE/infra/base_vcpe_infra_rackspace.yaml
heat/vCPE/vbng/base_vcpe_vbng_rackspace.env
heat/vCPE/vbng/base_vcpe_vbng_rackspace.yaml
heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.env
heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.yaml
heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.env
heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.yaml
heat/vCPE/vgw/base_vcpe_vgw_rackspace.env
heat/vCPE/vgw/base_vcpe_vgw_rackspace.yaml
heat/vFW/.DS_Store [deleted file]
heat/vFW/base_vfw.env [moved from heat/vFW/base_vfw_openstack.env with 95% similarity]
heat/vFW/base_vfw.yaml [moved from heat/vFW/base_vfw_openstack.yaml with 96% similarity]
heat/vFW/base_vfw_rackspace.env [deleted file]
heat/vFW/base_vfw_rackspace.yaml [deleted file]
heat/vLB/base_vlb.env [moved from heat/vLB/base_vlb_openstack.env with 78% similarity]
heat/vLB/base_vlb.yaml [moved from heat/vLB/base_vlb_openstack.yaml with 65% similarity]
heat/vLB/base_vlb_rackspace.env [deleted file]
heat/vLB/base_vlb_rackspace.yaml [deleted file]
heat/vLB/dnsscaling.env [moved from heat/vLB/dnsscaling_openstack.env with 96% similarity]
heat/vLB/dnsscaling.yaml [moved from heat/vLB/dnsscaling_openstack.yaml with 100% similarity]
heat/vLB/dnsscaling_rackspace.env [deleted file]
heat/vLB/dnsscaling_rackspace.yaml [deleted file]
heat/vLB/packet_gen_vlb.env [deleted file]
heat/vLB/packet_gen_vlb.yaml [deleted file]
pom.xml
vagrant/create_onap.sh
vnfs/VES/bldjobs/Doxyfile
vnfs/VES/bldjobs/Makefile
vnfs/VES5.0/evel/evel-library/bldjobs/Makefile
vnfs/VES5.0/evel/evel-library/code/evel_library/evel.h
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event_mgr.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_fault.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_heartbeat_fields.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal.h
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal_event.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_mobile_flow.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_other.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_reporting_measurement.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_scaling_measurement.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_sipsignaling.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_state_change.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_syslog.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_threshold_cross.c
vnfs/VES5.0/evel/evel-library/code/evel_library/evel_voicequality.c
vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc [deleted file]
vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json
vnfs/VESreporting_vFW5.0/vpp_measurement_reporter.c
vnfs/VESreporting_vLB5.0/vpp_measurement_reporter.c
vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf
vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test [new file with mode: 0644]
vnfs/vCPE/kea-sdnc-notify-mod/src/pkt4_send.cc
vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf [new file with mode: 0644]
vnfs/vCPE/scripts/kea-sdnc-notify.conf
vnfs/vCPE/scripts/v_aaa_install.sh
vnfs/vCPE/scripts/v_bng_init.sh
vnfs/vCPE/scripts/v_bng_install.sh
vnfs/vCPE/scripts/v_brgemu_init.sh
vnfs/vCPE/scripts/v_brgemu_install.sh
vnfs/vCPE/scripts/v_dhcp_install.sh
vnfs/vCPE/scripts/v_dns_init.sh
vnfs/vCPE/scripts/v_dns_install.sh
vnfs/vCPE/scripts/v_gmux_init.sh
vnfs/vCPE/scripts/v_gmux_install.sh
vnfs/vCPE/scripts/v_gw_init.sh
vnfs/vCPE/scripts/v_gw_install.sh
vnfs/vCPE/scripts/v_web_install.sh
vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch [new file with mode: 0755]
vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch [new file with mode: 0644]
vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch [new file with mode: 0644]
vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch [new file with mode: 0644]
vnfs/vFW/scripts/v_firewall_install.sh
vnfs/vFW/scripts/v_packetgen_install.sh
vnfs/vFW/scripts/v_sink_install.sh
vnfs/vLB/.DS_Store [deleted file]
vnfs/vLB/dns_streams/stream_dns1
vnfs/vLB/dns_streams/stream_dns10
vnfs/vLB/dns_streams/stream_dns2
vnfs/vLB/dns_streams/stream_dns3
vnfs/vLB/dns_streams/stream_dns4
vnfs/vLB/dns_streams/stream_dns5
vnfs/vLB/dns_streams/stream_dns6
vnfs/vLB/dns_streams/stream_dns7
vnfs/vLB/dns_streams/stream_dns8
vnfs/vLB/dns_streams/stream_dns9
vnfs/vLB/scripts/.DS_Store [deleted file]
vnfs/vLB/scripts/add_dns.sh
vnfs/vLB/scripts/dnsmembership.sh
vnfs/vLB/scripts/remove_dns.sh
vnfs/vLB/scripts/run_streams_dns.sh
vnfs/vLB/scripts/v_dns_install.sh
vnfs/vLB/scripts/v_lb_init.sh
vnfs/vLB/scripts/v_lb_install.sh
vnfs/vLB/scripts/v_packetgen_init.sh [moved from vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh with 76% similarity]
vnfs/vLB/scripts/v_packetgen_install.sh
vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh
vnfs/vLB/scripts/vpacketgen.sh [moved from vnfs/vLB/scripts/vpacketgenfordnsdemo.sh with 97% similarity]

diff --git a/boot/aai2_vm_init.sh b/boot/aai2_vm_init.sh
deleted file mode 100644 (file)
index ffe0955..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-AAI_INSTANCE=$(cat /opt/config/aai_instance.txt)
-
-cd /opt/test-config
-git pull
-
-if [[ $AAI_INSTANCE == "aai_instance_1" ]]
-then
-       ./deploy_vm1.sh
-elif [[ $AAI_INSTANCE == "aai_instance_2" ]]
-then
-       ./deploy_vm2.sh
-else
-       echo "Invalid instance. Exiting..."
-fi
index d4a04ed..9ee49d7 100644 (file)
@@ -5,7 +5,10 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt)
 ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt)
 DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
+GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
+AAI_INSTANCE=$(cat /opt/config/aai_instance.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -46,9 +49,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai_vm_init.sh -o /opt/aai_vm_init.sh
@@ -89,7 +93,20 @@ echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head
 resolvconf -u
 
 # Run docker containers
-mkdir -p /opt/openecomp/aai/logs
-mkdir -p /opt/openecomp/aai/data
 cd /opt
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO
+
+if [[ $AAI_INSTANCE == "aai_instance_1" ]]
+then
+       mkdir -p /opt/aai/logroot/AAI-RESOURCES
+       mkdir -p /opt/aai/logroot/AAI-TRAVERSAL
+       mkdir -p /opt/aai/logroot/AAI-ML
+       mkdir -p /opt/aai/logroot/AAI-SDB
+       mkdir -p /opt/aai/logroot/AAI-DRMS
+       mkdir -p /opt/aai/logroot/AAI-UI
+       chown -R 999:999 /opt/aai/logroot/AAI-RESOURCES /opt/aai/logroot/AAI-TRAVERSAL
+
+       sleep 300
+fi
+
 ./aai_vm_init.sh
\ No newline at end of file
index 6fcf7b0..ffe0955 100644 (file)
@@ -1,43 +1,16 @@
 #!/bin/bash
 
-NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
-NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
-NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
-DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt)
-DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt)
+AAI_INSTANCE=$(cat /opt/config/aai_instance.txt)
 
-# Pull HBase container from a public docker hub
-docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
-docker pull $NEXUS_DOCKER_REPO/aaidocker/aai-hbase-1.2.3
-docker rm -f hbase-1.2.3
-docker run -d --net=host --name="hbase-1.2.3" $NEXUS_DOCKER_REPO/aaidocker/aai-hbase-1.2.3
+cd /opt/test-config
+git pull
 
-# Wait 3 minutes before instantiating the A&AI container
-sleep 180
-
-docker pull $NEXUS_DOCKER_REPO/openecomp/ajsc-aai:$DOCKER_IMAGE_VERSION
-docker rm -f aai-service
-docker run --name=aai-service --net=host -v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt -it -e AAI_REPO_PATH=r/aai -e AAI_CHEF_ENV=simpledemo -d -e AAI_CHEF_LOC=/var/chef/aai-data/environments -e docker_gitbranch=release-1.0.0 $NEXUS_DOCKER_REPO/openecomp/ajsc-aai:$DOCKER_IMAGE_VERSION
-
-docker pull $NEXUS_DOCKER_REPO/openecomp/model-loader:$DOCKER_IMAGE_VERSION
-docker rm -f model-loader-service
-
-# Start Model Loader container only if SDC is up and running
-# Use the default SDC private IP address if no file exists or the file is empty
-if [[ -s "/opt/config/sdc_ip_addr.txt" ]]
+if [[ $AAI_INSTANCE == "aai_instance_1" ]]
+then
+       ./deploy_vm1.sh
+elif [[ $AAI_INSTANCE == "aai_instance_2" ]]
 then
-       SDC_IP_ADDR=$(cat /opt/config/sdc_ip_addr.txt)
+       ./deploy_vm2.sh
 else
-       SDC_IP_ADDR="10.0.3.1"
+       echo "Invalid instance. Exiting..."
 fi
-
-# Run Health Check against SDC and verify that all five components are up
-RES=$(curl http://$SDC_IP_ADDR:8181/sdc1/rest/healthCheck | grep -c "OK")
-while [[ $RES -lt 5 ]]
-do
-       RES=$(curl http://$SDC_IP_ADDR:8181/sdc1/rest/healthCheck | grep -c "OK")
-done
-
-# At this point, SDC is healthy and Model Loader container can start
-docker run --name=model-loader-service -it -d -e DISTR_CLIENT_ASDC_ADDRESS=c2.vm1.sdc.simpledemo.openecomp.org:8443 -e DISTR_CLIENT_ENVIRONMENT_NAME=$DMAAP_TOPIC -e DISTR_CLIENT_USER=aai -e DISTR_CLIENT_PASSWORD=OBF:1ks51l8d1o3i1pcc1r2r1e211r391kls1pyj1z7u1njf1lx51go21hnj1y0k1mli1sop1k8o1j651vu91mxw1vun1mze1vv11j8x1k5i1sp11mjc1y161hlr1gm41m111nkj1z781pw31kku1r4p1e391r571pbm1o741l4x1ksp -e APP_SERVER_BASE_URL=https://c1.vm1.aai.simpledemo.openecomp.org:8443 -e APP_SERVER_KEYSTORE_PASSWORD=OBF:1i9a1u2a1unz1lr61wn51wn11lss1unz1u301i6o -e APP_SERVER_AUTH_USER=ModelLoader -e APP_SERVER_AUTH_PASSWORD=OBF:1qvu1v2h1sov1sar1wfw1j7j1wg21saj1sov1v1x1qxw $NEXUS_DOCKER_REPO/openecomp/model-loader:$DOCKER_IMAGE_VERSION
-
index c2d4512..b241efe 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/appc_vm_init.sh -o /opt/appc_vm_init.sh
@@ -91,5 +93,5 @@ resolvconf -u
 
 # Clone Gerrit repository and run docker containers
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/appc/deployment.git appc
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO appc
 ./appc_vm_init.sh
\ No newline at end of file
index 90b09ea..3baaf37 100644 (file)
@@ -5,6 +5,7 @@ NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
 export NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
 DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt)
 DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt)
+DGBUILDER_IMAGE_VERSION=$(cat /opt/config/dgbuilder_version.txt)
 export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
 
 cd /opt/appc
@@ -18,7 +19,7 @@ docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
 docker pull $NEXUS_DOCKER_REPO/openecomp/appc-image:$DOCKER_IMAGE_VERSION
 docker tag $NEXUS_DOCKER_REPO/openecomp/appc-image:$DOCKER_IMAGE_VERSION openecomp/appc-image:latest
 
-docker pull $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION
-docker tag $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/dgbuilder-sdnc-image:latest
+docker pull $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image:$DGBUILDER_IMAGE_VERSION
+docker tag $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image/$DGBUILDER_IMAGE_VERSION onap/ccsdk-dgbuilder-image:latest
 
 /opt/docker/docker-compose up -d
index 0893ca6..0c8a114 100644 (file)
@@ -41,9 +41,9 @@ c1.vm1.dcae.simpledemo.openecomp.org.        IN      A       dcae_ip_addr
 c2.vm1.dcae.simpledemo.openecomp.org.        IN      A       dcae_ip_addr
 c3.vm1.dcae.simpledemo.openecomp.org         IN      A       dcae_ip_addr
 
-vm1.mso.simpledemo.openecomp.org.       IN      A       mso_ip_addr
-c1.vm1.mso.simpledemo.openecomp.org.    IN      A       mso_ip_addr
-c1.vm1.mso.simpledemo.openecomp.org.    IN      A       mso_ip_addr
+vm1.mso.simpledemo.openecomp.org.       IN      A       so_ip_addr
+c1.vm1.mso.simpledemo.openecomp.org.    IN      A       so_ip_addr
+c1.vm1.mso.simpledemo.openecomp.org.    IN      A       so_ip_addr
 
 vm1.policy.simpledemo.openecomp.org.    IN      A       policy_ip_addr
 c1.vm1.policy.simpledemo.openecomp.org. IN      A       policy_ip_addr
@@ -69,14 +69,22 @@ vm1.portal.simpledemo.openecomp.org.           IN      A       portal_ip_addr
 c1.vm1.portal.simpledemo.openecomp.org.        IN      A       portal_ip_addr
 c2.vm1.portal.simpledemo.openecomp.org.        IN      A       portal_ip_addr
 
+vm1.clamp.simpledemo.openecomp.org.           IN      A       clamp_ip_addr
+c1.vm1.clamp.simpledemo.openecomp.org.        IN      A       clamp_ip_addr
+c2.vm1.clamp.simpledemo.openecomp.org.        IN      A       clamp_ip_addr
+
 ;vm1.aaf.simpledemo.openecomp.org.     IN      A       aaf_ip_addr
 
-vm1.mr.simpledemo.openecomp.org.       IN      A       mr_ip_addr      
+vm1.mr.simpledemo.openecomp.org.       IN      A       mr_ip_addr
+
+vm1.openo.simpledemo.openecomp.org. IN  A   openo_ip_addr
 
 
 ;CNAMES
 ;A&AI
 aai.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aai.simpledemo.openecomp.org.
+aai.ui.simpledemo.openecomp.org.    IN  CNAME   vm1.aai.simpledemo.openecomp.org.
+aai.searchservice.simpledemo.openecomp.org.     IN      CNAME   vm1.aai.simpledemo.openecomp.org.
 aai.hbase.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
 aai.gremlinserver.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
 aai.elasticsearch.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
@@ -90,7 +98,7 @@ sdc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.sdc.simpledemo.openecomp.org.
 ;DCAE
 dcae.api.simpledemo.openecomp.org.     IN      CNAME   vm1.dcae.simpledemo.openecomp.org.
 
-;MSO
+;SO
 mso.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mso.simpledemo.openecomp.org.
 
 ;Policy
@@ -113,5 +121,15 @@ collector.api.simpledemo.openecomp.org. IN      A   dcae_coll_ip_addr
 ;dbc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.mr.simpledemo.openecomp.org.
 ;drprov.api.simpledemo.openecomp.org.  IN      CNAME   vm1.mr.simpledemo.openecomp.org.
 
+;CLAMP
+clamp.api.simpledemo.openecomp.org.    IN      CNAME   vm1.clamp.simpledemo.openecomp.org.
+
 ;AAF
 ;aaf.api.simpledemo.openecomp.org.     IN      CNAME   vm1.aaf.simpledemo.openecomp.org.
+
+;OPEN-O
+msb.api.simpledemo.openecomp.org.      IN      CNAME   vm1.openo.simpledemo.openecomp.org.
+mvim.api.simpledemo.openecomp.org.     IN      CNAME   vm1.openo.simpledemo.openecomp.org.
+vnfsdk.api.simpledemo.openecomp.org.   IN      CNAME   vm1.openo.simpledemo.openecomp.org.
+vfc.api.simpledemo.openecomp.org.      IN      CNAME   vm1.openo.simpledemo.openecomp.org.
+uui.api.simpledemo.openecomp.org.      IN      CNAME   vm1.openo.simpledemo.openecomp.org.
similarity index 81%
rename from boot/mso_install.sh
rename to boot/clamp_install.sh
index e7d47df..26e8f06 100644 (file)
@@ -5,9 +5,9 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt)
 ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt)
 DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
-OPENSTACK_API_KEY=$(cat /opt/config/openstack_api_key.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -48,17 +48,18 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mso_vm_init.sh -o /opt/mso_vm_init.sh
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mso_serv.sh -o /opt/mso_serv.sh
-chmod +x /opt/mso_vm_init.sh
-chmod +x /opt/mso_serv.sh
-mv /opt/mso_serv.sh /etc/init.d
-update-rc.d mso_serv.sh defaults
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/clamp_vm_init.sh -o /opt/clamp_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/clamp_serv.sh -o /opt/clamp_serv.sh
+chmod +x /opt/clamp_vm_init.sh
+chmod +x /opt/clamp_serv.sh
+mv /opt/clamp_serv.sh /etc/init.d
+update-rc.d clamp_serv.sh defaults
 
 # Download and install docker-engine and docker-compose
 echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
@@ -92,9 +93,7 @@ resolvconf -u
 
 # Clone Gerrit repository
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/so/docker-config.git test_lab
-MSO_ENCRYPTION_KEY=$(cat /opt/test_lab/encryption.key)
-echo -n "$OPENSTACK_API_KEY" | openssl aes-128-ecb -e -K $MSO_ENCRYPTION_KEY -nosalt | xxd -c 256 -p > /opt/config/api_key.txt
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO
 
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -109,4 +108,4 @@ then
 fi
 
 # Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted
-./mso_vm_init.sh
+./clamp_vm_init.sh
similarity index 98%
rename from boot/asdc_serv.sh
rename to boot/clamp_serv.sh
index 7d2539e..ed31184 100644 (file)
@@ -10,7 +10,7 @@
 ### END INIT INFO
 
 dir="/opt"
-cmd="./asdc_vm_init.sh"
+cmd="./clamp_vm_init.sh"
 user="root"
 
 name=`basename $0`
diff --git a/boot/clamp_vm_init.sh b/boot/clamp_vm_init.sh
new file mode 100644 (file)
index 0000000..f8b26e3
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt)
+
+# Fetch the latest code/scripts
+cd /opt/clamp
+git pull
+
+# Remove unused folders as only extra/ folder is used for docker compose
+rm -rf pom.xml
+rm -rf src/
+
+# No configuration change here as directly done in the CLAMP repo
+
+# Pull the clamp docker image from nexus
+# Maria db will be pulled automatically from docker.io during docker-compose
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+
+docker pull $NEXUS_DOCKER_REPO/onap/clamp:$DOCKER_IMAGE_VERSION
+
+cd extra/docker/clamp/
+
+# Change the Clamp docker image name in the docker-compose.yml to match the one downloaded
+sed -i "/image: onap\/clamp/c\    image: $NEXUS_DOCKER_REPO\/onap\/clamp:$DOCKER_IMAGE_VERSION" docker-compose.yml
+
+# Start Clamp and MariaDB containers with docker compose and clamp/extra/docker/clamp/docker-compose.yml
+/opt/docker/docker-compose up -d
diff --git a/boot/cli_install.sh b/boot/cli_install.sh
new file mode 100644 (file)
index 0000000..57f0edc
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+#*******************************************************************************
+# Copyright 2017 Huawei Technologies Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#*******************************************************************************
+
+CLI_LATEST_BINARY="https://nexus.onap.org/service/local/artifact/maven/redirect?r=snapshots&g=org.onap.cli&a=cli-zip&e=zip&v=LATEST"
+CLI_INSTALL_DIR=/opt/onap/cli
+CLI_ZIP=cli.zip
+CLI_BIN=/usr/bin/onap
+export ONAP_CLI_HOME=$CLI_INSTALL_DIR
+
+#create install dir
+if [ -d $CLI_INSTALL_DIR ]
+then
+    mv $CLI_INSTALL_DIR $CLI_INSTALL_DIR/../cli_`date +"%m-%d-%y-%H-%M-%S"`
+    rm $CLI_BIN
+fi
+
+mkdir -p $CLI_INSTALL_DIR
+cd $CLI_INSTALL_DIR
+
+#Download and unzip CLI
+apt-get install -y wget unzip openjdk-8-jre
+wget -O $CLI_ZIP $CLI_LATEST_BINARY
+
+unzip $CLI_ZIP
+if [ ! -d ./data ]; then mkdir ./data; fi
+if [ ! -d ./onap-cli-schema ]; then mkdir ./onap-cli-schema; fi
+chmod +x ./bin/onap.sh
+
+#Make onap available in path
+ln ./bin/onap.sh $CLI_BIN
+
+#Print the version
+onap -v
+
+cd -
diff --git a/boot/db_openecomp_org b/boot/db_openecomp_org
deleted file mode 100644 (file)
index be42b60..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-;
-; BIND data file for local loopback interface
-;
-$TTL    604800
-@       IN      SOA     openecomp.org. admin.openecomp.org. (
-                        20161202        ; Serial
-                         604800         ; Refresh
-                          86400         ; Retry
-                        2419200         ; Expire
-                         604800 )       ; Negative Cache TTL
-;
-; name servers - NS records
-    IN      NS      openecomp.org.
-
-; name servers - A records
-openecomp.org.          IN      A       10.0.0.1
-
-;
-vm1.aai.simpledemo.openecomp.org.       IN      A       10.0.1.1
-c1.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
-c2.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
-c3.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
-
-vm1.appc.simpledemo.openecomp.org.      IN      A       10.0.2.1
-c1.vm1.appc.simpledemo.openecomp.org.   IN      A       10.0.2.1
-c2.vm1.appc.simpledemo.openecomp.org.   IN      A       10.0.2.1
-
-vm1.asdc.simpledemo.openecomp.org.      IN      A       10.0.3.1
-c1.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
-c2.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
-c3.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
-c4.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
-
-vm1.dcae.simpledemo.openecomp.org.           IN      A       10.0.4.1
-c1.vm1.dcae.simpledemo.openecomp.org.        IN      A       10.0.4.1
-c2.vm1.dcae.simpledemo.openecomp.org.        IN      A       10.0.4.1
-c3.vm1.dcae.simpledemo.openecomp.org         IN      A       10.0.4.1
-
-vm1.mso.simpledemo.openecomp.org.       IN      A       10.0.5.1
-c1.vm1.mso.simpledemo.openecomp.org.    IN      A       10.0.5.1
-c1.vm1.mso.simpledemo.openecomp.org.    IN      A       10.0.5.1
-
-vm1.policy.simpledemo.openecomp.org.    IN      A       10.0.6.1
-c1.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c2.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c3.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c4.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c5.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c6.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c7.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-c8.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
-
-vm1.sdnc.simpledemo.openecomp.org.      IN      A       10.0.7.1
-c1.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
-c2.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
-c3.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
-c4.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
-
-vm1.vid.simpledemo.openecomp.org.       IN      A       10.0.8.1
-c1.vm1.vid.simpledemo.openecomp.org.    IN      A       10.0.8.1
-c2.vm1.vid.simpledemo.openecomp.org.    IN      A       10.0.8.1
-
-vm1.portal.simpledemo.openecomp.org.           IN      A       10.0.9.1
-c1.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
-c2.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
-
-vm1.aaf.simpledemo.openecomp.org.      IN      A       10.0.12.1
-
-vm1.mr.simpledemo.openecomp.org.       IN      A       10.0.11.1       
-
-;CNAMES
-;A&AI
-aai.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aai.simpledemo.openecomp.org.
-aai.hbase.simpledemo.openecomp.org.    IN      CNAME   vm1.aai.simpledemo.openecomp.org.
-
-;APPC
-appc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.appc.simpledemo.openecomp.org.
-
-;ASDC
-asdc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.asdc.simpledemo.openecomp.org.      
-
-;DCAE
-dcae.api.simpledemo.openecomp.org.     IN      CNAME   vm1.dcae.simpledemo.openecomp.org.
-
-;MSO
-mso.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mso.simpledemo.openecomp.org.
-
-;Policy
-policy.api.simpledemo.openecomp.org.   IN      CNAME   vm1.policy.simpledemo.openecomp.org.
-
-;SDNC
-sdnc.api.simpledemo.openecomp.org.     IN      CNAME    vm1.sdnc.simpledemo.openecomp.org.
-
-;VID
-vid.api.simpledemo.openecomp.org.      IN      CNAME   vm1.vid.simpledemo.openecomp.org.       
-
-;PORTAL
-portal.api.simpledemo.openecomp.org.   IN      CNAME   vm1.portal.simpledemo.openecomp.org.
-
-;Message Router
-;mr.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mr.simpledemo.openecomp.org.        
-ueb.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mr.simpledemo.openecomp.org.
-mr.api.simpledemo.openecomp.org.        IN      A   10.0.4.102
-collector.api.simpledemo.openecomp.org. IN      A   10.0.4.102
-;dbc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.mr.simpledemo.openecomp.org.
-;drprov.api.simpledemo.openecomp.org.  IN      CNAME   vm1.mr.simpledemo.openecomp.org.
-
-;AAF
-aaf.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aaf.simpledemo.openecomp.org.
\ No newline at end of file
index f7d2b9d..942be99 100644 (file)
@@ -69,15 +69,20 @@ vm1.portal.simpledemo.openecomp.org.           IN      A       10.0.9.1
 c1.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
 c2.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
 
-vm1.aaf.simpledemo.openecomp.org.      IN      A       10.0.12.1
+vm1.aaf.simpledemo.openecomp.org.      IN      A       10.0.13.1
 
-vm1.mr.simpledemo.openecomp.org.       IN      A       10.0.11.1       
+vm1.mr.simpledemo.openecomp.org.       IN      A       10.0.11.1
+
+vm1.clamp.simpledemo.openecomp.org.           IN      A       10.0.12.1
+c1.vm1.clamp.simpledemo.openecomp.org.        IN      A       10.0.12.1
+c2.vm1.clamp.simpledemo.openecomp.org.        IN      A       10.0.12.1
 
 
 ;CNAMES
 ;A&AI
 aai.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aai.simpledemo.openecomp.org.
 aai.ui.simpledemo.openecomp.org.    IN  CNAME   vm1.aai.simpledemo.openecomp.org.
+aai.searchservice.simpledemo.openecomp.org.     IN      CNAME   vm1.aai.simpledemo.openecomp.org.
 aai.hbase.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
 aai.gremlinserver.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
 aai.elasticsearch.simpledemo.openecomp.org.    IN      CNAME   vm2.aai.simpledemo.openecomp.org.
@@ -114,5 +119,8 @@ collector.api.simpledemo.openecomp.org. IN      A   10.0.4.102
 ;dbc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.mr.simpledemo.openecomp.org.
 ;drprov.api.simpledemo.openecomp.org.  IN      CNAME   vm1.mr.simpledemo.openecomp.org.
 
+;CLAMP
+clamp.api.simpledemo.openecomp.org.    IN      CNAME   vm1.clamp.simpledemo.openecomp.org.
+
 ;AAF
 aaf.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aaf.simpledemo.openecomp.org.
index 4cf7896..09a9e33 100644 (file)
@@ -6,6 +6,8 @@ ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt)
 DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
+MR_REPO=$(cat /opt/config/mr_repo.txt)
 
 BASE=$(cat /opt/config/dcae_base_environment.txt)
 PUBLIC_NET_ID=$(cat /opt/config/public_net_id.txt)
@@ -78,9 +80,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/dcae_vm_init.sh -o /opt/dcae_vm_init.sh
@@ -122,7 +125,7 @@ resolvconf -u
 
 # Clone Gerrit repository
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/dcae/demo/startup/controller.git dcae-startup-vm-controller
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO dcae-startup-vm-controller
 
 # Build a configuration file for the DCAE Controller.
 cd /opt/dcae-startup-vm-controller
@@ -154,7 +157,7 @@ NEXUS-RAWURL: $NEXUS_REPO
 DOCKER-REGISTRY: $DOCKER_REGISTRY
 DOCKER-VERSION: $DOCKER_VERSION
 
-GIT-MR-REPO: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git
+GIT-MR-REPO: $MR_REPO
 
 public_net_id: $PUBLIC_NET_ID
 dcae_ip_addr: $DCAE_IP_ADDR
index e76f371..27ea223 100644 (file)
@@ -50,9 +50,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk bind9 bind9utils bind9-doc ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk bind9 bind9utils bind9-doc ntp ntpdate make
 
 # Download script
 mkdir /etc/bind/zones
@@ -70,7 +71,7 @@ then
        sed -i "s/appc_ip_addr/"$(cat /opt/config/appc_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/dcae_ip_addr/"$(cat /opt/config/dcae_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/dns_ip_addr/"$(cat /opt/config/dns_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
-       sed -i "s/mso_ip_addr/"$(cat /opt/config/mso_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
+       sed -i "s/so_ip_addr/"$(cat /opt/config/so_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/mr_ip_addr/"$(cat /opt/config/mr_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/policy_ip_addr/"$(cat /opt/config/policy_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/portal_ip_addr/"$(cat /opt/config/portal_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
@@ -79,6 +80,8 @@ then
        sed -i "s/sdnc_ip_addr/"$(cat /opt/config/sdnc_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/vid_ip_addr/"$(cat /opt/config/vid_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
        sed -i "s/dcae_coll_ip_addr/"$(cat /opt/config/dcae_coll_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
+       sed -i "s/clamp_ip_addr/"$(cat /opt/config/clamp_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
+       sed -i "s/openo_ip_addr/"$(cat /opt/config/openo_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org
 fi
 
 # Configure Bind
index 8c6ee20..e216838 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mr_vm_init.sh -o /opt/mr_vm_init.sh
@@ -91,5 +93,5 @@ resolvconf -u
 
 # Clone Gerrit repository and run docker containers
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/dcae/demo/startup/message-router.git dcae-startup-vm-message-router
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO dcae-startup-vm-message-router
 ./mr_vm_init.sh
\ No newline at end of file
diff --git a/boot/msb_vm_init.sh b/boot/msb_vm_init.sh
new file mode 100644 (file)
index 0000000..cbce060
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DOCKER_IMAGE_VERSION=$(cat /opt/config/msb_docker.txt)
+
+source /opt/config/onap_ips.txt
+
+# start up MSB
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/onap/msb/msb_discovery:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/msb/msb_apigateway:$DOCKER_IMAGE_VERSION
+
+docker rm -f msb_consul
+docker rm -f msb_discovery
+docker rm -f msb_apigateway
+
+docker run -d -p 8500:8500  --name msb_consul consul
+CONSUL_IP=`sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' msb_consul`
+
+docker run -d  -p 10081:10081  -e CONSUL_IP=$CONSUL_IP --name msb_discovery $NEXUS_DOCKER_REPO/onap/msb/msb_discovery:$DOCKER_IMAGE_VERSION
+DISCOVERY_IP=`sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' msb_discovery`
+
+docker run -d -p 80:80 -e CONSUL_IP=$CONSUL_IP -e SDCLIENT_IP=$DISCOVERY_IP -e "ROUTE_LABELS=visualRange:0|1" --name msb_apigateway $NEXUS_DOCKER_REPO/onap/msb/msb_apigateway:$DOCKER_IMAGE_VERSION
+
+# Allow the MSB container to come up before registering services
+sleep 20
+
+# register ONAP services to MSB
+#aai
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-cloudInfrastructure", "version": "v11", "url": "/aai/v11/cloud-infrastructure","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-cloudInfrastructure-deprecated", "version": "v11", "url": "/aai/v11/cloud-infrastructure","path": "/aai/v11/cloud-infrastructure","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-business", "version": "v11", "url": "/aai/v11/business","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-business-deprecated", "version": "v11", "url": "/aai/v11/business","path": "/aai/v11/business","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-search", "version": "v11", "url": "/aai/v11/search","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-search-deprecated", "version": "v11", "url": "/aai/v11/search","path": "/aai/v11/search","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-actions", "version": "v11", "url": "/aai/v11/actions","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-actions-deprecated", "version": "v11", "url": "/aai/v11/actions","path": "/aai/v11/actions","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-service-design-and-creation", "version": "v11", "url": "/aai/v11/service-design-and-creation","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-service-design-and-creation-deprecated", "version": "v11", "url": "/aai/v11/service-design-and-creation","path": "/aai/v11/service-design-and-creation","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-network", "version": "v11", "url": "/aai/v11/network","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-network-deprecated", "version": "v11", "url": "/aai/v11/network","path": "/aai/v11/network","protocol": "REST",  "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#so
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "so", "version": "v1", "url": "/ecomp/mso/infra","protocol": "REST",  "nodes": [ {"ip": "'$SO_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "so-deprecated", "version": "v1", "url": "/ecomp/mso/infra","path": "/ecomp/mso/infra","protocol": "REST",  "nodes": [ {"ip": "'$SO_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#Dmaap message router
+#curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "message-router", "version": "v1", "url": "/","protocol": "REST",  "nodes": [ {"ip": "'$DMAAP_IP'","port": "3904"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#policy
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "policy-pdp", "version": "v1", "url": "/pdp","protocol": "REST",  "nodes": [ {"ip": "'$POLICY_IP'","port": "8081"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "policy-pdp-deprecated", "version": "v1", "url": "/pdp","path": "/pdp","protocol": "REST",  "nodes": [ {"ip": "'$POLICY_IP'","port": "8081"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#portal
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "portal", "version": "v2", "url": "/","protocol": "REST",  "nodes": [ {"ip": "'$PORTAL_IP'","port": "8989"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#sdc
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdc", "version": "v1", "url": "/sdc/v1","protocol": "REST",  "nodes": [ {"ip": "'$SDC_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdc-deprecated", "version": "v1", "url": "/sdc/v1","path": "/sdc/v1","protocol": "REST",  "nodes": [ {"ip": "'$SDC_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#sdnc
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdnc", "version": "v1", "url": "/","protocol": "REST",  "nodes": [ {"ip": "'$SDNC_IP'","port": "8282"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdnc", "version": "v1", "url": "/restconf","path": "/restconf","protocol": "REST",  "nodes": [ {"ip": "'$SDNC_IP'","port": "8282"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
+
+#multi-vim
+curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "multicloud-titanium_cloud", "version": "v0", "url": "/api/multicloud-titanium_cloud/v0","protocol": "REST",  "nodes": [ {"ip": "'$OPENO_IP'","port": "9005"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
\ No newline at end of file
diff --git a/boot/mvim_vm_init.sh b/boot/mvim_vm_init.sh
new file mode 100755 (executable)
index 0000000..f8776bd
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Establish environment variables
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DOCKER_IMAGE_VERSION=$(cat /opt/config/mvim_docker.txt)
+
+source /opt/config/onap_ips.txt
+
+# Refresh images
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/onap/multicloud/framework:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/multicloud/vio:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/multicloud/openstack-ocata:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/multicloud/openstack-windriver:$DOCKER_IMAGE_VERSION
+
+docker rm -f multicloud-broker
+docker rm -f multicloud-vio
+docker rm -f multicloud-ocata
+docker rm -f multicloud-windriver
+
+docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9001:9001 --name multicloud-broker $NEXUS_DOCKER_REPO/onap/multicloud/framework:$DOCKER_IMAGE_VERSION
+docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9004:9004 --name multicloud-vio $NEXUS_DOCKER_REPO/onap/multicloud/vio:$DOCKER_IMAGE_VERSION
+docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9006:9006 --name multicloud-ocata $NEXUS_DOCKER_REPO/onap/multicloud/openstack-ocata:$DOCKER_IMAGE_VERSION
+docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9005:9005 --name multicloud-windriver $NEXUS_DOCKER_REPO/onap/multicloud/openstack-windriver:$DOCKER_IMAGE_VERSION
\ No newline at end of file
diff --git a/boot/openo_all_serv.sh b/boot/openo_all_serv.sh
new file mode 100644 (file)
index 0000000..e451fb1
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+bash /opt/msb_vm_init.sh &>/dev/null &disown
+bash /opt/vnfsdk_vm_init.sh &>/dev/null &disown
+bash /opt/mvim_vm_init.sh &>/dev/null &disown
+bash /opt/vfc_vm_init.sh &>/dev/null &disown
+bash /opt/uui_vm_init.sh &>/dev/null &disown
\ No newline at end of file
diff --git a/boot/openo_install.sh b/boot/openo_install.sh
new file mode 100644 (file)
index 0000000..0f36497
--- /dev/null
@@ -0,0 +1,120 @@
+#!/bin/bash
+
+# Read configuration files
+NEXUS_REPO=$(cat /opt/config/nexus_repo.txt)
+ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt)
+DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
+CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
+VNFSDK_BRANCH=$(cat /opt/config/vnfsdk_branch.txt)
+MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+VNFSDK_REPO=$(cat /opt/config/vnfsdk_repo.txt)
+
+# Add host name to /etc/host to avoid warnings in openstack images
+if [[ $CLOUD_ENV != "rackspace" ]]
+then
+       echo 127.0.0.1 $(hostname) >> /etc/hosts
+
+       # Allow remote login as root
+       mv /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bk
+       cp /home/ubuntu/.ssh/authorized_keys /root/.ssh
+fi
+
+# Set private IP in /etc/network/interfaces manually in the presence of public interface
+# Some VM images don't add the private interface automatically, we have to do it during the component installation
+if [[ $CLOUD_ENV == "openstack_nofloat" ]]
+then
+       LOCAL_IP=$(cat /opt/config/local_ip_addr.txt)
+       CIDR=$(cat /opt/config/oam_network_cidr.txt)
+       BITMASK=$(echo $CIDR | cut -d"/" -f2)
+
+       # Compute the netmask based on the network cidr
+       if [[ $BITMASK == "8" ]]
+       then
+               NETMASK=255.0.0.0
+       elif [[ $BITMASK == "16" ]]
+       then
+               NETMASK=255.255.0.0
+       elif [[ $BITMASK == "24" ]]
+       then
+               NETMASK=255.255.255.0
+       fi
+
+       echo "auto eth1" >> /etc/network/interfaces
+       echo "iface eth1 inet static" >> /etc/network/interfaces
+       echo "    address $LOCAL_IP" >> /etc/network/interfaces
+       echo "    netmask $NETMASK" >> /etc/network/interfaces
+       echo "    mtu $MTU" >> /etc/network/interfaces
+       ifup eth1
+fi
+
+# Download dependencies
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+apt-get update
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make
+
+# Download scripts from Nexus
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vnfsdk_vm_init.sh -o /opt/vnfsdk_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/msb_vm_init.sh -o /opt/msb_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mvim_vm_init.sh -o /opt/mvim_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vfc_vm_init.sh -o /opt/vfc_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/uui_vm_init.sh -o /opt/uui_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/openo_all_serv.sh -o /opt/openo_all_serv.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/openo_serv.sh -o /opt/openo_serv.sh
+chmod +x /opt/vnfsdk_vm_init.sh
+chmod +x /opt/msb_vm_init.sh
+chmod +x /opt/mvim_vm_init.sh
+chmod +x /opt/vfc_vm_init.sh
+chmod +x /opt/uui_vm_init.sh
+chmod +x /opt/openo_all_serv.sh
+chmod +x /opt/openo_serv.sh
+mv /opt/openo_serv.sh /etc/init.d
+update-rc.d openo_serv.sh defaults
+
+# Download and install docker-engine and docker-compose
+echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
+apt-get update
+apt-get install -y linux-image-extra-$(uname -r) linux-image-extra-virtual
+apt-get install -y --allow-unauthenticated docker-engine
+
+mkdir /opt/docker
+curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /opt/docker/docker-compose
+chmod +x /opt/docker/docker-compose
+
+# Set the MTU size of docker containers to the minimum MTU size supported by vNICs. OpenStack deployments may need to know the external DNS IP
+DNS_FLAG=""
+if [ -s /opt/config/dns_ip_addr.txt ]
+then
+       DNS_FLAG=$DNS_FLAG"--dns $(cat /opt/config/dns_ip_addr.txt) "
+fi
+if [ -s /opt/config/external_dns.txt ]
+then
+       DNS_FLAG=$DNS_FLAG"--dns $(cat /opt/config/external_dns.txt) "
+fi
+echo "DOCKER_OPTS=\"$DNS_FLAG--mtu=$MTU\"" >> /etc/default/docker
+
+cp /lib/systemd/system/docker.service /etc/systemd/system
+sed -i "/ExecStart/s/$/ --mtu=$MTU/g" /etc/systemd/system/docker.service
+service docker restart
+
+# DNS IP address configuration
+echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head
+resolvconf -u
+
+# Clone Gerrit repository and run docker containers
+cd /opt
+git clone -b $VNFSDK_BRANCH --single-branch $VNFSDK_REPO
+
+# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
+if [[ $CLOUD_ENV != "rackspace" ]]
+then
+       sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub
+       grub-mkconfig -o /boot/grub/grub.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules
+       echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
+       echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic
+       reboot
+fi
+
+./openo_all_serv.sh
\ No newline at end of file
diff --git a/boot/openo_serv.sh b/boot/openo_serv.sh
new file mode 100644 (file)
index 0000000..0afa931
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./openo_all_serv.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
index 18cc3de..3f6ea5d 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/policy_vm_init.sh -o /opt/policy_vm_init.sh
@@ -91,5 +93,5 @@ resolvconf -u
 
 # Clone Gerrit repository and run docker containers
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/policy/docker.git policy
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO policy
 ./policy_vm_init.sh
\ No newline at end of file
index 6b1c34f..c1b816e 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/portal_vm_init.sh -o /opt/portal_vm_init.sh
@@ -92,5 +94,6 @@ resolvconf -u
 # Clone Gerrit repository and run docker containers
 mkdir -p /PROJECT/OpenSource/UbuntuEP/logs
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/portal.git
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO
+
 ./portal_vm_init.sh
\ No newline at end of file
index 5f34aae..5b201e0 100755 (executable)
@@ -1,71 +1,45 @@
 #!/bin/bash
-# Starts docker containers for ONAP Portal
+# Starts docker containers for ONAP Portal in Rackspace.
+# Version for Amsterdam/R1 uses docker-compose.
 
 # be verbose
 set -x
 
-# Refresh source area with start scripts
-cd /opt/portal
-git pull
-cd /opt
-
 # Establish environment variables
 NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
 NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
 NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
 DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt)
 
-# Get container, image and tag names used below
-source portal/deliveries/os_settings.sh
+# Refresh configuration and scripts
+cd /opt/portal
+git pull
+cd deliveries
+
+# Get image names used below from docker-compose environment file
+source .env
 
-# Unpack property files
-unzip -o portal/deliveries/etc.zip -d /PROJECT/OpenSource/UbuntuEP/
+# Copy property files
+ETC=/PROJECT/OpenSource/UbuntuEP/etc
+mkdir -p $ETC
+cp -r properties_rackspace/* $ETC
 
 # Refresh images
 docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
-docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION
-docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION
-docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION
-
-# Remove lingering containers; order matters.
-docker rm -f $DB_CONT_NAME
-docker rm -f $DB_VOL_NAME
-docker rm -f $EP_CONT_NAME
-docker rm -f $WMS_CONT_NAME
-
-docker create --name $DB_VOL_NAME -v /var/lib/mysql mariadb
-docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME
-docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME
-# WMS image has no version in the registry
-docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION ${WMS_IMG_NAME}:latest
-
-# Recreate the named containers
-cd portal/deliveries
-echo "Starting database"
-./dbstart.sh
-echo "Delaying for database"
-sleep 10
-echo "Starting apps"
-./new_start.sh
-echo "Starting widget-ms"
-./widget_ms_start.sh
-
-sleep 180
+docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION
+# Add CLI docker image
+docker pull $NEXUS_DOCKER_REPO/onap/cli:$DOCKER_IMAGE_VERSION
+
+# Tag them as expected by docker-compose file
+docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME:$PORTAL_TAG
+docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME:$PORTAL_TAG
+docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION $WMS_IMG_NAME:$PORTAL_TAG
+# Add tagging for CLI docker image as expected by docker-compose file
+docker tag $NEXUS_DOCKER_REPO/onap/cli:$DOCKER_IMAGE_VERSION onap/cli:$PORTAL_TAG
+
+# docker-compose is not in /usr/bin
+/opt/docker/docker-compose down
+/opt/docker/docker-compose up -d
 
-if [ ! -e /opt/config/boot.txt ]
-then
-       if [ -e /opt/config/public_ip.txt ]
-       then
-               IP_ADDRESS=$(cat /opt/config/public_ip.txt)
-       else
-               IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
-       fi
-       # Wait until MySQL is running...
-       while [[ $(netstat -vulntp |grep -i mysql | awk '{print $4}') != ":::3306" ]]
-       do
-               sleep 1
-       done
-       # no longer necessary; done at docker build time
-       # mysql -u root -p'Aa123456' -h $IP_ADDRESS < /opt/portal/deliveries/Apps_Users_OnBoarding_Script.sql
-       echo "yes" > /opt/config/boot.txt
-fi
index caf5bef..3447a01 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/robot_vm_init.sh -o /opt/robot_vm_init.sh
@@ -93,7 +95,7 @@ resolvconf -u
 mkdir -p /opt/eteshare/logs
 mkdir -p /opt/eteshare/config
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/testsuite/properties.git testsuite/properties
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO testsuite/properties
 
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
index 5b68272..7831348 100644 (file)
@@ -22,13 +22,14 @@ cp demo.sh /opt
 #      sed -i "s/10.0.1.1/"$(cat /opt/config/aai1_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.2.1/"$(cat /opt/config/appc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.4.1/"$(cat /opt/config/dcae_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
-#      sed -i "s/10.0.5.1/"$(cat /opt/config/mso_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
+#      sed -i "s/10.0.5.1/"$(cat /opt/config/so_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.11.1/"$(cat /opt/config/mr_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.6.1/"$(cat /opt/config/policy_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.9.1/"$(cat /opt/config/portal_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.3.1/"$(cat /opt/config/sdc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.7.1/"$(cat /opt/config/sdnc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/10.0.8.1/"$(cat /opt/config/vid_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
+#   sed -i "s/10.0.12.1/"$(cat /opt/config/clamp_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #      sed -i "s/https:\/\/identity.api.rackspacecloud.com/"$(cat /opt/config/keystone.txt)"/g" /opt/eteshare/config/integration_robot_properties.py
 #fi
 
similarity index 80%
rename from boot/asdc_install.sh
rename to boot/sdc_install.sh
index 59d6c83..2c32266 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,17 +48,18 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_vm_init.sh -o /opt/asdc_vm_init.sh
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_serv.sh -o /opt/asdc_serv.sh
-chmod +x /opt/asdc_vm_init.sh
-chmod +x /opt/asdc_serv.sh
-mv /opt/asdc_serv.sh /etc/init.d
-update-rc.d asdc_serv.sh defaults
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_vm_init.sh -o /opt/sdc_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_serv.sh -o /opt/sdc_serv.sh
+chmod +x /opt/sdc_vm_init.sh
+chmod +x /opt/sdc_serv.sh
+mv /opt/sdc_serv.sh /etc/init.d
+update-rc.d sdc_serv.sh defaults
 
 # Download and install docker-engine and docker-compose
 echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
@@ -70,17 +72,17 @@ curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose
 chmod +x /opt/docker/docker-compose
 
 # Create partition and mount the external volume
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_ext_volume_partitions.txt -o /opt/asdc_ext_volume_partitions.txt
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_ext_volume_partitions.txt -o /opt/sdc_ext_volume_partitions.txt
 
 if [[ $CLOUD_ENV == "rackspace" ]]
 then
        DISK="xvdb"
 else
        DISK=$(ls /dev |grep -e '^.*db$')
-       sed -i "s/xvdb/$DISK/g" /opt/asdc_ext_volume_partitions.txt
+       sed -i "s/xvdb/$DISK/g" /opt/sdc_ext_volume_partitions.txt
 fi
 
-sfdisk /dev/$DISK < /opt/asdc_ext_volume_partitions.txt
+sfdisk /dev/$DISK < /opt/sdc_ext_volume_partitions.txt
 mkfs -t ext4 /dev/$DISK"1"
 mkdir -p /data
 mount /dev/$DISK"1" /data
@@ -116,7 +118,7 @@ chmod 777 /data
 chmod 777 /data/logs/BE
 chmod 777 /data/logs/FE
 
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/sdc.git
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO
 
 cat > /root/.bash_aliases << EOF
 alias dcls='/data/scripts/docker_clean.sh \$1'
@@ -138,4 +140,4 @@ then
 fi
 
 # Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted
-./asdc_vm_init.sh
+./sdc_vm_init.sh
similarity index 98%
rename from boot/mso_serv.sh
rename to boot/sdc_serv.sh
index 00ee417..b48c848 100644 (file)
@@ -10,7 +10,7 @@
 ### END INIT INFO
 
 dir="/opt"
-cmd="./mso_vm_init.sh"
+cmd="./sdc_vm_init.sh"
 user="root"
 
 name=`basename $0`
similarity index 100%
rename from boot/asdc_vm_init.sh
rename to boot/sdc_vm_init.sh
index 8814876..3b5c5cf 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdnc_vm_init.sh -o /opt/sdnc_vm_init.sh
@@ -91,5 +93,5 @@ resolvconf -u
 
 # Clone Gerrit repository and run docker containers
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/sdnc/oam.git sdnc
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO sdnc
 ./sdnc_vm_init.sh
\ No newline at end of file
index bc5b036..f23f122 100644 (file)
@@ -4,6 +4,7 @@ NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
 NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
 export NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
 DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt)
+DGBUILDER_IMAGE_VERSION=$(cat /opt/config/dgbuilder_version.txt)
 export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
 export DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 
@@ -19,7 +20,7 @@ docker tag $NEXUS_DOCKER_REPO/openecomp/sdnc-image:$DOCKER_IMAGE_VERSION openeco
 docker pull $NEXUS_DOCKER_REPO/openecomp/admportal-sdnc-image:$DOCKER_IMAGE_VERSION
 docker tag $NEXUS_DOCKER_REPO/openecomp/admportal-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/admportal-sdnc-image:latest
 
-docker pull $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION
-docker tag $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/dgbuilder-sdnc-image:latest
+docker pull $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image:$DGBUILDER_IMAGE_VERSION
+docker tag $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image/$DGBUILDER_IMAGE_VERSION onap/ccsdk-dgbuilder-image:latest
 
 /opt/docker/docker-compose up -d
similarity index 60%
rename from boot/aai2_install.sh
rename to boot/so_install.sh
index d270801..d9a8a64 100644 (file)
@@ -5,9 +5,10 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt)
 ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt)
 DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
+OPENSTACK_API_KEY=$(cat /opt/config/openstack_api_key.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
-AAI_INSTANCE=$(cat /opt/config/aai_instance.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -48,20 +49,21 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai2_vm_init.sh -o /opt/aai2_vm_init.sh
-curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai2_serv.sh -o /opt/aai2_serv.sh
-chmod +x /opt/aai2_vm_init.sh
-chmod +x /opt/aai2_serv.sh
-mv /opt/aai2_serv.sh /etc/init.d
-update-rc.d aai2_serv.sh defaults
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/so_vm_init.sh -o /opt/so_vm_init.sh
+curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/so_serv.sh -o /opt/so_serv.sh
+chmod +x /opt/so_vm_init.sh
+chmod +x /opt/so_serv.sh
+mv /opt/so_serv.sh /etc/init.d
+update-rc.d so_serv.sh defaults
 
 # Download and install docker-engine and docker-compose
-echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee /etc/apt/sources.list.d/docker.list
+echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
 apt-get update
 apt-get install -y linux-image-extra-$(uname -r) linux-image-extra-virtual
 apt-get install -y --allow-unauthenticated docker-engine
@@ -90,21 +92,23 @@ service docker restart
 echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head
 resolvconf -u
 
-# Run docker containers
+# Clone Gerrit repository
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/aai/test-config
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO test_lab
+SO_ENCRYPTION_KEY=$(cat /opt/test_lab/encryption.key)
+echo -n "$OPENSTACK_API_KEY" | openssl aes-128-ecb -e -K $SO_ENCRYPTION_KEY -nosalt | xxd -c 256 -p > /opt/config/api_key.txt
 
-if [[ $AAI_INSTANCE == "aai_instance_1" ]]
+# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
+if [[ $CLOUD_ENV != "rackspace" ]]
 then
-       mkdir -p /opt/aai/logroot/AAI-RESOURCES
-       mkdir -p /opt/aai/logroot/AAI-TRAVERSAL
-       mkdir -p /opt/aai/logroot/AAI-ML
-       mkdir -p /opt/aai/logroot/AAI-SDB
-       mkdir -p /opt/aai/logroot/AAI-DRMS
-       mkdir -p /opt/aai/logroot/AAI-UI
-       chown -R 999:999 /opt/aai/logroot/AAI-RESOURCES /opt/aai/logroot/AAI-TRAVERSAL
-
-       sleep 300
+       sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub
+       grub-mkconfig -o /boot/grub/grub.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules
+       echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
+       echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic
+       reboot
 fi
 
-./aai2_vm_init.sh
\ No newline at end of file
+# Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted
+./so_vm_init.sh
similarity index 98%
rename from boot/aai2_serv.sh
rename to boot/so_serv.sh
index add0009..d324447 100644 (file)
@@ -10,7 +10,7 @@
 ### END INIT INFO
 
 dir="/opt"
-cmd="./aai2_vm_init.sh"
+cmd="./so_vm_init.sh"
 user="root"
 
 name=`basename $0`
similarity index 97%
rename from boot/mso_vm_init.sh
rename to boot/so_vm_init.sh
index e39f6b0..d767a14 100644 (file)
@@ -58,7 +58,7 @@ else
 EOF
 fi
 
-# Update the MSO configuration file.
+# Update the SO configuration file.
 read -d '' MSO_CONFIG_UPDATES <<-EOF
 {
 "default_attributes":
@@ -97,5 +97,5 @@ export MSO_CONFIG_UPDATES
 cd /opt/test_lab
 git pull
 chmod +x deploy.sh
-#This script takes in input 2 nexus repos (the first one for the MSO image, the second one for mariadb)
+#This script takes in input 2 nexus repos (the first one for the SO image, the second one for mariadb)
 ./deploy.sh $NEXUS_DOCKER_REPO $NEXUS_USERNAME $NEXUS_PASSWD $NEXUS_DOCKER_REPO $NEXUS_USERNAME $NEXUS_PASSWD
diff --git a/boot/uui_vm_init.sh b/boot/uui_vm_init.sh
new file mode 100755 (executable)
index 0000000..ebec9e3
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Establish environment variables
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DOCKER_IMAGE_VERSION=$(cat /opt/config/uui_docker.txt)
+
+source /opt/config/onap_ips.txt
+
+# Refresh images
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/onap/uui/ui:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/uui/server:$DOCKER_IMAGE_VERSION
+
+docker rm -f uui_ui
+docker rm -f uui_server
+
+# Insert docker run instructions here
+docker run -i -t -d --name uui_ui -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/uui/ui:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name uui_server -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/uui/server:$DOCKER_IMAGE_VERSION
\ No newline at end of file
diff --git a/boot/vfc_vm_init.sh b/boot/vfc_vm_init.sh
new file mode 100755 (executable)
index 0000000..5badc20
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# Establish environment variables
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DOCKER_IMAGE_VERSION=$(cat /opt/config/vfc_docker.txt)
+
+source /opt/config/onap_ips.txt
+
+# Refresh images
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/catalog:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/emsdriver:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/gvnfmdriver:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/jujudriver:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/nfvo/svnfm/huawei:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/nslcm:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/resmanagement:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnflcm:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnfmgr:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnfres:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/ztesdncdriver:$DOCKER_IMAGE_VERSION
+docker pull $NEXUS_DOCKER_REPO/onap/vfc/ztevmanagerdriver:$DOCKER_IMAGE_VERSION
+
+docker rm -f vfc_catalog
+docker rm -f vfc_emsdriver
+docker rm -f vfc_gvnfmdriver
+docker rm -f vfc_jujudriver
+docker rm -f vfc_svnfm_huawei
+docker rm -f vfc_nslcm
+docker rm -f vfc_resmanagement
+docker rm -f vfc_vnflcm
+docker rm -f vfc_vnfmgr
+docker rm -f vfc_vnfres
+docker rm -f vfc_ztesdncdriver
+docker rm -f vfc_ztevmanagerdriver
+
+# Insert docker run instructions here
+docker run -i -t -d --name vfc_catalog -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/catalog:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_emsdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/emsdriver:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_gvnfmdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/gvnfmdriver:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_jujudriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/jujudriver:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_svnfm_huawei -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/nfvo/svnfm/huawei:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_nslcm -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/nslcm:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_resmanagement -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/resmanagement:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_vnflcm -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnflcm:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_vnfmgr -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnfmgr:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_vnfres -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnfres:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_ztesdncdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/ztesdncdriver:$DOCKER_IMAGE_VERSION
+docker run -i -t -d --name vfc_ztevmanagerdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/ztevmanagerdriver:$DOCKER_IMAGE_VERSION
\ No newline at end of file
index d9f775c..118995c 100644 (file)
@@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt)
 MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+CODE_REPO=$(cat /opt/config/remote_repo.txt)
 
 # Add host name to /etc/host to avoid warnings in openstack images
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -47,9 +48,10 @@ then
 fi
 
 # Download dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
+apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make
 
 # Download scripts from Nexus
 curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vid_vm_init.sh -o /opt/vid_vm_init.sh
@@ -91,5 +93,5 @@ resolvconf -u
 
 # Clone Gerrit repository and run docker containers
 cd /opt
-git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/vid.git
+git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO
 ./vid_vm_init.sh
\ No newline at end of file
diff --git a/boot/vnfsdk_vm_init.sh b/boot/vnfsdk_vm_init.sh
new file mode 100755 (executable)
index 0000000..fa28285
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Starts docker containers for VNFSDK VNF  repository.
+# Version for Amsterdam/R1 uses docker-compose.
+
+# be verbose
+set -x
+
+# Establish environment variables
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+#DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) --> not needed at the moment
+
+# Refresh configuration and scripts
+cd /opt/refrepo
+git pull
+cd vnfmarket-be/deployment/install
+
+# Get image names used below from docker-compose environment file
+source .env
+
+# Refresh images
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/onap/refrepo:${REFREPO_TAG}
+docker pull $NEXUS_DOCKER_REPO/onap/refrepo:${POSTGRES_TAG}
+
+# docker-compose is not in /usr/bin
+/opt/docker/docker-compose down
+/opt/docker/docker-compose up -d
+
index b94bcca..74a9c8e 100644 (file)
@@ -20,6 +20,8 @@ parameters:
 
   flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE
 
+  flavor_xxlarge: PUT THE XXLARGE FLAVOR NAME HERE
+
   vm_base_name: vm1
 
   key_name: onap_key
@@ -38,10 +40,6 @@ parameters:
 
   artifacts_version: 1.1.0-SNAPSHOT
 
-  docker_version: 1.1-STAGING-latest
-
-  gerrit_branch: master
-
   openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE
 
   openstack_username: PUT YOUR OPENSTACK USERNAME HERE
@@ -67,10 +65,10 @@ parameters:
 
   dns_list: PUT THE ADDRESS OF THE EXTERNAL DNS HERE (e.g. a comma-separated list of IP addresses in your /etc/resolv.conf in UNIX-based Operating Systems)
   external_dns: PUT THE FIRST ADDRESS OF THE EXTERNAL DNS LIST HERE
+  oam_network_cidr: 10.0.0.0/16
 
   ### Private IP addresses ###
 
-  oam_network_cidr: 10.0.0.0/16
   aai1_ip_addr: 10.0.1.1
   aai2_ip_addr: 10.0.1.2
   appc_ip_addr: 10.0.2.1
@@ -81,7 +79,7 @@ parameters:
   dcae_hdp2_ip_addr: 10.0.4.104
   dcae_hdp3_ip_addr: 10.0.4.105
   dns_ip_addr: 10.0.100.1
-  mso_ip_addr: 10.0.5.1
+  so_ip_addr: 10.0.5.1
   mr_ip_addr: 10.0.11.1
   policy_ip_addr: 10.0.6.1
   portal_ip_addr: 10.0.9.1
@@ -89,6 +87,8 @@ parameters:
   sdc_ip_addr: 10.0.3.1
   sdnc_ip_addr: 10.0.7.1
   vid_ip_addr: 10.0.8.1
+  clamp_ip_addr: 10.0.12.1
+  openo_ip_addr: 10.0.14.1
 
   dcae_coll_float_ip: PUT DCAE COLLECTOR FLOATING IP HERE
   dcae_db_float_ip: PUT DCAE DATABASE FLOATING IP HERE
@@ -114,4 +114,62 @@ parameters:
 
   gitlab_branch: master
 
-  dcae_code_version: 1.1.0
\ No newline at end of file
+  dcae_code_version: 1.1.0
+
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_branch: master
+  appc_branch: master
+  so_branch: master
+  mr_branch: master
+  dcae_branch: master
+  policy_branch: master
+  portal_branch: master
+  robot_branch: master
+  sdc_branch: master
+  sdnc_branch: master
+  vid_branch: master
+  clamp_branch: master
+  vnfsdk_branch: master
+
+  aai_docker: 1.1-STAGING-latest
+  appc_docker: 1.1-STAGING-latest
+  so_docker: 1.1-STAGING-latest
+  mr_docker: 1.1-STAGING-latest
+  dcae_docker: 1.1-STAGING-latest
+  policy_docker: 1.1-STAGING-latest
+  portal_docker: 1.1-STAGING-latest
+  robot_docker: 1.1-STAGING-latest
+  sdc_docker: 1.1-STAGING-latest
+  sdnc_docker: 1.2-STAGING-latest
+  vid_docker: 1.1-STAGING-latest
+  clamp_docker: 1.1-STAGING-latest
+  msb_docker: latest
+  mvim_docker: latest
+  vfc_docker: latest
+  uui_docker: latest
+  dgbuilder_docker: 0.1-STAGING-latest
+
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+  aai_repo: http://gerrit.onap.org/r/aai/test-config
+  appc_repo: http://gerrit.onap.org/r/appc/deployment.git
+  dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git
+  mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git 
+  so_repo: http://gerrit.onap.org/r/so/docker-config.git
+  policy_repo: http://gerrit.onap.org/r/policy/docker.git
+  portal_repo: http://gerrit.onap.org/r/portal.git
+  robot_repo: http://gerrit.onap.org/r/testsuite/properties.git
+  sdc_repo: http://gerrit.onap.org/r/sdc.git
+  sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git
+  vid_repo: http://gerrit.onap.org/r/vid.git
+  clamp_repo: http://gerrit.onap.org/r/clamp.git
+  vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git
index 4833999..8258232 100644 (file)
@@ -68,6 +68,10 @@ parameters:
     type: string
     description: Name of the Extra Large Flavor supported by the cloud provider
 
+  flavor_xxlarge:
+    type: string
+    description: Name of the Extra Extra Large Flavor supported by the cloud provider
+
   vm_base_name:
     type: string
     description: Base name of ONAP VMs
@@ -100,15 +104,6 @@ parameters:
     type: string
     description: Artifacts version of ONAP components
 
-  docker_version:
-    type: string
-    label: Version number of ONAP docker images
-
-  gerrit_branch:
-    type: string
-    label: Gerrit code branch
-    description: Gerrit branch where to download the code from
-
   dmaap_topic:
     type: string
     description: DMaaP Topic name
@@ -127,7 +122,7 @@ parameters:
 
   openstack_api_key:
     type: string
-    description: Openstack API Key
+    description: Openstack password or API Key
 
   horizon_url:
     type: string
@@ -155,102 +150,61 @@ parameters:
     type: string
     description: First element of the dns_list for ONAP network
 
-  ### Private IP addresses ###
   oam_network_cidr:
     type: string
     description: CIDR of the OAM ONAP network
 
+  ### Private IP addresses ###
   aai1_ip_addr:
     type: string
-    description: AAI Instance 1 IP Address
-
   aai2_ip_addr:
     type: string
-    description: AAI Instance 2 IP Address
-
   appc_ip_addr:
     type: string
-    description: APP-C IP Address
-
   dcae_ip_addr:
     type: string
-    description: DCAE IP Address
   dcae_coll_ip_addr:
     type: string
-    description: DCAE Collector IP Address
-
   dcae_db_ip_addr:
     type: string
-    description: DCAE Database IP Address
-
   dcae_hdp1_ip_addr:
     type: string
-    description: Hadoop VM1 IP Address
-
   dcae_hdp2_ip_addr:
     type: string
-    description: Hadoop VM2 IP Address
-
   dcae_hdp3_ip_addr:
     type: string
-    description: Hadoop VM3 IP Address
-
   dns_ip_addr:
     type: string
-    description: DNS IP Address
-
-  mso_ip_addr:
+  so_ip_addr:
     type: string
-    description: MSO IP Address
-
   mr_ip_addr:
     type: string
-    description: Message Router IP Address
-
   policy_ip_addr:
     type: string
-    description: Policy Engine IP Address
-
   portal_ip_addr:
     type: string
-    description: Portal IP Address
-
   robot_ip_addr:
     type: string
-    description: Robot Framework IP Address
-
   sdc_ip_addr:
     type: string
-    description: SDC IP Address
-
   sdnc_ip_addr:
     type: string
-    description: SDN-C IP Address
-
   vid_ip_addr:
     type: string
-    description: VID IP Address
-
+  clamp_ip_addr:
+    type: string
+  openo_ip_addr:
+    type: string
   dcae_coll_float_ip:
     type: string
-    description: DCAE Collector Floating IP Address
-
   dcae_db_float_ip:
     type: string
-    description: DCAE Collector Database Floating IP Address
-
   dcae_hdp1_float_ip:
     type: string
-    description: Hadoop VM1 Floating IP Address
-
   dcae_hdp2_float_ip:
     type: string
-    description: Hadoop VM2 Floating IP Address
-
   dcae_hdp3_float_ip:
     type: string
-    description: Hadoop VM3 Floating IP Address
 
   ###########################
   #                         #
@@ -290,6 +244,107 @@ parameters:
     type: string
     description: DCAE Code Version Number
 
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+
+  aai_repo:
+    type: string
+  appc_repo:
+    type: string
+  dcae_repo:
+    type: string
+  mr_repo:
+    type: string
+  so_repo:
+    type: string
+  policy_repo:
+    type: string
+  portal_repo:
+    type: string
+  robot_repo:
+    type: string
+  sdc_repo:
+    type: string
+  sdnc_repo:
+    type: string
+  vid_repo:
+    type: string
+  clamp_repo:
+    type: string
+  vnfsdk_repo:
+    type: string
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_docker:
+    type: string
+  appc_docker:
+    type: string
+  so_docker:
+    type: string
+  mr_docker:
+    type: string
+  dcae_docker:
+    type: string
+  policy_docker:
+    type: string
+  portal_docker:
+    type: string
+  robot_docker:
+    type: string
+  sdc_docker:
+    type: string
+  sdnc_docker:
+    type: string
+  vid_docker:
+    type: string
+  clamp_docker:
+    type: string
+  msb_docker:
+    type: string
+  mvim_docker:
+    type: string
+  vfc_docker:
+    type: string
+  uui_docker:
+    type: string
+  dgbuilder_docker:
+    type: string
+
+  aai_branch:
+    type: string
+  appc_branch:
+    type: string
+  so_branch:
+    type: string
+  mr_branch:
+    type: string
+  dcae_branch:
+    type: string
+  policy_branch:
+    type: string
+  portal_branch:
+    type: string
+  robot_branch:
+    type: string
+  sdc_branch:
+    type: string
+  sdnc_branch:
+    type: string
+  vid_branch:
+    type: string
+  clamp_branch:
+    type: string
+  vnfsdk_branch:
+    type: string
+
 
 #############
 #           #
@@ -319,24 +374,24 @@ resources:
 
 
   # ONAP management private network
-  oam_ecomp:
+  oam_onap:
     type: OS::Neutron::Net
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
 
-  oam_ecomp_subnet:
+  oam_onap_subnet:
     type: OS::Neutron::Subnet
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
-      network_id: { get_resource: oam_ecomp }
+      network_id: { get_resource: oam_onap }
       cidr: { get_param: oam_network_cidr }
       dns_nameservers: { get_param: dns_list }
 
@@ -350,15 +405,15 @@ resources:
     type: OS::Neutron::RouterInterface
     properties:
       router_id: { get_resource: router }
-      subnet_id: { get_resource: oam_ecomp_subnet }
+      subnet_id: { get_resource: oam_onap_subnet }
 
 
   # DNS Server instantiation
   dns_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}]
 
   dns_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -385,14 +440,14 @@ resources:
           params:
             __nexus_repo__: { get_param: nexus_repo }
             __artifacts_version__: { get_param: artifacts_version }
-            __oam_network_cidr__: { get_attr: [oam_ecomp_subnet, cidr] }
+            __oam_network_cidr__: { get_attr: [oam_onap_subnet, cidr] }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __aai1_ip_addr__: { get_param: aai1_ip_addr }
             __aai2_ip_addr__: { get_param: aai2_ip_addr }
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
             __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
@@ -400,6 +455,8 @@ resources:
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
           template: |
@@ -417,7 +474,7 @@ resources:
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
             echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
@@ -425,6 +482,8 @@ resources:
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
 
             # Download and run install script
@@ -438,8 +497,8 @@ resources:
   aai1_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
 
   aai1_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -472,10 +531,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -493,19 +553,20 @@ resources:
             echo "aai_instance_1" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
   aai2_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
 
   aai2_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -537,10 +598,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -558,40 +620,41 @@ resources:
             echo "aai_instance_2" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}]
 
-  mso_floating_ip:
+  so_floating_ip:
     type: OS::Neutron::FloatingIP
     properties:
       floating_network_id: { get_param: public_net_id }
-      port_id: { get_resource: mso_private_port }
+      port_id: { get_resource: so_private_port }
 
-  mso_vm:
+  so_vm:
     type: OS::Nova::Server
     properties:
       image: { get_param: ubuntu_1604_image }
       flavor: { get_param: flavor_large }
       name:
         str_replace:
-          template: base-mso
+          template: base-so
           params:
             base: { get_param: vm_base_name }      
       key_name: { get_resource: vm_key }
       networks:
-        - port: { get_resource: mso_private_port }
+        - port: { get_resource: so_private_port }
       user_data_format: RAW
       user_data:
         str_replace:
@@ -608,10 +671,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: so_docker }
+            __gerrit_branch__: { get_param: so_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -633,20 +697,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__so_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh
             cd /opt
-            chmod +x mso_install.sh
-            ./mso_install.sh
+            chmod +x so_install.sh
+            ./so_install.sh
 
 
   # Message Router instantiation
   mrouter_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}]
 
   mrouter_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -677,9 +742,10 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: mr_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -694,6 +760,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__mr_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh
@@ -706,8 +773,8 @@ resources:
   robot_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}]
 
   robot_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -736,30 +803,34 @@ resources:
             __nexus_docker_repo__: { get_param: nexus_docker_repo }
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
-            __network_name__: { get_attr: [oam_ecomp, name] }
+            __network_name__: { get_attr: [oam_onap, name] }
             __openstack_username__: { get_param: openstack_username }
             __openstack_api_key__: { get_param : openstack_api_key }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
             __artifacts_version__: { get_param: artifacts_version }
             __openstack_region__: { get_param: openstack_region }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: mr_docker }
+            __gerrit_branch__: { get_param: mr_branch }
             __cloud_env__: { get_param: cloud_env }
             __keystone_url__: { get_param: keystone_url }
             __aai1_ip_addr__: { get_param: aai1_ip_addr }
             __aai2_ip_addr__: { get_param: aai2_ip_addr }
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __external_dns__: { get_param: external_dns }
-            __vm_image_name__: { get_param: ubuntu_1404_image}
-            __vm_flavor__: { get_param: flavor_medium}
+            __vm_image_name__: { get_param: ubuntu_1404_image }
+            __vm_flavor__: { get_param: flavor_medium }
+            __robot_repo__: { get_param: robot_repo }
           template: |
             #!/bin/bash
 
@@ -772,6 +843,7 @@ resources:
             echo "__network_name__" > /opt/config/network.txt
             echo "__openstack_username__" > /opt/config/openstack_username.txt
             echo "__openstack_api_key__" > /opt/config/openstack_password.txt
+            echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt
             echo "__openstack_region__" > /opt/config/region.txt
             echo "__artifacts_version__" > /opt/config/artifacts_version.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
@@ -782,17 +854,20 @@ resources:
             echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
             echo "__vm_image_name__" > /opt/config/vm_image_name.txt
             echo "__vm_flavor__" > /opt/config/vm_flavor.txt
+            echo "__robot_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh
@@ -805,8 +880,8 @@ resources:
   vid_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}]
 
   vid_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -837,10 +912,11 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: vid_docker }
+            __gerrit_branch__: { get_param: vid_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __vid_repo__: { get_param: vid_repo }
           template: |
             #!/bin/bash
 
@@ -856,6 +932,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vid_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh
@@ -868,8 +945,8 @@ resources:
   sdnc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
 
   sdnc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -900,10 +977,12 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdnc_docker }
+            __gerrit_branch__: { get_param: sdnc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdnc_repo__: { get_param: sdnc_repo }
           template: |
             #!/bin/bash
 
@@ -917,8 +996,10 @@ resources:
             echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdnc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh
@@ -931,8 +1012,8 @@ resources:
   sdc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
 
   sdc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -975,10 +1056,11 @@ resources:
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __public_ip__: { get_attr: [sdc_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdc_docker }
+            __gerrit_branch__: { get_param: sdc_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdc_repo__: { get_param: sdc_repo }
           template: |
             #!/bin/bash
 
@@ -997,20 +1079,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh
             cd /opt
-            chmod +x asdc_install.sh
-            ./asdc_install.sh
+            chmod +x sdc_install.sh
+            ./sdc_install.sh
 
 
   # PORTAL instantiation
   portal_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}]
 
   portal_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1042,10 +1125,11 @@ resources:
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __public_ip__: { get_attr: [portal_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: portal_docker }
+            __gerrit_branch__: { get_param: portal_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __portal_repo__: { get_param: portal_repo }
           template: |
             #!/bin/bash
 
@@ -1062,6 +1146,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__portal_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh
@@ -1074,8 +1159,8 @@ resources:
   dcae_c_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
 
   dcae_c_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1111,7 +1196,7 @@ resources:
             __dcae_state__: { get_param: dcae_state }
             __artifacts_version__: { get_param: artifacts_version }
             __tenant_id__: { get_param: openstack_tenant_id }
-            __openstack_private_network_name__: { get_attr: [oam_ecomp, name] }
+            __openstack_private_network_name__: { get_attr: [oam_onap, name] }
             __openstack_user__: { get_param: openstack_username }
             __openstack_password__: { get_param: openstack_api_key }
             __openstack_auth_method__: { get_param: openstack_auth_method }
@@ -1122,8 +1207,8 @@ resources:
             __openstack_region__: { get_param: openstack_region }
             __horizon_url__: { get_param: horizon_url }
             __keystone_url__: { get_param: keystone_url }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: dcae_docker }
+            __gerrit_branch__: { get_param: dcae_branch }
             __dcae_code_version__: { get_param: dcae_code_version }
             __cloud_env__: { get_param: cloud_env }
             __public_net_id__: { get_param: public_net_id }
@@ -1147,6 +1232,8 @@ resources:
             __flavor_medium__: { get_param: flavor_medium }
             __flavor_large__: { get_param: flavor_large }
             __flavor_xlarge__: { get_param: flavor_xlarge }
+            __dcae_repo__: { get_param: dcae_repo }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -1199,6 +1286,8 @@ resources:
             echo "__flavor_medium__" > /opt/config/flavor_medium.txt
             echo "__flavor_large__" > /opt/config/flavor_large.txt
             echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt
+            echo "__dcae_repo__" > /opt/config/remote_repo.txt
+            echo "__mr_repo__" > /opt/config/mr_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh
@@ -1211,8 +1300,8 @@ resources:
   policy_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}]
 
   policy_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1244,10 +1333,11 @@ resources:
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __public_ip__: { get_attr: [policy_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: policy_docker }
+            __gerrit_branch__: { get_param: policy_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __policy_repo__: { get_param: policy_repo }
           template: |
             #!/bin/bash
 
@@ -1264,6 +1354,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__policy_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh
@@ -1276,8 +1367,8 @@ resources:
   appc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}]
 
   appc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1309,10 +1400,12 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: appc_docker }
+            __gerrit_branch__: { get_param: appc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __appc_repo__: { get_param: appc_repo }
           template: |
             #!/bin/bash
 
@@ -1327,11 +1420,195 @@ resources:
             echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__appc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh
             cd /opt
             chmod +x appc_install.sh
-            ./appc_install.sh
\ No newline at end of file
+            ./appc_install.sh
+
+
+  # CLAMP instantiation
+  clamp_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}]
+
+  clamp_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: clamp_private_port }
+
+  clamp_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_medium }
+      name:
+        str_replace:
+          template: base-clamp
+          params:
+            base: { get_param: vm_base_name }      
+      key_name: { get_resource: vm_key }
+      networks:
+        - port: { get_resource: clamp_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __openstack_username__: { get_param: openstack_username }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
+            __openstack_api_key__: { get_param: openstack_api_key }
+            __openstack_region__: { get_param: openstack_region }
+            __keystone_url__: { get_param: keystone_url }
+            __dmaap_topic__: { get_param: dmaap_topic }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __docker_version__: { get_param: clamp_docker }
+            __gerrit_branch__: { get_param: clamp_branch }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __clamp_repo__: { get_param: clamp_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
+            echo "__openstack_username__" > /opt/config/openstack_username.txt
+            echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt
+            echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt
+            echo "__openstack_region__" > /opt/config/openstack_region.txt
+            echo "__keystone_url__" > /opt/config/keystone.txt
+            echo "__docker_version__" > /opt/config/docker_version.txt
+            echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__clamp_repo__" > /opt/config/remote_repo.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh
+            cd /opt
+            chmod +x clamp_install.sh
+            ./clamp_install.sh
+
+
+  # OPEN-O VM instantiation
+  openo_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}]
+
+  openo_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: openo_private_port }
+
+  openo_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_xxlarge }
+      name:
+        str_replace:
+          template: base-openo-server
+          params:
+            base: { get_param: vm_base_name }
+      key_name: { get_resource: vm_key }
+      networks:
+        - port: { get_resource: openo_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __oam_network_cidr__: { get_param: oam_network_cidr }
+            __aai1_ip_addr__: { get_param: aai1_ip_addr }
+            __aai2_ip_addr__: { get_param: aai2_ip_addr }
+            __appc_ip_addr__: { get_param: appc_ip_addr }
+            __dcae_ip_addr__: { get_param: dcae_ip_addr }
+            __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
+            __mr_ip_addr__: { get_param: mr_ip_addr }
+            __policy_ip_addr__: { get_param: policy_ip_addr }
+            __portal_ip_addr__: { get_param: portal_ip_addr }
+            __robot_ip_addr__: { get_param: robot_ip_addr }
+            __sdc_ip_addr__: { get_param: sdc_ip_addr }
+            __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
+            __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __vnfsdk_branch__: { get_param: vnfsdk_branch }
+            __msb_docker__: { get_param: msb_docker }
+            __mvim_docker__: { get_param: mvim_docker }
+            __vfc_docker__: { get_param: vfc_docker }
+            __uui_docker__: { get_param: uui_docker }
+            __vnfsdk_repo__: { get_param: vnfsdk_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt
+            echo "__msb_docker__" > /opt/config/msb_docker.txt
+            echo "__mvim_docker__" > /opt/config/mvim_docker.txt
+            echo "__vfc_docker__" > /opt/config/vfc_docker.txt
+            echo "__uui_docker__" > /opt/config/uui_docker.txt
+            echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt
+
+            # Create env file with the IP address of all ONAP components
+            echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh
+            cd /opt
+            chmod +x openo_install.sh
+            ./openo_install.sh
\ No newline at end of file
index 4f3a42d..4b7e9f4 100644 (file)
@@ -24,6 +24,8 @@ parameters:
 
   flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE
 
+  flavor_xxlarge: PUT THE XXLARGE FLAVOR NAME HERE
+
   vm_base_name: vm1
 
   key_name: onap_key
@@ -42,10 +44,6 @@ parameters:
 
   artifacts_version: 1.1.0-SNAPSHOT
 
-  docker_version: 1.1-STAGING-latest
-
-  gerrit_branch: master
-
   openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE
 
   openstack_username: PUT YOUR OPENSTACK USERNAME HERE
@@ -71,6 +69,7 @@ parameters:
 
   dns_list: PUT THE ADDRESS OF THE EXTERNAL DNS HERE (e.g. a comma-separated list of IP addresses in your /etc/resolv.conf in UNIX-based Operating Systems)
   external_dns: PUT THE FIRST ADDRESS OF THE EXTERNAL DNS LIST HERE
+  oam_network_cidr: 10.0.0.0/16
 
   ### Floating IP addresses ###
 
@@ -84,7 +83,7 @@ parameters:
   dcae_hdp2_float_ip: PUT DCAE HADOOP VM2 FLOATING IP HERE
   dcae_hdp3_float_ip: PUT DCAE HADOOP VM3 FLOATING IP HERE
   dns_float_ip: PUT DNS FLOATING IP HERE
-  mso_float_ip: PUT MSO FLOATING IP HERE
+  so_float_ip: PUT SO FLOATING IP HERE
   mr_float_ip: PUT MESSAGE ROUTER FLOATING IP HERE
   policy_float_ip: PUT POLICY FLOATING IP HERE
   portal_float_ip: PUT PORTAL FLOATING IP HERE
@@ -92,11 +91,11 @@ parameters:
   sdc_float_ip: PUT SDC FLOATING IP HERE
   sdnc_float_ip: PUT SDN-C FLOATING IP HERE
   vid_float_ip: PUT VID FLOATING IP HERE
-
+  clamp_float_ip: PUT CLAMP FLOATING IP HERE
+  openo_float_ip: PUT OPEN-O FLOATING IP HERE
 
   ### Private IP addresses ###
 
-  oam_network_cidr: 10.0.0.0/16
   aai1_ip_addr: 10.0.1.1
   aai2_ip_addr: 10.0.1.2
   appc_ip_addr: 10.0.2.1
@@ -107,7 +106,7 @@ parameters:
   dcae_hdp2_ip_addr: 10.0.4.104
   dcae_hdp3_ip_addr: 10.0.4.105
   dns_ip_addr: 10.0.100.1
-  mso_ip_addr: 10.0.5.1
+  so_ip_addr: 10.0.5.1
   mr_ip_addr: 10.0.11.1
   policy_ip_addr: 10.0.6.1
   portal_ip_addr: 10.0.9.1
@@ -115,6 +114,8 @@ parameters:
   sdc_ip_addr: 10.0.3.1
   sdnc_ip_addr: 10.0.7.1
   vid_ip_addr: 10.0.8.1
+  clamp_ip_addr: 10.0.12.1
+  openo_ip_addr: 10.0.14.1
 
   ###########################
   #                         #
@@ -135,3 +136,61 @@ parameters:
   gitlab_branch: master
 
   dcae_code_version: 1.1.0
+
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_branch: master
+  appc_branch: master
+  so_branch: master
+  mr_branch: master
+  dcae_branch: master
+  policy_branch: master
+  portal_branch: master
+  robot_branch: master
+  sdc_branch: master
+  sdnc_branch: master
+  vid_branch: master
+  clamp_branch: master
+  vnfsdk_branch: master
+
+  aai_docker: 1.1-STAGING-latest
+  appc_docker: 1.1-STAGING-latest
+  so_docker: 1.1-STAGING-latest
+  mr_docker: 1.1-STAGING-latest
+  dcae_docker: 1.1-STAGING-latest
+  policy_docker: 1.1-STAGING-latest
+  portal_docker: 1.1-STAGING-latest
+  robot_docker: 1.1-STAGING-latest
+  sdc_docker: 1.1-STAGING-latest
+  sdnc_docker: 1.2-STAGING-latest
+  vid_docker: 1.1-STAGING-latest
+  clamp_docker: 1.1-STAGING-latest
+  msb_docker: latest
+  mvim_docker: latest
+  vfc_docker: latest
+  uui_docker: latest
+  dgbuilder_docker: 0.1-STAGING-latest
+
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+  aai_repo: http://gerrit.onap.org/r/aai/test-config
+  appc_repo: http://gerrit.onap.org/r/appc/deployment.git
+  dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git
+  mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git 
+  so_repo: http://gerrit.onap.org/r/so/docker-config.git
+  policy_repo: http://gerrit.onap.org/r/policy/docker.git
+  portal_repo: http://gerrit.onap.org/r/portal.git
+  robot_repo: http://gerrit.onap.org/r/testsuite/properties.git
+  sdc_repo: http://gerrit.onap.org/r/sdc.git
+  sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git
+  vid_repo: http://gerrit.onap.org/r/vid.git
+  clamp_repo: http://gerrit.onap.org/r/clamp.git
+  vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git
index af49a77..438be71 100644 (file)
@@ -44,14 +44,6 @@ parameters:
     type: string
     description: Public network for floating IP address allocation
 
-  public_subnet_id:
-    type: string
-    description: Public network subnet id
-
-  router_gateway_ip:
-    type: string
-    description: Public network gateway IP address
-
   ubuntu_1404_image:
     type: string
     description: Name of the Ubuntu 14.04 image
@@ -76,6 +68,10 @@ parameters:
     type: string
     description: Name of the Extra Large Flavor supported by the cloud provider
 
+  flavor_xxlarge:
+    type: string
+    description: Name of the Extra Extra Large Flavor supported by the cloud provider
+
   vm_base_name:
     type: string
     description: Base name of ONAP VMs
@@ -108,15 +104,6 @@ parameters:
     type: string
     description: Artifacts version of ONAP components
 
-  docker_version:
-    type: string
-    label: Version number of ONAP docker images
-
-  gerrit_branch:
-    type: string
-    label: Gerrit code branch
-    description: Gerrit branch where to download the code from
-
   dmaap_topic:
     type: string
     description: DMaaP Topic name
@@ -135,7 +122,7 @@ parameters:
 
   openstack_api_key:
     type: string
-    description: Openstack API Key
+    description: Openstack password or API Key
 
   horizon_url:
     type: string
@@ -149,6 +136,7 @@ parameters:
     type: string
     description: Cloud Provider Name
 
+
   ######################
   #                    #
   # Network parameters #
@@ -163,155 +151,94 @@ parameters:
     type: string
     description: First element of the dns_list for ONAP network
 
+  oam_network_cidr:
+    type: string
+    description: CIDR of the OAM ONAP network
+
   ### Floating IP addresses ###
   aai1_float_ip:
     type: string
-    description: AAI Instance 1 Floating IP Address
-
   aai2_float_ip:
     type: string
-    description: AAI Instance 2 Floating IP Address
-
   appc_float_ip:
     type: string
-    description: APP-C Floating IP Address
-
   dcae_float_ip:
     type: string
-    description: DCAE Floating IP Address
-
   dcae_coll_float_ip:
     type: string
-    description: DCAE Collector Floating IP Address
-
   dcae_db_float_ip:
     type: string
-    description: DCAE Collector Database Floating IP Address
-
   dcae_hdp1_float_ip:
     type: string
-    description: Hadoop VM1 Floating IP Address
-
   dcae_hdp2_float_ip:
     type: string
-    description: Hadoop VM2 Floating IP Address
-
   dcae_hdp3_float_ip:
     type: string
-    description: Hadoop VM3 Floating IP Address
-
   dns_float_ip:
     type: string
-    description: DNS Floating IP Address
-
-  mso_float_ip:
+  so_float_ip:
     type: string
-    description: MSO Floating IP Address
-
   mr_float_ip:
     type: string
-    description: Message Router Floating IP Address
-
   policy_float_ip:
     type: string
-    description: Policy Engine Floating IP Address
-
   portal_float_ip:
     type: string
-    description: Portal Floating IP Address
-
   robot_float_ip:
     type: string
-    description: Robot Framework Floating IP Address
-
   sdc_float_ip:
     type: string
-    description: SDC Floating IP Address
-
   sdnc_float_ip:
     type: string
-    description: SDN-C Floating IP Address
-
   vid_float_ip:
     type: string
-    description: VID Floating IP Address
-
-  ### Private IP addresses ###
-  oam_network_cidr:
+  clamp_float_ip:
     type: string
-    description: CIDR of the OAM ONAP network
+  openo_float_ip:
+    type: string
+  ### Private IP addresses ###
 
   aai1_ip_addr:
     type: string
-    description: AAI Instance 1 IP Address
-
   aai2_ip_addr:
     type: string
-    description: AAI Instance 2 IP Address
-
   appc_ip_addr:
     type: string
-    description: APP-C IP Address
-
   dcae_ip_addr:
     type: string
-    description: DCAE IP Address
   dcae_coll_ip_addr:
     type: string
-    description: DCAE Collector IP Address
-
   dcae_db_ip_addr:
     type: string
-    description: DCAE Database IP Address
-
   dcae_hdp1_ip_addr:
     type: string
-    description: Hadoop VM1 IP Address
-
   dcae_hdp2_ip_addr:
     type: string
-    description: Hadoop VM2 IP Address
-
   dcae_hdp3_ip_addr:
     type: string
-    description: Hadoop VM3 IP Address
-
   dns_ip_addr:
     type: string
-    description: DNS IP Address
-
-  mso_ip_addr:
+  so_ip_addr:
     type: string
-    description: MSO IP Address
-
   mr_ip_addr:
     type: string
-    description: Message Router IP Address
-
   policy_ip_addr:
     type: string
-    description: Policy Engine IP Address
-
   portal_ip_addr:
     type: string
-    description: Portal IP Address
-
   robot_ip_addr:
     type: string
-    description: Robot Framework IP Address
-
   sdc_ip_addr:
     type: string
-    description: SDC IP Address
-
   sdnc_ip_addr:
     type: string
-    description: SDN-C IP Address
-
   vid_ip_addr:
     type: string
-    description: VID IP Address
+  clamp_ip_addr:
+    type: string
+  openo_ip_addr:
+    type: string
 
 
   ###########################
@@ -352,6 +279,107 @@ parameters:
     type: string
     description: DCAE Code Version Number
 
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+
+  aai_repo:
+    type: string
+  appc_repo:
+    type: string
+  dcae_repo:
+    type: string
+  mr_repo:
+    type: string
+  so_repo:
+    type: string
+  policy_repo:
+    type: string
+  portal_repo:
+    type: string
+  robot_repo:
+    type: string
+  sdc_repo:
+    type: string
+  sdnc_repo:
+    type: string
+  vid_repo:
+    type: string
+  clamp_repo:
+    type: string
+  vnfsdk_repo:
+    type: string
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_docker:
+    type: string
+  appc_docker:
+    type: string
+  so_docker:
+    type: string
+  mr_docker:
+    type: string
+  dcae_docker:
+    type: string
+  policy_docker:
+    type: string
+  portal_docker:
+    type: string
+  robot_docker:
+    type: string
+  sdc_docker:
+    type: string
+  sdnc_docker:
+    type: string
+  vid_docker:
+    type: string
+  clamp_docker:
+    type: string
+  msb_docker:
+    type: string
+  mvim_docker:
+    type: string
+  vfc_docker:
+    type: string
+  uui_docker:
+    type: string
+  dgbuilder_docker:
+    type: string
+
+  aai_branch:
+    type: string
+  appc_branch:
+    type: string
+  so_branch:
+    type: string
+  mr_branch:
+    type: string
+  dcae_branch:
+    type: string
+  policy_branch:
+    type: string
+  portal_branch:
+    type: string
+  robot_branch:
+    type: string
+  sdc_branch:
+    type: string
+  sdnc_branch:
+    type: string
+  vid_branch:
+    type: string
+  clamp_branch:
+    type: string
+  vnfsdk_branch:
+    type: string
+
 
 #############
 #           #
@@ -381,24 +409,24 @@ resources:
 
 
   # ONAP management private network
-  oam_ecomp:
+  oam_onap:
     type: OS::Neutron::Net
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
 
-  oam_ecomp_subnet:
+  oam_onap_subnet:
     type: OS::Neutron::Subnet
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
-      network_id: { get_resource: oam_ecomp }
+      network_id: { get_resource: oam_onap }
       cidr: { get_param: oam_network_cidr }
       dns_nameservers: { get_param: dns_list }
 
@@ -415,15 +443,15 @@ resources:
     type: OS::Neutron::RouterInterface
     properties:
       router_id: { get_resource: router }
-      subnet_id: { get_resource: oam_ecomp_subnet }
+      subnet_id: { get_resource: oam_onap_subnet }
 
 
   # DNS Server instantiation
   dns_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}]
 
   dns_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -451,14 +479,14 @@ resources:
           params:
             __nexus_repo__: { get_param: nexus_repo }
             __artifacts_version__: { get_param: artifacts_version }
-            __oam_network_cidr__: { get_attr: [oam_ecomp_subnet, cidr] }
+            __oam_network_cidr__: { get_attr: [oam_onap_subnet, cidr] }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __aai1_ip_addr__: { get_param: aai1_ip_addr }
             __aai2_ip_addr__: { get_param: aai2_ip_addr }
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
             __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
@@ -466,6 +494,8 @@ resources:
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
           template: |
@@ -483,7 +513,7 @@ resources:
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
             echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
@@ -491,6 +521,8 @@ resources:
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
 
             # Download and run install script
@@ -504,8 +536,8 @@ resources:
   aai1_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
 
   aai1_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -539,10 +571,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
+            __docker_version__: { get_param: aai_docker }
             __cloud_env__: { get_param: cloud_env }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: aai_branch }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -560,19 +593,20 @@ resources:
             echo "aai_instance_1" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
   aai2_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
 
   aai2_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -605,10 +639,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
+            __docker_version__: { get_param: aai_docker }
             __cloud_env__: { get_param: cloud_env }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: aai_branch }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -626,41 +661,42 @@ resources:
             echo "aai_instance_2" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}]
 
-  mso_floating_ip:
+  so_floating_ip:
     type: OS::Neutron::FloatingIP
     properties:
       floating_network_id: { get_param: public_net_id }
-      port_id: { get_resource: mso_private_port }
-      floating_ip_address: { get_param: mso_float_ip }
+      port_id: { get_resource: so_private_port }
+      floating_ip_address: { get_param: so_float_ip }
 
-  mso_vm:
+  so_vm:
     type: OS::Nova::Server
     properties:
       image: { get_param: ubuntu_1604_image }
       flavor: { get_param: flavor_large }
       name:
         str_replace:
-          template: base-mso
+          template: base-so
           params:
             base: { get_param: vm_base_name }      
       key_name: { get_resource: vm_key }
       networks:
-        - port: { get_resource: mso_private_port }
+        - port: { get_resource: so_private_port }
       user_data_format: RAW
       user_data:
         str_replace:
@@ -677,10 +713,11 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: so_docker }
+            __gerrit_branch__: { get_param: so_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -702,20 +739,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__so_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh
             cd /opt
-            chmod +x mso_install.sh
-            ./mso_install.sh
+            chmod +x so_install.sh
+            ./so_install.sh
 
 
   # Message Router instantiation
   mrouter_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}]
 
   mrouter_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -747,9 +785,10 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: mr_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -764,6 +803,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__mr_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh
@@ -776,8 +816,8 @@ resources:
   robot_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}]
 
   robot_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -807,30 +847,34 @@ resources:
             __nexus_docker_repo__: { get_param: nexus_docker_repo }
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
-            __network_name__: { get_attr: [oam_ecomp, name] }
+            __network_name__: { get_attr: [oam_onap, name] }
             __openstack_username__: { get_param: openstack_username }
             __openstack_api_key__: { get_param : openstack_api_key }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
             __artifacts_version__: { get_param: artifacts_version }
             __openstack_region__: { get_param: openstack_region }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: robot_docker }
+            __gerrit_branch__: { get_param: robot_branch }
             __keystone_url__: { get_param: keystone_url }
             __aai1_ip_addr__: { get_param: aai1_ip_addr }
             __aai2_ip_addr__: { get_param: aai2_ip_addr }
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
-            __vm_image_name__: { get_param: ubuntu_1404_image}
-            __vm_flavor__: { get_param: flavor_medium}
+            __vm_image_name__: { get_param: ubuntu_1404_image }
+            __vm_flavor__: { get_param: flavor_medium }
+            __robot_repo__: { get_param: robot_repo }
           template: |
             #!/bin/bash
 
@@ -843,6 +887,7 @@ resources:
             echo "__network_name__" > /opt/config/network.txt
             echo "__openstack_username__" > /opt/config/openstack_username.txt
             echo "__openstack_api_key__" > /opt/config/openstack_password.txt
+            echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt
             echo "__openstack_region__" > /opt/config/region.txt
             echo "__artifacts_version__" > /opt/config/artifacts_version.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
@@ -853,17 +898,20 @@ resources:
             echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
             echo "__vm_image_name__" > /opt/config/vm_image_name.txt
             echo "__vm_flavor__" > /opt/config/vm_flavor.txt
+            echo "__robot_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh
@@ -876,8 +924,8 @@ resources:
   vid_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}]
 
   vid_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -909,10 +957,11 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: vid_docker }
+            __gerrit_branch__: { get_param: vid_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __vid_repo__: { get_param: vid_repo }
           template: |
             #!/bin/bash
 
@@ -928,6 +977,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vid_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh
@@ -940,8 +990,8 @@ resources:
   sdnc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
 
   sdnc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -973,10 +1023,12 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdnc_docker }
+            __gerrit_branch__: { get_param: sdnc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdnc_repo__: { get_param: sdnc_repo }
           template: |
             #!/bin/bash
 
@@ -990,8 +1042,10 @@ resources:
             echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdnc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh
@@ -1004,8 +1058,8 @@ resources:
   sdc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
 
   sdc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1049,10 +1103,11 @@ resources:
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __public_ip__: { get_attr: [sdc_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdc_docker }
+            __gerrit_branch__: { get_param: sdc_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdc_repo__: { get_param: sdc_repo }
           template: |
             #!/bin/bash
 
@@ -1071,20 +1126,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh
             cd /opt
-            chmod +x asdc_install.sh
-            ./asdc_install.sh
+            chmod +x sdc_install.sh
+            ./sdc_install.sh
 
 
   # PORTAL instantiation
   portal_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}]
 
   portal_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1117,10 +1173,11 @@ resources:
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __public_ip__: { get_attr: [portal_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: portal_docker }
+            __gerrit_branch__: { get_param: portal_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __portal_repo__: { get_param: portal_repo }
           template: |
             #!/bin/bash
 
@@ -1137,6 +1194,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__portal_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh
@@ -1149,8 +1207,8 @@ resources:
   dcae_c_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
 
   dcae_c_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1187,7 +1245,7 @@ resources:
             __dcae_state__: { get_param: dcae_state }
             __artifacts_version__: { get_param: artifacts_version }
             __tenant_id__: { get_param: openstack_tenant_id }
-            __openstack_private_network_name__: { get_attr: [oam_ecomp, name] }
+            __openstack_private_network_name__: { get_attr: [oam_onap, name] }
             __openstack_user__: { get_param: openstack_username }
             __openstack_password__: { get_param: openstack_api_key }
             __openstack_auth_method__: { get_param: openstack_auth_method }
@@ -1198,8 +1256,8 @@ resources:
             __openstack_region__: { get_param: openstack_region }
             __horizon_url__: { get_param: horizon_url }
             __keystone_url__: { get_param: keystone_url }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: dcae_docker }
+            __gerrit_branch__: { get_param: dcae_branch }
             __dcae_code_version__: { get_param: dcae_code_version }
             __cloud_env__: { get_param: cloud_env }
             __public_net_id__: { get_param: public_net_id }
@@ -1223,6 +1281,8 @@ resources:
             __flavor_medium__: { get_param: flavor_medium }
             __flavor_large__: { get_param: flavor_large }
             __flavor_xlarge__: { get_param: flavor_xlarge }
+            __dcae_repo__: { get_param: dcae_repo }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -1275,6 +1335,8 @@ resources:
             echo "__flavor_medium__" > /opt/config/flavor_medium.txt
             echo "__flavor_large__" > /opt/config/flavor_large.txt
             echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt
+            echo "__dcae_repo__" > /opt/config/remote_repo.txt
+            echo "__mr_repo__" > /opt/config/mr_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh
@@ -1287,8 +1349,8 @@ resources:
   policy_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}]
 
   policy_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1321,10 +1383,11 @@ resources:
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __public_ip__: { get_attr: [policy_floating_ip, floating_ip_address] }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: policy_docker }
+            __gerrit_branch__: { get_param: policy_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __policy_repo__: { get_param: policy_repo }
           template: |
             #!/bin/bash
 
@@ -1341,6 +1404,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__policy_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh
@@ -1353,8 +1417,8 @@ resources:
   appc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}]
 
   appc_floating_ip:
     type: OS::Neutron::FloatingIP
@@ -1387,10 +1451,12 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: appc_docker }
+            __gerrit_branch__: { get_param: appc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __appc_repo__: { get_param: appc_repo }
           template: |
             #!/bin/bash
 
@@ -1405,11 +1471,197 @@ resources:
             echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__appc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh
             cd /opt
             chmod +x appc_install.sh
-            ./appc_install.sh
\ No newline at end of file
+            ./appc_install.sh
+
+
+  # CLAMP instantiation
+  clamp_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}]
+
+  clamp_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: clamp_private_port }
+      floating_ip_address: { get_param: clamp_float_ip }
+
+  clamp_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_medium }
+      name:
+        str_replace:
+          template: base-clamp
+          params:
+            base: { get_param: vm_base_name }      
+      key_name: { get_resource: vm_key }
+      networks:
+        - port: { get_resource: clamp_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __openstack_username__: { get_param: openstack_username }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
+            __openstack_api_key__: { get_param: openstack_api_key }
+            __openstack_region__: { get_param: openstack_region }
+            __keystone_url__: { get_param: keystone_url }
+            __dmaap_topic__: { get_param: dmaap_topic }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __docker_version__: { get_param: clamp_docker }
+            __gerrit_branch__: { get_param: clamp_branch }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __clamp_repo__: { get_param: clamp_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
+            echo "__openstack_username__" > /opt/config/openstack_username.txt
+            echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt
+            echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt
+            echo "__openstack_region__" > /opt/config/openstack_region.txt
+            echo "__keystone_url__" > /opt/config/keystone.txt
+            echo "__docker_version__" > /opt/config/docker_version.txt
+            echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__clamp_repo__" > /opt/config/remote_repo.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh
+            cd /opt
+            chmod +x clamp_install.sh
+            ./clamp_install.sh
+
+
+  # OPEN-O VM instantiation
+  openo_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}]
+
+  openo_floating_ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network_id: { get_param: public_net_id }
+      port_id: { get_resource: openo_private_port }
+      floating_ip_address: { get_param: onap_float_ip }
+
+  openo_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_xxlarge }
+      name:
+        str_replace:
+          template: base-openo-server
+          params:
+            base: { get_param: vm_base_name }
+      key_name: { get_resource: vm_key }
+      networks:
+        - port: { get_resource: openo_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __oam_network_cidr__: { get_param: oam_network_cidr }
+            __aai1_ip_addr__: { get_param: aai1_ip_addr }
+            __aai2_ip_addr__: { get_param: aai2_ip_addr }
+            __appc_ip_addr__: { get_param: appc_ip_addr }
+            __dcae_ip_addr__: { get_param: dcae_ip_addr }
+            __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
+            __mr_ip_addr__: { get_param: mr_ip_addr }
+            __policy_ip_addr__: { get_param: policy_ip_addr }
+            __portal_ip_addr__: { get_param: portal_ip_addr }
+            __robot_ip_addr__: { get_param: robot_ip_addr }
+            __sdc_ip_addr__: { get_param: sdc_ip_addr }
+            __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
+            __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __vnfsdk_branch__: { get_param: vnfsdk_branch }
+            __msb_docker__: { get_param: msb_docker }
+            __mvim_docker__: { get_param: mvim_docker }
+            __vfc_docker__: { get_param: vfc_docker }
+            __uui_docker__: { get_param: uui_docker }
+            __vnfsdk_repo__: { get_param: vnfsdk_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt
+            echo "__msb_docker__" > /opt/config/msb_docker.txt
+            echo "__mvim_docker__" > /opt/config/mvim_docker.txt
+            echo "__vfc_docker__" > /opt/config/vfc_docker.txt
+            echo "__uui_docker__" > /opt/config/uui_docker.txt
+            echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt
+
+            # Create env file with the IP address of all ONAP components
+            echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh
+            cd /opt
+            chmod +x openo_install.sh
+            ./openo_install.sh
\ No newline at end of file
index dad932b..086eced 100644 (file)
@@ -20,6 +20,8 @@ parameters:
 
   flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE
 
+  flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE
+
   vm_base_name: vm1
 
   key_name: onap_key
@@ -38,10 +40,6 @@ parameters:
 
   artifacts_version: 1.1.0-SNAPSHOT
 
-  docker_version: 1.1-STAGING-latest
-
-  gerrit_branch: master
-
   openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE
 
   openstack_username: PUT YOUR OPENSTACK USERNAME HERE
@@ -66,8 +64,10 @@ parameters:
   ######################
 
   external_dns: PUT THE ADDRESS OF THE EXTERNAL DNS HERE
-
   oam_network_cidr: 10.0.0.0/16
+
+  ### Private IP addresses ###
+
   aai1_ip_addr: 10.0.1.1
   aai2_ip_addr: 10.0.1.2
   appc_ip_addr: 10.0.2.1
@@ -78,7 +78,7 @@ parameters:
   dcae_hdp2_ip_addr: 10.0.4.104
   dcae_hdp3_ip_addr: 10.0.4.105
   dns_ip_addr: 10.0.100.1
-  mso_ip_addr: 10.0.5.1
+  so_ip_addr: 10.0.5.1
   mr_ip_addr: 10.0.11.1
   policy_ip_addr: 10.0.6.1
   portal_ip_addr: 10.0.9.1
@@ -86,7 +86,8 @@ parameters:
   sdc_ip_addr: 10.0.3.1
   sdnc_ip_addr: 10.0.7.1
   vid_ip_addr: 10.0.8.1
-
+  clamp_ip_addr: 10.0.12.1
+  openo_ip_addr: 10.0.14.1
 
   ###########################
   #                         #
@@ -108,3 +109,60 @@ parameters:
 
   dcae_code_version: 1.1.0
 
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_branch: master
+  appc_branch: master
+  so_branch: master
+  mr_branch: master
+  dcae_branch: master
+  policy_branch: master
+  portal_branch: master
+  robot_branch: master
+  sdc_branch: master
+  sdnc_branch: master
+  vid_branch: master
+  clamp_branch: master
+  vnfsdk_branch: master
+
+  aai_docker: 1.1-STAGING-latest
+  appc_docker: 1.1-STAGING-latest
+  so_docker: 1.1-STAGING-latest
+  mr_docker: 1.1-STAGING-latest
+  dcae_docker: 1.1-STAGING-latest
+  policy_docker: 1.1-STAGING-latest
+  portal_docker: 1.1-STAGING-latest
+  robot_docker: 1.1-STAGING-latest
+  sdc_docker: 1.1-STAGING-latest
+  sdnc_docker: 1.2-STAGING-latest
+  vid_docker: 1.1-STAGING-latest
+  clamp_docker: 1.1-STAGING-latest
+  msb_docker: latest
+  mvim_docker: latest
+  vfc_docker: latest
+  uui_docker: latest
+  dgbuilder_docker: 0.1-STAGING-latest
+
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+  aai_repo: http://gerrit.onap.org/r/aai/test-config
+  appc_repo: http://gerrit.onap.org/r/appc/deployment.git
+  dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git
+  mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git 
+  so_repo: http://gerrit.onap.org/r/so/docker-config.git
+  policy_repo: http://gerrit.onap.org/r/policy/docker.git
+  portal_repo: http://gerrit.onap.org/r/portal.git
+  robot_repo: http://gerrit.onap.org/r/testsuite/properties.git
+  sdc_repo: http://gerrit.onap.org/r/sdc.git
+  sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git
+  vid_repo: http://gerrit.onap.org/r/vid.git
+  clamp_repo: http://gerrit.onap.org/r/clamp.git
+  vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git
index b505d72..0d857ce 100644 (file)
@@ -68,6 +68,10 @@ parameters:
     type: string
     description: Name of the Extra Large Flavor supported by the cloud provider
 
+  flavor_xxlarge:
+    type: string
+    description: Name of the Extra Extra Large Flavor supported by the cloud provider
+
   vm_base_name:
     type: string
     description: Base name of ONAP VMs
@@ -100,15 +104,6 @@ parameters:
     type: string
     description: Artifacts version of ONAP components
 
-  docker_version:
-    type: string
-    label: Version number of ONAP docker images
-
-  gerrit_branch:
-    type: string
-    label: Gerrit code branch
-    description: Gerrit branch where to download the code from
-
   dmaap_topic:
     type: string
     description: DMaaP Topic name
@@ -127,7 +122,7 @@ parameters:
 
   openstack_api_key:
     type: string
-    description: Openstack API Key
+    description: Openstack password or API Key
 
   horizon_url:
     type: string
@@ -151,83 +146,52 @@ parameters:
     type: string
     description: External DNS for OAM ONAP network
 
-  ### Private IP addresses ###
   oam_network_cidr:
     type: string
     description: CIDR of the OAM ONAP network
 
+  ### Private IP addresses ###
+
   aai1_ip_addr:
     type: string
-    description: AAI Instance 1 IP Address
-
   aai2_ip_addr:
     type: string
-    description: AAI Instance 2 IP Address
-
   appc_ip_addr:
     type: string
-    description: APP-C IP Address
-
   dcae_ip_addr:
     type: string
-    description: DCAE IP Address
   dcae_coll_ip_addr:
     type: string
-    description: DCAE Collector IP Address
-
   dcae_db_ip_addr:
     type: string
-    description: DCAE Database IP Address
-
   dcae_hdp1_ip_addr:
     type: string
-    description: Hadoop VM1 IP Address
-
   dcae_hdp2_ip_addr:
     type: string
-    description: Hadoop VM2 IP Address
-
   dcae_hdp3_ip_addr:
     type: string
-    description: Hadoop VM3 IP Address
-
   dns_ip_addr:
     type: string
-    description: DNS IP Address
-
-  mso_ip_addr:
+  so_ip_addr:
     type: string
-    description: MSO IP Address
-
   mr_ip_addr:
     type: string
-    description: Message Router IP Address
-
   policy_ip_addr:
     type: string
-    description: Policy Engine IP Address
-
   portal_ip_addr:
     type: string
-    description: Portal IP Address
-
   robot_ip_addr:
     type: string
-    description: Robot Framework IP Address
-
   sdc_ip_addr:
     type: string
-    description: SDC IP Address
-
   sdnc_ip_addr:
     type: string
-    description: SDN-C IP Address
-
   vid_ip_addr:
     type: string
-    description: VID IP Address
-
+  clamp_ip_addr:
+    type: string
+  openo_ip_addr:
+    type: string
 
   ###########################
   #                         #
@@ -267,6 +231,107 @@ parameters:
     type: string
     description: DCAE Code Version Number
 
+  #####################
+  #                   #
+  # ONAP repositories #
+  #                   #
+  #####################
+
+  aai_repo:
+    type: string
+  appc_repo:
+    type: string
+  dcae_repo:
+    type: string
+  mr_repo:
+    type: string
+  so_repo:
+    type: string
+  policy_repo:
+    type: string
+  portal_repo:
+    type: string
+  robot_repo:
+    type: string
+  sdc_repo:
+    type: string
+  sdnc_repo:
+    type: string
+  vid_repo:
+    type: string
+  clamp_repo:
+    type: string
+  vnfsdk_repo:
+    type: string
+
+  ################################
+  #                              #
+  # Docker versions and branches #
+  #                              #
+  ################################
+
+  aai_docker:
+    type: string
+  appc_docker:
+    type: string
+  so_docker:
+    type: string
+  mr_docker:
+    type: string
+  dcae_docker:
+    type: string
+  policy_docker:
+    type: string
+  portal_docker:
+    type: string
+  robot_docker:
+    type: string
+  sdc_docker:
+    type: string
+  sdnc_docker:
+    type: string
+  vid_docker:
+    type: string
+  clamp_docker:
+    type: string
+  msb_docker:
+    type: string
+  mvim_docker:
+    type: string
+  vfc_docker:
+    type: string
+  uui_docker:
+    type: string
+  dgbuilder_docker:
+    type: string
+
+  aai_branch:
+    type: string
+  appc_branch:
+    type: string
+  so_branch:
+    type: string
+  mr_branch:
+    type: string
+  dcae_branch:
+    type: string
+  policy_branch:
+    type: string
+  portal_branch:
+    type: string
+  robot_branch:
+    type: string
+  sdc_branch:
+    type: string
+  sdnc_branch:
+    type: string
+  vid_branch:
+    type: string
+  clamp_branch:
+    type: string
+  vnfsdk_branch:
+    type: string
+
 
 #############
 #           #
@@ -296,24 +361,24 @@ resources:
 
 
   # ONAP management private network
-  oam_ecomp:
+  oam_onap:
     type: OS::Neutron::Net
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
 
-  oam_ecomp_subnet:
+  oam_onap_subnet:
     type: OS::Neutron::Subnet
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
-      network_id: { get_resource: oam_ecomp }
+      network_id: { get_resource: oam_onap }
       cidr: { get_param: oam_network_cidr }
 
 
@@ -321,8 +386,8 @@ resources:
   dns_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}]
 
   dns_vm:
     type: OS::Nova::Server
@@ -351,7 +416,7 @@ resources:
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
             __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
@@ -359,6 +424,8 @@ resources:
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
           template: |
@@ -376,7 +443,7 @@ resources:
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
             echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
@@ -384,6 +451,8 @@ resources:
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
 
             # Download and run install script
@@ -397,8 +466,8 @@ resources:
   aai1_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}]
 
   aai1_vm:
     type: OS::Nova::Server
@@ -428,10 +497,11 @@ resources:
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __aai_ip_addr__: { get_param: aai1_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -451,19 +521,20 @@ resources:
             echo "aai_instance_1" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
   aai2_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}]
 
   aai2_vm:
     type: OS::Nova::Server
@@ -492,10 +563,11 @@ resources:
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __aai_ip_addr__: { get_param: aai2_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -515,35 +587,36 @@ resources:
             echo "aai_instance_2" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}]
 
-  mso_vm:
+  so_vm:
     type: OS::Nova::Server
     properties:
       image: { get_param: ubuntu_1604_image }
       flavor: { get_param: flavor_large }
       name:
         str_replace:
-          template: base-mso
+          template: base-so
           params:
             base: { get_param: vm_base_name }      
       key_name: { get_resource: vm_key }
       networks:
         - network: { get_param: public_net_id }
-        - port: { get_resource: mso_private_port }
+        - port: { get_resource: so_private_port }
       user_data_format: RAW
       user_data:
         str_replace:
@@ -560,12 +633,13 @@ resources:
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
             __dns_ip_addr__: { get_param: dns_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: so_docker }
+            __gerrit_branch__: { get_param: so_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -576,7 +650,7 @@ resources:
             echo "__nexus_username__" > /opt/config/nexus_username.txt
             echo "__nexus_password__" > /opt/config/nexus_password.txt
             echo "__artifacts_version__" > /opt/config/artifacts_version.txt
-            echo "__mso_ip_addr__" > /opt/config/local_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/local_ip_addr.txt
             echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
             echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
             echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
@@ -589,20 +663,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__so_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh
             cd /opt
-            chmod +x mso_install.sh
-            ./mso_install.sh
+            chmod +x so_install.sh
+            ./so_install.sh
 
 
   # Message Router instantiation
   mrouter_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}]
 
   mrouter_vm:
     type: OS::Nova::Server
@@ -630,9 +705,10 @@ resources:
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: mr_gerrit }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -649,6 +725,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__mr_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh
@@ -661,8 +738,8 @@ resources:
   robot_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}]
  
   robot_vm:
     type: OS::Nova::Server
@@ -686,32 +763,36 @@ resources:
             __nexus_docker_repo__: { get_param: nexus_docker_repo }
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
-            __network_name__: { get_attr: [oam_ecomp, name] }
+            __network_name__: { get_attr: [oam_onap, name] }
             __openstack_username__: { get_param: openstack_username }
             __openstack_api_key__: { get_param : openstack_api_key }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
             __artifacts_version__: { get_param: artifacts_version }
             __openstack_region__: { get_param: openstack_region }
             __robot_ip_addr__: { get_param: robot_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: robot_docker }
+            __gerrit_branch__: { get_param: robot_branch }
             __keystone_url__: { get_param: keystone_url }
             __aai1_ip_addr__: { get_param: aai1_ip_addr }
             __aai2_ip_addr__: { get_param: aai2_ip_addr }
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dcae_ip_addr__: { get_param: dcae_ip_addr }
-            __mso_ip_addr__: { get_param: mso_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __portal_ip_addr__: { get_param: portal_ip_addr }
             __sdc_ip_addr__: { get_param: sdc_ip_addr }
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
-            __vm_image_name__: { get_param: ubuntu_1404_image}
-            __vm_flavor__: { get_param: flavor_medium}
+            __vm_image_name__: { get_param: ubuntu_1404_image }
+            __vm_flavor__: { get_param: flavor_medium }
+            __robot_repo__: { get_param: robot_repo }
           template: |
             #!/bin/bash
 
@@ -724,6 +805,7 @@ resources:
             echo "__network_name__" > /opt/config/network.txt
             echo "__openstack_username__" > /opt/config/openstack_username.txt
             echo "__openstack_api_key__" > /opt/config/openstack_password.txt
+            echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt
             echo "__openstack_region__" > /opt/config/region.txt
             echo "__artifacts_version__" > /opt/config/artifacts_version.txt
             echo "__robot_ip_addr__" > /opt/config/local_ip_addr.txt
@@ -736,17 +818,20 @@ resources:
             echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt
             echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt
             echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt
-            echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt
+            echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt
             echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt
             echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt
             echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt
             echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt
             echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt
+            echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt
+            echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
             echo "__vm_image_name__" > /opt/config/vm_image_name.txt
             echo "__vm_flavor__" > /opt/config/vm_flavor.txt
+            echo "__robot_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh
@@ -759,8 +844,8 @@ resources:
   vid_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}]
 
   vid_vm:
     type: OS::Nova::Server
@@ -788,10 +873,11 @@ resources:
             __vid_ip_addr__: { get_param: vid_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: vid_docker }
+            __gerrit_branch__: { get_param: vid_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __vid_repo__: { get_param: vid_repo }
           template: |
             #!/bin/bash
 
@@ -809,6 +895,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vid_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh
@@ -821,8 +908,8 @@ resources:
   sdnc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}]
 
   sdnc_vm:
     type: OS::Nova::Server
@@ -850,10 +937,12 @@ resources:
             __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdnc_docker }
+            __gerrit_branch__: { get_param: sdnc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdnc_repo__: { get_param: sdnc_repo }
           template: |
             #!/bin/bash
 
@@ -869,8 +958,10 @@ resources:
             echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdnc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh
@@ -883,8 +974,8 @@ resources:
   sdc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}]
 
   sdc_volume_data:
     type: OS::Cinder::Volume
@@ -923,10 +1014,11 @@ resources:
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
             __mr_ip_addr__: { get_param: mr_ip_addr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdc_docker }
+            __gerrit_branch__: { get_param: sdc_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __sdc_repo__: { get_param: sdc_repo }
           template: |
             #!/bin/bash
 
@@ -946,20 +1038,21 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__sdc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh
             cd /opt
-            chmod +x asdc_install.sh
-            ./asdc_install.sh
+            chmod +x sdc_install.sh
+            ./sdc_install.sh
 
 
   # PORTAL instantiation
   portal_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}]
 
   portal_vm:
     type: OS::Nova::Server
@@ -987,10 +1080,11 @@ resources:
             __portal_ip_addr__: { get_param: portal_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: portal_docker }
+            __gerrit_branch__: { get_param: portal_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __portal_repo__: { get_param: portal_repo }
           template: |
             #!/bin/bash
 
@@ -1008,6 +1102,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__portal_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh
@@ -1020,8 +1115,8 @@ resources:
   dcae_c_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}]
 
   dcae_c_vm:
     type: OS::Nova::Server
@@ -1053,7 +1148,7 @@ resources:
             __dcae_state__: { get_param: dcae_state }
             __artifacts_version__: { get_param: artifacts_version }
             __tenant_id__: { get_param: openstack_tenant_id }
-            __openstack_private_network_name__: { get_attr: [oam_ecomp, name] }
+            __openstack_private_network_name__: { get_attr: [oam_onap, name] }
             __openstack_user__: { get_param: openstack_username }
             __openstack_password__: { get_param: openstack_api_key }
             __openstack_auth_method__: { get_param: openstack_auth_method }
@@ -1064,8 +1159,8 @@ resources:
             __openstack_region__: { get_param: openstack_region }
             __horizon_url__: { get_param: horizon_url }
             __keystone_url__: { get_param: keystone_url }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: dcae_docker }
+            __gerrit_branch__: { get_param: dcae_branch }
             __dcae_code_version__: { get_param: dcae_code_version }
             __cloud_env__: { get_param: cloud_env }
             __public_net_id__: { get_param: public_net_id }
@@ -1083,6 +1178,8 @@ resources:
             __flavor_medium__: { get_param: flavor_medium }
             __flavor_large__: { get_param: flavor_large }
             __flavor_xlarge__: { get_param: flavor_xlarge }
+            __dcae_repo__: { get_param: dcae_repo }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -1130,6 +1227,8 @@ resources:
             echo "__flavor_medium__" > /opt/config/flavor_medium.txt
             echo "__flavor_large__" > /opt/config/flavor_large.txt
             echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt
+            echo "__dcae_repo__" > /opt/config/remote_repo.txt
+            echo "__mr_repo__" > /opt/config/mr_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh
@@ -1142,8 +1241,8 @@ resources:
   policy_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}]
 
   policy_vm:
     type: OS::Nova::Server
@@ -1171,10 +1270,11 @@ resources:
             __policy_ip_addr__: { get_param: policy_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: policy_docker }
+            __gerrit_branch__: { get_param: policy_branch }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __policy_repo__: { get_param: policy_repo }
           template: |
             #!/bin/bash
 
@@ -1192,6 +1292,7 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__policy_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh
@@ -1204,8 +1305,8 @@ resources:
   appc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}]
 
   appc_vm:
     type: OS::Nova::Server
@@ -1234,10 +1335,12 @@ resources:
             __appc_ip_addr__: { get_param: appc_ip_addr }
             __dns_ip_addr__: { get_param: dns_ip_addr }
             __oam_network_cidr__: { get_param: oam_network_cidr }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: appc_docker }
+            __gerrit_branch__: { get_param: appc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
             __external_dns__: { get_param: external_dns }
+            __appc_repo__: { get_param: appc_repo }
           template: |
             #!/bin/bash
 
@@ -1254,11 +1357,189 @@ resources:
             echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
             echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__appc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh
             cd /opt
             chmod +x appc_install.sh
-            ./appc_install.sh
\ No newline at end of file
+            ./appc_install.sh
+
+
+  # CLAMP instantiation
+  clamp_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}]
+
+  clamp_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_medium }
+      name:
+        str_replace:
+          template: base-clamp
+          params:
+            base: { get_param: vm_base_name }      
+      key_name: { get_resource: vm_key }
+      networks:
+        - network: { get_param: public_net_id }
+        - port: { get_resource: clamp_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __openstack_username__: { get_param: openstack_username }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
+            __openstack_api_key__: { get_param: openstack_api_key }
+            __openstack_region__: { get_param: openstack_region }
+            __keystone_url__: { get_param: keystone_url }
+            __dmaap_topic__: { get_param: dmaap_topic }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __oam_network_cidr__: { get_param: oam_network_cidr }
+            __docker_version__: { get_param: clamp_docker }
+            __gerrit_branch__: { get_param: clamp_branch }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __clamp_repo__: { get_param: clamp_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__clamp_ip_addr__" > /opt/config/local_ip_addr.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
+            echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
+            echo "__openstack_username__" > /opt/config/openstack_username.txt
+            echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt
+            echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt
+            echo "__openstack_region__" > /opt/config/openstack_region.txt
+            echo "__keystone_url__" > /opt/config/keystone.txt
+            echo "__docker_version__" > /opt/config/docker_version.txt
+            echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__clamp_repo__" > /opt/config/remote_repo.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh
+            cd /opt
+            chmod +x clamp_install.sh
+            ./clamp_install.sh
+
+
+  # OPEN-O VM instantiation
+  openo_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}]
+
+  openo_vm:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: ubuntu_1604_image }
+      flavor: { get_param: flavor_xxlarge }
+      name:
+        str_replace:
+          template: base-openo-server
+          params:
+            base: { get_param: vm_base_name }
+      key_name: { get_resource: vm_key }
+      networks:
+        - network: { get_param: public_net_id }
+        - port: { get_resource: openo_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __artifacts_version__: { get_param: artifacts_version }
+            __dns_ip_addr__: { get_param: dns_ip_addr }
+            __oam_network_cidr__: { get_param: oam_network_cidr }
+            __aai1_ip_addr__: { get_param: aai1_ip_addr }
+            __aai2_ip_addr__: { get_param: aai2_ip_addr }
+            __appc_ip_addr__: { get_param: appc_ip_addr }
+            __dcae_ip_addr__: { get_param: dcae_ip_addr }
+            __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr }
+            __so_ip_addr__: { get_param: so_ip_addr }
+            __mr_ip_addr__: { get_param: mr_ip_addr }
+            __policy_ip_addr__: { get_param: policy_ip_addr }
+            __portal_ip_addr__: { get_param: portal_ip_addr }
+            __robot_ip_addr__: { get_param: robot_ip_addr }
+            __sdc_ip_addr__: { get_param: sdc_ip_addr }
+            __sdnc_ip_addr__: { get_param: sdnc_ip_addr }
+            __vid_ip_addr__: { get_param: vid_ip_addr }
+            __clamp_ip_addr__: { get_param: clamp_ip_addr }
+            __openo_ip_addr__: { get_param: openo_ip_addr }
+            __cloud_env__: { get_param: cloud_env }
+            __external_dns__: { get_param: external_dns }
+            __vnfsdk_branch__: { get_param: vnfsdk_branch }
+            __msb_docker__: { get_param: msb_docker }
+            __mvim_docker__: { get_param: mvim_docker }
+            __vfc_docker__: { get_param: vfc_docker }
+            __uui_docker__: { get_param: uui_docker }
+            __vnfsdk_repo__: { get_param: vnfsdk_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt
+            echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt
+            echo "__external_dns__" > /opt/config/external_dns.txt
+            echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt
+            echo "__msb_docker__" > /opt/config/msb_docker.txt
+            echo "__mvim_docker__" > /opt/config/mvim_docker.txt
+            echo "__vfc_docker__" > /opt/config/vfc_docker.txt
+            echo "__uui_docker__" > /opt/config/uui_docker.txt
+            echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt
+
+            # Create env file with the IP address of all ONAP components
+            echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt
+            echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh
+            cd /opt
+            chmod +x openo_install.sh
+            ./openo_install.sh
index 422dce3..d92b3c7 100644 (file)
@@ -32,10 +32,6 @@ parameters:
 
   artifacts_version: 1.1.0-SNAPSHOT
 
-  docker_version: 1.1-STAGING-latest
-
-  gerrit_branch: master
-
   cloud_env: rackspace
 
 
@@ -59,10 +55,51 @@ parameters:
 
 
   # IP Address of DCAE VMs
-
   dcae_ip_addr: 10.0.4.1
   dcae_coll_ip_addr: 10.0.4.102
   dcae_db_ip_addr: 10.0.4.101
   dcae_hdp1_ip_addr: 10.0.4.103
   dcae_hdp2_ip_addr: 10.0.4.104
-  dcae_hdp3_ip_addr: 10.0.4.105
\ No newline at end of file
+  dcae_hdp3_ip_addr: 10.0.4.105
+
+  # ONAP repositories, docker versions, and Gerrit branches
+
+  aai_repo: http://gerrit.onap.org/r/aai/test-config
+  appc_repo: http://gerrit.onap.org/r/appc/deployment.git
+  dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git
+  mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git
+  so_repo: http://gerrit.onap.org/r/so/docker-config.git
+  policy_repo: http://gerrit.onap.org/r/policy/docker.git
+  portal_repo: http://gerrit.onap.org/r/portal.git
+  robot_repo: http://gerrit.onap.org/r/testsuite/properties.git
+  sdc_repo: http://gerrit.onap.org/r/sdc.git
+  sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git
+  vid_repo: http://gerrit.onap.org/r/vid.git
+  clamp_repo: http://gerrit.onap.org/r/clamp.git
+
+  aai_branch: master
+  appc_branch: master
+  so_branch: master
+  mr_branch: master
+  dcae_branch: master
+  policy_branch: master
+  portal_branch: master
+  robot_branch: master
+  sdc_branch: master
+  sdnc_branch: master
+  vid_branch: master
+  clamp_branch: master
+
+  aai_docker: 1.1-STAGING-latest
+  appc_docker: 1.1-STAGING-latest
+  so_docker: 1.1-STAGING-latest
+  mr_docker: 1.1-STAGING-latest
+  dcae_docker: 1.1-STAGING-latest
+  policy_docker: 1.1-STAGING-latest
+  portal_docker: 1.1-STAGING-latest
+  robot_docker: 1.1-STAGING-latest
+  sdc_docker: 1.1-STAGING-latest
+  sdnc_docker: 1.2-STAGING-latest
+  vid_docker: 1.1-STAGING-latest
+  clamp_docker: 1.1-STAGING-latest
+  dgbuilder_docker: 0.1-STAGING-latest
index f62043a..27652a4 100644 (file)
@@ -89,14 +89,6 @@ parameters:
     type: string
     description: Artifacts version of ONAP components
 
-  docker_version:
-    type: string
-    description: Docker version of ONAP docker images
-
-  gerrit_branch:
-    type: string
-    description: Gerrit branch where to download the code from
-
   cloud_env:
     type: string
     description: Cloud Provider Name
@@ -105,7 +97,7 @@ parameters:
   # Parameters for DCAE instantiation
   dcae_base_environment:
     type: string
-    description: DCAE Base Environment configuration (RACKSPACE/2-NIC/...)
+    description: DCAE Base Environment configuration (for this template, only RACKSPACE is supported)
 
   dcae_zone:
     type: string
@@ -159,6 +151,84 @@ parameters:
     type: string
     description: Hadoop VM3 IP Address
 
+  # ONAP repositories, docker versions, and Gerrit branches
+  aai_repo:
+    type: string
+  appc_repo:
+    type: string
+  dcae_repo:
+    type: string
+  mr_repo:
+    type: string
+  so_repo:
+    type: string
+  policy_repo:
+    type: string
+  portal_repo:
+    type: string
+  robot_repo:
+    type: string
+  sdc_repo:
+    type: string
+  sdnc_repo:
+    type: string
+  vid_repo:
+    type: string
+  clamp_repo:
+    type: string
+
+  aai_docker:
+    type: string
+  appc_docker:
+    type: string
+  so_docker:
+    type: string
+  mr_docker:
+    type: string
+  dcae_docker:
+    type: string
+  policy_docker:
+    type: string
+  portal_docker:
+    type: string
+  robot_docker:
+    type: string
+  sdc_docker:
+    type: string
+  sdnc_docker:
+    type: string
+  vid_docker:
+    type: string
+  clamp_docker:
+    type: string
+  dgbuilder_docker:
+    type: string
+
+  aai_branch:
+    type: string
+  appc_branch:
+    type: string
+  so_branch:
+    type: string
+  mr_branch:
+    type: string
+  dcae_branch:
+    type: string
+  policy_branch:
+    type: string
+  portal_branch:
+    type: string
+  robot_branch:
+    type: string
+  sdc_branch:
+    type: string
+  sdnc_branch:
+    type: string
+  vid_branch:
+    type: string
+  clamp_branch:
+    type: string
+
 
 resources:
   random-str:
@@ -181,24 +251,24 @@ resources:
 
 
   # ONAP management private network
-  oam_ecomp:
+  oam_onap:
     type: OS::Neutron::Net
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
 
-  oam_ecomp_subnet:
+  oam_onap_subnet:
     type: OS::Neutron::Subnet
     properties:
       name:
         str_replace:
-          template: oam_ecomp_rand
+          template: oam_onap_rand
           params:
             rand: { get_resource: random-str }
-      network_id: { get_resource: oam_ecomp }
+      network_id: { get_resource: oam_onap }
       cidr: 10.0.0.0/16
 
 
@@ -206,8 +276,8 @@ resources:
   dns_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.0.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.0.1}]
 
   dns_vm:
     type: OS::Nova::Server
@@ -250,8 +320,8 @@ resources:
   aai1_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.1.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.1.1}]
 
   aai1_volume:
     type: OS::Cinder::Volume
@@ -288,9 +358,10 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -307,19 +378,20 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "aai_instance_1" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
   aai2_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.1.2}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.1.2}]
 
   aai2_volume:
     type: OS::Cinder::Volume
@@ -355,9 +427,10 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: aai_docker }
+            __gerrit_branch__: { get_param: aai_branch }
             __cloud_env__: { get_param: cloud_env }
+            __aai_repo__: { get_param: aai_repo }
           template: |
             #!/bin/bash
 
@@ -374,35 +447,36 @@ resources:
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "aai_instance_2" > /opt/config/aai_instance.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__aai_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh
             cd /opt
-            chmod +x aai2_install.sh
-            ./aai2_install.sh
+            chmod +x aai_install.sh
+            ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.5.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.5.1}]
 
-  mso_vm:
+  so_vm:
     type: OS::Nova::Server
     properties:
       image: Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)
       flavor: 4 GB General Purpose v1
       name:
         str_replace:
-          template: base-mso
+          template: base-so
           params:
             base: { get_param: vm_base_name }
       key_name: { get_resource: vm_key }
       networks:
         - network: { get_param: public_net_id }
-        - port: { get_resource: mso_private_port }
+        - port: { get_resource: so_private_port }
       user_data_format: RAW
       user_data:
         str_replace:
@@ -416,9 +490,10 @@ resources:
             __openstack_api_key__: { get_param: openstack_api_key }
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: so_docker }
+            __gerrit_branch__: { get_param: so_branch }
             __cloud_env__: { get_param: cloud_env }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -437,20 +512,21 @@ resources:
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__so_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh
             cd /opt
-            chmod +x mso_install.sh
-            ./mso_install.sh
+            chmod +x so_install.sh
+            ./so_install.sh
 
 
   # Message Router instantiation
   mrouter_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.11.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.11.1}]
 
   mrouter_vm:
     type: OS::Nova::Server
@@ -475,8 +551,9 @@ resources:
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __gerrit_branch__: { get_param: mr_branch }
             __cloud_env__: { get_param: cloud_env }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -490,6 +567,7 @@ resources:
             echo "10.0.0.1" > /opt/config/dns_ip_addr.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__mr_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh
@@ -502,8 +580,8 @@ resources:
   robot_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.10.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.10.1}]
 
   robot_vm:
     type: OS::Nova::Server
@@ -527,15 +605,17 @@ resources:
             __nexus_docker_repo__: { get_param: nexus_docker_repo }
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
-            __network_name__: { get_attr: [oam_ecomp, name] }
+            __network_name__: { get_attr: [oam_onap, name] }
             __openstack_username__: { get_param: openstack_username }
             __openstack_api_key__: { get_param : openstack_api_key }
             __openstack_password__: { get_param: openstack_password }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
             __artifacts_version__: { get_param: artifacts_version }
             __openstack_region__: { get_param: openstack_region }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: robot_docker }
+            __gerrit_branch__: { get_param: robot_branch }
             __cloud_env__: { get_param: cloud_env }
+            __robot_repo__: { get_param: robot_repo }
           template: |
             #!/bin/bash
 
@@ -549,6 +629,7 @@ resources:
             echo "__openstack_username__" > /opt/config/openstack_username.txt
             echo "__openstack_password__" > /opt/config/openstack_password.txt
             echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt
+            echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt
             echo "__openstack_region__" > /opt/config/region.txt
             echo "__artifacts_version__" > /opt/config/artifacts_version.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
@@ -559,16 +640,18 @@ resources:
             echo "10.0.1.2" > /opt/config/aai2_ip_addr.txt
             echo "10.0.2.1" > /opt/config/appc_ip_addr.txt
             echo "10.0.4.1" > /opt/config/dcae_ip_addr.txt
-            echo "10.0.5.1" > /opt/config/mso_ip_addr.txt
+            echo "10.0.5.1" > /opt/config/so_ip_addr.txt
             echo "10.0.11.1" > /opt/config/mr_ip_addr.txt
             echo "10.0.6.1" > /opt/config/policy_ip_addr.txt
             echo "10.0.9.1" > /opt/config/portal_ip_addr.txt
             echo "10.0.3.1" > /opt/config/sdc_ip_addr.txt
             echo "10.0.7.1" > /opt/config/sdnc_ip_addr.txt
             echo "10.0.8.1" > /opt/config/vid_ip_addr.txt
+            echo "10.0.12.1" > /opt/config/clamp_ip_addr.txt
             echo "Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)" > /opt/config/vm_image_name.txt
             echo "4 GB General Purpose v1" > /opt/config/vm_flavor.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__robot_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh
@@ -581,8 +664,8 @@ resources:
   vid_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.8.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.8.1}]
 
   vid_vm:
     type: OS::Nova::Server
@@ -607,9 +690,10 @@ resources:
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: vid_docker }
+            __gerrit_branch__: { get_param: vid_branch }
             __cloud_env__: { get_param: cloud_env }
+            __vid_repo__: { get_param: vid_repo }
           template: |
             #!/bin/bash
 
@@ -624,6 +708,7 @@ resources:
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__vid_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh
@@ -636,8 +721,8 @@ resources:
   sdnc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.7.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.7.1}]
 
   sdnc_vm:
     type: OS::Nova::Server
@@ -662,9 +747,11 @@ resources:
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdnc_docker }
+            __gerrit_branch__: { get_param: sdnc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
+            __sdnc_repo__: { get_param: sdnc_repo }
           template: |
             #!/bin/bash
 
@@ -678,7 +765,9 @@ resources:
             echo "10.0.0.1" > /opt/config/dns_ip_addr.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__sdnc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh
@@ -691,8 +780,8 @@ resources:
   sdc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.3.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.3.1}]
 
   sdc_volume_local:
     type: OS::Cinder::Volume
@@ -742,9 +831,10 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __env_name__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: sdc_docker }
+            __gerrit_branch__: { get_param: sdc_branch }
             __cloud_env__: { get_param: cloud_env }
+            __sdc_repo__: { get_param: sdc_repo }
           template: |
             #!/bin/bash
 
@@ -761,20 +851,21 @@ resources:
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__sdc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
-            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh
             cd /opt
-            chmod +x asdc_install.sh
-            ./asdc_install.sh
+            chmod +x sdc_install.sh
+            ./sdc_install.sh
 
 
   # PORTAL instantiation
   portal_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.9.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.9.1}]
 
   portal_volume:
     type: OS::Cinder::Volume
@@ -809,9 +900,10 @@ resources:
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: portal_docker }
+            __gerrit_branch__: { get_param: portal_branch }
             __cloud_env__: { get_param: cloud_env }
+            __portal_repo__: { get_param: portal_repo }
           template: |
             #!/bin/bash
 
@@ -826,6 +918,7 @@ resources:
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__portal_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh
@@ -838,8 +931,8 @@ resources:
   dcae_c_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.4.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.4.1}]
   dcae_c_vm:
     type: OS::Nova::Server
     properties:
@@ -868,7 +961,7 @@ resources:
             __dcae_state__: { get_param: dcae_state }
             __artifacts_version__: { get_param: artifacts_version }
             __tenant_id__: { get_param: openstack_tenant_id }
-            __openstack_private_network_name__: { get_attr: [oam_ecomp, name] }
+            __openstack_private_network_name__: { get_attr: [oam_onap, name] }
             __openstack_user__: { get_param: openstack_username }
             __openstack_password__: { get_param: openstack_api_key }
             __openstack_auth_method__: { get_param: openstack_auth_method }
@@ -877,8 +970,8 @@ resources:
             __pub_key__: { get_param: pub_key }
             __nexus_repo_root__: { get_param: nexus_repo_root }
             __openstack_region__: { get_param: openstack_region }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: dcae_docker }
+            __gerrit_branch__: { get_param: dcae_branch }
             __cloud_env__: { get_param: cloud_env }
             __dcae_code_version__: { get_param: dcae_code_version }
             __public_net_id__: { get_param: public_net_id }
@@ -889,6 +982,8 @@ resources:
             __dcae_hdp1_ip_addr__: { get_param: dcae_hdp1_ip_addr }
             __dcae_hdp2_ip_addr__: { get_param: dcae_hdp2_ip_addr }
             __dcae_hdp3_ip_addr__: { get_param: dcae_hdp3_ip_addr }
+            __dcae_repo__: { get_param: dcae_repo }
+            __mr_repo__: { get_param: mr_repo }
           template: |
             #!/bin/bash
 
@@ -928,6 +1023,8 @@ resources:
             echo "__dcae_hdp1_ip_addr__" > /opt/config/dcae_hdp1_ip_addr.txt
             echo "__dcae_hdp2_ip_addr__" > /opt/config/dcae_hdp2_ip_addr.txt
             echo "__dcae_hdp3_ip_addr__" > /opt/config/dcae_hdp3_ip_addr.txt
+            echo "__dcae_repo__" > /opt/config/remote_repo.txt
+            echo "__mr_repo__" > /opt/config/mr_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh
@@ -940,8 +1037,8 @@ resources:
   policy_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.6.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.6.1}]
 
   policy_volume:
     type: OS::Cinder::Volume
@@ -976,9 +1073,10 @@ resources:
             __nexus_username__: { get_param: nexus_username }
             __nexus_password__: { get_param: nexus_password }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: policy_docker }
+            __gerrit_branch__: { get_param: policy_branch }
             __cloud_env__: { get_param: cloud_env }
+            __policy_repo__: { get_param: policy_repo }
           template: |
             #!/bin/bash
 
@@ -993,6 +1091,7 @@ resources:
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__policy_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh
@@ -1005,8 +1104,8 @@ resources:
   appc_private_port:
     type: OS::Neutron::Port
     properties:
-      network: { get_resource: oam_ecomp }
-      fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.2.1}]
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.2.1}]
 
   appc_vm:
     type: OS::Nova::Server
@@ -1032,9 +1131,11 @@ resources:
             __nexus_password__: { get_param: nexus_password }
             __dmaap_topic__: { get_param: dmaap_topic }
             __artifacts_version__: { get_param: artifacts_version }
-            __docker_version__: { get_param: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __docker_version__: { get_param: appc_docker }
+            __gerrit_branch__: { get_param: appc_branch }
+            __dgbuilder_docker__: { get_param: dgbuilder_docker }
             __cloud_env__: { get_param: cloud_env }
+            __appc_repo__: { get_param: appc_repo }
           template: |
             #!/bin/bash
 
@@ -1049,10 +1150,77 @@ resources:
             echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
             echo "__docker_version__" > /opt/config/docker_version.txt
             echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__appc_repo__" > /opt/config/remote_repo.txt
 
             # Download and run install script
             curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh
             cd /opt
             chmod +x appc_install.sh
-            ./appc_install.sh
\ No newline at end of file
+            ./appc_install.sh
+
+
+  # CLAMP instantiation
+  clamp_private_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: oam_onap }
+      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.12.1}]
+
+  clamp_vm:
+    type: OS::Nova::Server
+    properties:
+      image: Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)
+      flavor: 4 GB General Purpose v1
+      name:
+        str_replace:
+          template: base-clamp
+          params:
+            base: { get_param: vm_base_name }
+      key_name: { get_resource: vm_key }
+      networks:
+        - network: { get_param: public_net_id }
+        - port: { get_resource: clamp_private_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __nexus_repo__: { get_param: nexus_repo }
+            __nexus_docker_repo__: { get_param: nexus_docker_repo }
+            __nexus_username__: { get_param: nexus_username }
+            __nexus_password__: { get_param: nexus_password }
+            __openstack_username__: { get_param: openstack_username }
+            __openstack_tenant_id__: { get_param: openstack_tenant_id }
+            __openstack_api_key__: { get_param: openstack_api_key }
+            __dmaap_topic__: { get_param: dmaap_topic }
+            __artifacts_version__: { get_param: artifacts_version }
+            __docker_version__: { get_param: clamp_docker }
+            __gerrit_branch__: { get_param: clamp_branch }
+            __cloud_env__: { get_param: cloud_env }
+            __clamp_repo__: { get_param: clamp_repo }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir -p /opt/config
+            echo "__nexus_repo__" > /opt/config/nexus_repo.txt
+            echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt
+            echo "__nexus_username__" > /opt/config/nexus_username.txt
+            echo "__nexus_password__" > /opt/config/nexus_password.txt
+            echo "__artifacts_version__" > /opt/config/artifacts_version.txt
+            echo "10.0.0.1" > /opt/config/dns_ip_addr.txt
+            echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt
+            echo "__openstack_username__" > /opt/config/openstack_username.txt
+            echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt
+            echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt
+            echo "__docker_version__" > /opt/config/docker_version.txt
+            echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__clamp_repo__" > /opt/config/remote_repo.txt
+
+            # Download and run install script
+            curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh
+            cd /opt
+            chmod +x clamp_install.sh
+            ./clamp_install.sh
index 4de6090..689d1cf 100644 (file)
@@ -17,8 +17,9 @@ parameters:
   vdns_private_ip_1: 10.0.101.3
   vweb_private_ip_0: 10.2.0.10
   vweb_private_ip_1: 10.0.101.40
+  mr_ip_addr: 10.0.11.1
   vaaa_name_0: zdcpe1cpe01aaa01
-  vdns_name_0: zdcpe11cpe01dns01
+  vdns_name_0: zdcpe1cpe01dns01
   vdhcp_name_0: zdcpe1cpe01dhcp01
   vweb_name_0: zdcpe1cpe01web01
   vnf_id: vCPE_Infrastructure_demo_app
index 6b9160b..c0a1875 100644 (file)
@@ -76,7 +76,7 @@ parameters:
   vaaa_private_ip_0:
     type: string
     label: vAAA private IP address towards the CPE_SIGNAL private network
-    description: Private IP address that is assigned to the vAAA to communicate with the vCPE components 
+    description: Private IP address that is assigned to the vAAA to communicate with the vCPE components
   vaaa_private_ip_1:
     type: string
     label: vAAA private IP address towards the ONAP management network
@@ -137,6 +137,10 @@ parameters:
     type: string
     label: DCAE collector port
     description: Port of the DCAE collector
+  mr_ip_addr:
+    type: string
+    label: Message Router IP address
+    description: IP address of the Message Router that for vDHCP configuration 
   key_name:
     type: string
     label: Key pair name
@@ -370,9 +374,10 @@ resources:
         str_replace:
           params:
             __oam_ipaddr__ : { get_param: vdhcp_private_ip_1 }
-            __cpe_signal_ipaddr__: { get_param: vdhcp_private_ip_0 }
-            __oam_cidr__: { get_param: onap_private_net_cidr }
-            __cpe_signal_net_cidr__: { get_param: cpe_signal_net_cidr }
+            __cpe_signal_ipaddr__ : { get_param: vdhcp_private_ip_0 }
+            __oam_cidr__ : { get_param: onap_private_net_cidr }
+            __cpe_signal_net_cidr__ : { get_param: cpe_signal_net_cidr }
+            __mr_ip_addr__ : { get_param: mr_ip_addr }
             __repo_url_blob__ : { get_param: repo_url_blob }
             __repo_url_artifacts__ : { get_param: repo_url_artifacts }
             __demo_artifacts_version__ : { get_param: demo_artifacts_version }
@@ -387,6 +392,7 @@ resources:
             echo "__cpe_signal_ipaddr__" > /opt/config/cpe_signal_ipaddr.txt
             echo "__oam_cidr__" > /opt/config/oam_cidr.txt
             echo "__cpe_signal_net_cidr__" > /opt/config/cpe_signal_net_cidr.txt
+            echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt
             echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
             echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
index e50d483..cc391c4 100644 (file)
@@ -13,7 +13,7 @@
   cpe_signal_private_net_cidr: 10.4.0.0/24
   vbng_private_ip_0: 10.3.0.1
   vbng_private_ip_1: 10.0.101.10
-  vbng_private_ip_2: 10.4.0.3\r
+  vbng_private_ip_2: 10.4.0.3
   vbng_private_ip_3: 10.1.0.10
   vbng_name_0: zdcpe1cpe01bng01
   vnf_id: vCPE_Infrastructure_Metro_vBNG_demo_app
@@ -27,3 +27,6 @@
   key_name: vbng_key
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
   cloud_env: rackspace
+  vpp_source_repo_url: https://gerrit.fd.io/r/vpp
+  vpp_source_repo_branch: stable/1704
+  vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch
index d5c0eed..8a49e17 100644 (file)
@@ -145,6 +145,18 @@ parameters:
     type: string
     label: Cloud environment
     description: Cloud environment (e.g., openstack, rackspace)
+  vpp_source_repo_url:
+    type: string
+    label: VPP Source Git Repo
+    description: URL for VPP source codes
+  vpp_source_repo_branch:
+    type: string
+    label: VPP Source Git Branch
+    description: Git Branch for the VPP source codes
+  vpp_patch_url:
+    type: string
+    label: VPP Patch URL
+    description: URL for VPP patch for vBNG
 
 #############
 #           #
@@ -240,6 +252,9 @@ resources:
             __demo_artifacts_version__ : { get_param: demo_artifacts_version }
             __install_script_version__ : { get_param: install_script_version }
             __cloud_env__ : { get_param: cloud_env }
+            __vpp_source_repo_url__ : { get_param: vpp_source_repo_url }
+            __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch }
+            __vpp_patch_url__ : { get_param: vpp_patch_url }
           template: |
             #!/bin/bash
 
@@ -260,6 +275,9 @@ resources:
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
             echo "__install_script_version__" > /opt/config/install_script_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt
+            echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt
+            echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt
 
             # Download and run install script
             curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_bng_install.sh -o /opt/v_bng_install.sh
index 0d4d894..719e7c9 100644 (file)
@@ -7,8 +7,9 @@
   vbrgemu_bng_private_net_cidr: 10.3.0.0/24
   vbrgemu_private_net_cidr: 192.168.1.0/24
   vbrgemu_private_ip_0: 10.3.0.2
-  vbrgemu_private_ip_1: 192.168.1.1\r
-  vbrgemu_name_0: zdcpe11cpe01brgemu01
+  vbrgemu_private_ip_1: 192.168.1.1
+  sdnc_ip: 10.0.7.1
+  vbrgemu_name_0: zdcpe1cpe01brgemu01
   vnf_id: vCPE_Infrastructure_BGREMU_demo_app
   vf_module_id: vCPE_Customer_BRGEMU
   repo_url_blob: https://nexus.onap.org/content/sites/raw
@@ -18,3 +19,8 @@
   key_name: vbrgemu_key
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
   cloud_env: rackspace
+  vpp_source_repo_url: https://gerrit.fd.io/r/vpp
+  vpp_source_repo_branch: stable/1704
+  hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp
+  hc2vpp_source_repo_branch: stable/1704
+  vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch
index 6f926eb..a6f42ba 100644 (file)
@@ -111,6 +111,26 @@ parameters:
     type: string
     label: Cloud environment
     description: Cloud environment (e.g., openstack, rackspace)
+  vpp_source_repo_url:
+    type: string
+    label: VPP Source Git Repo
+    description: URL for VPP source codes
+  vpp_source_repo_branch:
+    type: string
+    label: VPP Source Git Branch
+    description: Git Branch for the VPP source codes
+  hc2vpp_source_repo_url:
+    type: string
+    label: Honeycomb Source Git Repo
+    description: URL for Honeycomb source codes
+  hc2vpp_source_repo_branch:
+    type: string
+    label: Honeycomb Source Git Branch
+    description: Git Branch for the Honeycomb source codes
+  vpp_patch_url:
+    type: string
+    label: VPP Patch URL
+    description: URL for VPP patch for vBRG Emulator
 
 #############
 #           #
@@ -187,6 +207,11 @@ resources:
             __demo_artifacts_version__ : { get_param: demo_artifacts_version }
             __install_script_version__ : { get_param: install_script_version }
             __cloud_env__ : { get_param: cloud_env }
+            __vpp_source_repo_url__ : { get_param: vpp_source_repo_url }
+            __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch }
+            __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url }
+            __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch }
+            __vpp_patch_url__ : { get_param: vpp_patch_url }
           template: |
             #!/bin/bash
 
@@ -200,6 +225,12 @@ resources:
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
             echo "__install_script_version__" > /opt/config/install_script_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt
+            echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt
+            echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt
+            echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt
+            echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt
+           echo "__sdnc_ip__" > /opt/config/ip.txt
 
             # Download and run install script
             curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_brgemu_install.sh -o /opt/v_brgemu_install.sh
index 76dd86e..de15d1b 100644 (file)
@@ -12,7 +12,7 @@
   vgmux_private_ip_0: 10.1.0.20
   vgmux_private_ip_1: 10.0.101.20
   vgmux_private_ip_2: 10.5.0.20
-  vgmux_name_0: zdcpe11cpe01mux01
+  vgmux_name_0: zdcpe1cpe01mux01
   vnf_id: vCPE_Infrastructure_vGMUX_demo_app
   vf_module_id: vCPE_Intrastructure_Metro_vGMUX
   dcae_collector_ip: 10.0.4.102
@@ -24,3 +24,9 @@
   key_name: vbng_key
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
   cloud_env: rackspace
+  vpp_source_repo_url: https://gerrit.fd.io/r/vpp
+  vpp_source_repo_branch: stable/1704
+  hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp
+  hc2vpp_source_repo_branch: stable/1704
+  vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch
+  h2vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch
index b6e212a..6cbaef1 100644 (file)
@@ -133,6 +133,30 @@ parameters:
     type: string
     label: Cloud environment
     description: Cloud environment (e.g., openstack, rackspace)
+  vpp_source_repo_url:
+    type: string
+    label: VPP Source Git Repo
+    description: URL for VPP source codes
+  vpp_source_repo_branch:
+    type: string
+    label: VPP Source Git Branch
+    description: Git Branch for the VPP source codes
+  hc2vpp_source_repo_url:
+    type: string
+    label: Honeycomb Source Git Repo
+    description: URL for Honeycomb source codes
+  hc2vpp_source_repo_branch:
+    type: string
+    label: Honeycomb Source Git Branch
+    description: Git Branch for the Honeycomb source codes
+  vpp_patch_url:
+    type: string
+    label: VPP Patch URL
+    description: URL for VPP patch for vG-MUX
+  hc2vpp_patch_url:
+    type: string
+    label: Honeycomb Patch URL
+    description: URL for Honeycomb patch for vG-MUX
 
 #############
 #           #
@@ -230,6 +254,12 @@ resources:
             __demo_artifacts_version__ : { get_param: demo_artifacts_version }
             __install_script_version__ : { get_param: install_script_version }
             __cloud_env__ : { get_param: cloud_env }
+            __vpp_source_repo_url__ : { get_param: vpp_source_repo_url }
+            __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch }
+            __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url }
+            __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch }
+            __vpp_patch_url__ : { get_param: vpp_patch_url }
+            __hc2vpp_patch_url__ : { get_param: hc2vpp_patch_url }
           template: |
             #!/bin/bash
 
@@ -246,6 +276,12 @@ resources:
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
             echo "__install_script_version__" > /opt/config/install_script_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt
+            echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt
+            echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt
+            echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt
+            echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt
+            echo "__hc2vpp_patch_url__" > /opt/config/hc2vpp_patch_url.txt
 
             # Download and run install script
             curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_gmux_install.sh -o /opt/v_gmux_install.sh
index 33da8d7..c2a1b64 100644 (file)
@@ -12,7 +12,7 @@
   vgw_private_ip_0: 10.5.0.21
   vgw_private_ip_1: 10.0.101.30
   vgw_private_ip_2: 10.2.0.2
-  vgw_name_0: zdcpe11cpe01gw01
+  vgw_name_0: zdcpe1cpe01gw01
   vnf_id: vCPE_Infrastructure_GW_demo_app
   vf_module_id: vCPE_Customer_GW
   dcae_collector_ip: 10.0.4.102
@@ -24,3 +24,7 @@
   key_name: vgw_key
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
   cloud_env: rackspace
+  vpp_source_repo_url: https://gerrit.fd.io/r/vpp
+  vpp_source_repo_branch: stable/1704
+  hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp
+  hc2vpp_source_repo_branch: stable/1704
index 0621556..d8fe4cd 100644 (file)
@@ -133,6 +133,22 @@ parameters:
     type: string
     label: Cloud environment
     description: Cloud environment (e.g., openstack, rackspace)
+  vpp_source_repo_url:
+    type: string
+    label: VPP Source Git Repo
+    description: URL for VPP source codes
+  vpp_source_repo_branch:
+    type: string
+    label: VPP Source Git Branch
+    description: Git Branch for the VPP source codes
+  hc2vpp_source_repo_url:
+    type: string
+    label: Honeycomb Source Git Repo
+    description: URL for Honeycomb source codes
+  hc2vpp_source_repo_branch:
+    type: string
+    label: Honeycomb Source Git Branch
+    description: Git Branch for the Honeycomb source codes
 
 #############
 #           #
@@ -207,6 +223,10 @@ resources:
             __demo_artifacts_version__ : { get_param: demo_artifacts_version }
             __install_script_version__ : { get_param: install_script_version }
             __cloud_env__ : { get_param: cloud_env }
+            __vpp_source_repo_url__ : { get_param: vpp_source_repo_url }
+            __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch }
+            __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url }
+            __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch }
           template: |
             #!/bin/bash
 
@@ -222,6 +242,10 @@ resources:
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
             echo "__install_script_version__" > /opt/config/install_script_version.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
+            echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt
+            echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt
+            echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt
+            echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt
 
             # Download and run install script
             curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_gw_install.sh -o /opt/v_gw_install.sh
diff --git a/heat/vFW/.DS_Store b/heat/vFW/.DS_Store
deleted file mode 100644 (file)
index e2759ef..0000000
Binary files a/heat/vFW/.DS_Store and /dev/null differ
similarity index 95%
rename from heat/vFW/base_vfw_openstack.env
rename to heat/vFW/base_vfw.env
index 7040f86..9790d0e 100644 (file)
@@ -29,4 +29,4 @@ parameters:
   install_script_version: 1.1.0-SNAPSHOT\r
   key_name: vfw_key\r
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN\r
-  cloud_env: openstack\r
+  cloud_env: PUT openstack OR rackspace HERE\r
similarity index 96%
rename from heat/vFW/base_vfw_openstack.yaml
rename to heat/vFW/base_vfw.yaml
index 4900c55..77b53a8 100644 (file)
@@ -208,16 +208,13 @@ resources:
   vfw_private_0_port:\r
     type: OS::Neutron::Port\r
     properties:\r
-      security_groups: []\r
-      port_security_enabled: False\r
       network: { get_resource: unprotected_private_network }\r
       fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vfw_private_ip_0 }}]\r
 \r
   vfw_private_1_port:\r
     type: OS::Neutron::Port\r
     properties:\r
-      security_groups: []\r
-      port_security_enabled: False\r
+      allowed_address_pairs: [{ "ip_address": { get_param: vpg_private_ip_0 }}]\r
       network: { get_resource: protected_private_network }\r
       fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vfw_private_ip_1 }}]\r
 \r
diff --git a/heat/vFW/base_vfw_rackspace.env b/heat/vFW/base_vfw_rackspace.env
deleted file mode 100644 (file)
index 0f6175d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-parameters:
-  vfw_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
-  vfw_flavor_name: 4 GB General Purpose v1
-  public_net_id: 00000000-0000-0000-0000-000000000000
-  unprotected_private_net_id: zdfw1fwl01_unprotected
-  protected_private_net_id: zdfw1fwl01_protected
-  onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  unprotected_private_net_cidr: 192.168.10.0/24
-  protected_private_net_cidr: 192.168.20.0/24
-  onap_private_net_cidr: 10.0.0.0/16
-  vfw_private_ip_0: 192.168.10.100
-  vfw_private_ip_1: 192.168.20.100
-  vfw_private_ip_2: 10.0.100.1
-  vpg_private_ip_0: 192.168.10.200
-  vpg_private_ip_1: 10.0.100.2
-  vsn_private_ip_0: 192.168.20.250
-  vsn_private_ip_1: 10.0.100.3
-  vfw_name_0: zdfw1fwl01fwl01
-  vpg_name_0: zdfw1fwl01pgn01
-  vsn_name_0: zdfw1fwl01snk01
-  vnf_id: vFirewall_demo_app
-  vf_module_id: vFirewall
-  dcae_collector_ip: 10.0.4.102
-  dcae_collector_port: 8080
-  repo_url_blob: https://nexus.onap.org/content/sites/raw
-  repo_url_artifacts: https://nexus.onap.org/content/groups/staging
-  demo_artifacts_version: 1.1.0
-  install_script_version: 1.1.0-SNAPSHOT
-  key_name: vfw_key
-  pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: rackspace
diff --git a/heat/vFW/base_vfw_rackspace.yaml b/heat/vFW/base_vfw_rackspace.yaml
deleted file mode 100644 (file)
index 51ac286..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-##########################################################################
-#
-#==================LICENSE_START==========================================
-# 
-#
-# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#==================LICENSE_END============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-##########################################################################
-
-heat_template_version: 2013-05-23
-
-description: Heat template that deploys vFirewall demo app for ONAP
-
-##############
-#            #
-# PARAMETERS #
-#            #
-##############
-
-parameters:
-  vfw_image_name:
-    type: string
-    label: Image name or ID
-    description: Image to be used for compute instance
-  vfw_flavor_name:
-    type: string
-    label: Flavor
-    description: Type of instance (flavor) to be used
-  public_net_id:
-    type: string
-    label: Public network name or ID
-    description: Public network that enables remote connection to VNF
-  unprotected_private_net_id:
-    type: string
-    label: Unprotected private network name or ID
-    description: Private network that connects vPacketGenerator with vFirewall
-  protected_private_net_id:
-    type: string
-    label: Protected private network name or ID
-    description: Private network that connects vFirewall with vSink
-  onap_private_net_id:
-    type: string
-    label: ONAP management network name or ID
-    description: Private network that connects ONAP components and the VNF
-  onap_private_subnet_id:
-    type: string
-    label: ONAP management sub-network name or ID
-    description: Private sub-network that connects ONAP components and the VNF
-  unprotected_private_net_cidr:
-    type: string
-    label: Unprotected private network CIDR
-    description: The CIDR of the unprotected private network
-  protected_private_net_cidr:
-    type: string
-    label: Protected private network CIDR
-    description: The CIDR of the protected private network
-  onap_private_net_cidr:
-    type: string
-    label: ONAP private network CIDR
-    description: The CIDR of the protected private network
-  vfw_private_ip_0:
-    type: string
-    label: vFirewall private IP address towards the unprotected network
-    description: Private IP address that is assigned to the vFirewall to communicate with the vPacketGenerator
-  vfw_private_ip_1:
-    type: string
-    label: vFirewall private IP address towards the protected network
-    description: Private IP address that is assigned to the vFirewall to communicate with the vSink
-  vfw_private_ip_2:
-    type: string
-    label: vFirewall private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vFirewall to communicate with ONAP components
-  vpg_private_ip_0:
-    type: string
-    label: vPacketGenerator private IP address towards the unprotected network
-    description: Private IP address that is assigned to the vPacketGenerator to communicate with the vFirewall
-  vpg_private_ip_1:
-    type: string
-    label: vPacketGenerator private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vPacketGenerator to communicate with ONAP components
-  vsn_private_ip_0:
-    type: string
-    label: vSink private IP address towards the protected network
-    description: Private IP address that is assigned to the vSink to communicate with the vFirewall
-  vsn_private_ip_1:
-    type: string
-    label: vSink private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vSink to communicate with ONAP components
-  vfw_name_0:
-    type: string
-    label: vFirewall name
-    description: Name of the vFirewall
-  vpg_name_0:
-    type: string
-    label: vPacketGenerator name
-    description: Name of the vPacketGenerator
-  vsn_name_0:
-    type: string
-    label: vSink name
-    description: Name of the vSink
-  vnf_id:
-    type: string
-    label: VNF ID
-    description: The VNF ID is provided by ECOMP
-  vf_module_id:
-    type: string
-    label: vFirewall module ID
-    description: The vFirewall Module ID is provided by ECOMP
-  dcae_collector_ip:
-    type: string
-    label: DCAE collector IP address
-    description: IP address of the DCAE collector
-  dcae_collector_port:
-    type: string
-    label: DCAE collector port
-    description: Port of the DCAE collector
-  key_name:
-    type: string
-    label: Key pair name
-    description: Public/Private key pair name
-  pub_key:
-    type: string
-    label: Public key
-    description: Public key to be installed on the compute instance
-  repo_url_blob:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  repo_url_artifacts:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  install_script_version:
-    type: string
-    label: Installation script version number
-    description: Version number of the scripts that install the vFW demo app
-  demo_artifacts_version:
-    type: string
-    label: Artifacts version used in demo vnfs
-    description: Artifacts (jar, tar.gz) version used in demo vnfs
-  cloud_env:
-    type: string
-    label: Cloud environment
-    description: Cloud environment (e.g., openstack, rackspace)
-
-#############
-#           #
-# RESOURCES #
-#           #
-#############
-
-resources:
-  random-str:
-    type: OS::Heat::RandomString
-    properties:
-      length: 4
-
-  my_keypair:
-    type: OS::Nova::KeyPair
-    properties:
-      name:
-        str_replace:
-          template: base_rand
-          params:
-            base: { get_param: key_name }
-            rand: { get_resource: random-str }
-      public_key: { get_param: pub_key }
-      save_private_key: false
-
-  unprotected_private_network:
-    type: OS::Neutron::Net
-    properties:
-      name: { get_param: unprotected_private_net_id }
-
-  protected_private_network:
-    type: OS::Neutron::Net
-    properties:
-      name: { get_param: protected_private_net_id }
-
-  unprotected_private_subnet:
-    type: OS::Neutron::Subnet
-    properties:
-      network_id: { get_resource: unprotected_private_network }
-      cidr: { get_param: unprotected_private_net_cidr }
-
-  protected_private_subnet:
-    type: OS::Neutron::Subnet
-    properties:
-      network_id: { get_resource: protected_private_network }
-      cidr: { get_param: protected_private_net_cidr }
-
-  # Virtual Firewall instantiation
-  vfw_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: unprotected_private_network }
-      fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vfw_private_ip_0 }}]
-
-  vfw_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: protected_private_network }
-      fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vfw_private_ip_1 }}]
-
-  vfw_private_2_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vfw_private_ip_2 }}]
-
-  vfw_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vfw_image_name }
-      flavor: { get_param: vfw_flavor_name }
-      name: { get_param: vfw_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vfw_private_0_port }
-        - port: { get_resource: vfw_private_1_port }
-        - port: { get_resource: vfw_private_2_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __dcae_collector_ip__ : { get_param: dcae_collector_ip }
-            __dcae_collector_port__ : { get_param: dcae_collector_port }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt
-            echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-            
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_firewall_install.sh -o /opt/v_firewall_install.sh
-            cd /opt
-            chmod +x v_firewall_install.sh
-            ./v_firewall_install.sh
-
-
-  # Virtual Packet Generator instantiation
-  vpg_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: unprotected_private_network }
-      fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vpg_private_ip_0 }}]
-
-  vpg_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vpg_private_ip_1 }}]
-
-  vpg_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vfw_image_name }
-      flavor: { get_param: vfw_flavor_name }
-      name: { get_param: vpg_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vpg_private_0_port }
-        - port: { get_resource: vpg_private_1_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __fw_ipaddr__: { get_param: vfw_private_ip_0 }
-            __protected_net_cidr__: { get_param: protected_private_net_cidr }
-            __sink_ipaddr__: { get_param: vsn_private_ip_0 }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__fw_ipaddr__" > /opt/config/fw_ipaddr.txt
-            echo "__protected_net_cidr__" > /opt/config/protected_net_cidr.txt
-            echo "__sink_ipaddr__" > /opt/config/sink_ipaddr.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-            
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh
-            cd /opt
-            chmod +x v_packetgen_install.sh
-            ./v_packetgen_install.sh
-
-
-  # Virtual Sink instantiation
-  vsn_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: protected_private_network }
-      fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vsn_private_ip_0 }}]
-
-  vsn_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vsn_private_ip_1 }}]
-
-  vsn_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vfw_image_name }
-      flavor: { get_param: vfw_flavor_name }
-      name: { get_param: vsn_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vsn_private_0_port }
-        - port: { get_resource: vsn_private_1_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __protected_net_gw__: { get_param: vfw_private_ip_1 }
-            __unprotected_net__: { get_param: unprotected_private_net_cidr }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__protected_net_gw__" > /opt/config/protected_net_gw.txt
-            echo "__unprotected_net__" > /opt/config/unprotected_net.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-            
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_sink_install.sh -o /opt/v_sink_install.sh
-            cd /opt
-            chmod +x v_sink_install.sh
-            ./v_sink_install.sh
\ No newline at end of file
similarity index 78%
rename from heat/vLB/base_vlb_openstack.env
rename to heat/vLB/base_vlb.env
index afcfccf..50da384 100644 (file)
@@ -3,16 +3,25 @@ parameters:
   vlb_flavor_name: PUT THE FLAVOR NAME HERE
   public_net_id: PUT THE NETWORK ID HERE
   vlb_private_net_id: zdfw1lb01_private
+  pktgen_private_net_id: zdfw1pktgen01_private
   onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
   onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
   vlb_private_net_cidr: 192.168.10.0/24
+  pktgen_private_net_cidr: 192.168.9.0/24
   onap_private_net_cidr: PUT THE ONAP NETWORK CIDR HERE
   vlb_private_ip_0: 192.168.10.111
   vlb_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VLB
+  vlb_private_ip_2: 192.168.9.111
   vdns_private_ip_0: 192.168.10.211
   vdns_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VDNS
+  vpg_private_ip_0: 192.168.9.110
+  vpg_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VPKTGEN
+  vip: 192.168.9.112
+  gre_ipaddr: 192.168.10.112
+  pg_int: 192.168.9.109
   vlb_name_0: zdfw1lb01lb01
   vdns_name_0: zdfw1lb01dns01
+  vpg_name_0: zdfw1lb01pg01
   vnf_id: vLoadBalancer_demo_app
   vf_module_id: vLoadBalancer
   dcae_collector_ip: PUT THE ADDRESS OF THE DCAE COLLECTOR HERE
@@ -23,4 +32,4 @@ parameters:
   install_script_version: 1.1.0-SNAPSHOT
   key_name: vlb_key
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: openstack
+  cloud_env: PUT openstack OR backspace HERE
similarity index 65%
rename from heat/vLB/base_vlb_openstack.yaml
rename to heat/vLB/base_vlb.yaml
index 18a0d76..fa4fea0 100644 (file)
@@ -49,6 +49,10 @@ parameters:
     type: string
     label: vLoadBalancer private network name or ID
     description: Private network that connects vLoadBalancer with vDNSs
+  pktgen_private_net_id:
+    type: string
+    label: vPacketGen private network name or ID
+    description: Private network that connects vLoadBalancer with vPacketGen
   onap_private_net_id:
     type: string
     label: ECOMP management network name or ID
@@ -61,6 +65,10 @@ parameters:
     type: string
     label: vLoadBalancer private network CIDR
     description: The CIDR of the vLoadBalancer private network
+  pktgen_private_net_cidr:
+    type: string
+    label: vPacketGen private network CIDR
+    description: The CIDR of the vPacketGen private network
   onap_private_net_cidr:
     type: string
     label: ONAP private network CIDR
@@ -73,6 +81,10 @@ parameters:
     type: string
     label: vLoadBalancer private IP address towards the ONAP management network
     description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components
+  vlb_private_ip_2:
+    type: string
+    label: vLoadBalancer private IP address towards the vPacketGen network
+    description: Private IP address that is assigned to the vLoadBalancer to communicate with vPacketGen
   vdns_private_ip_0:
     type: string
     label: vDNS private IP address towards the private network
@@ -81,6 +93,26 @@ parameters:
     type: string
     label: vDNS private IP address towards the ONAP management network
     description: Private IP address that is assigned to the vDNS to communicate with ONAP components
+  vpg_private_ip_0:
+    type: string
+    label: vPacketGen private IP address towards the vPacketGen private network
+    description: Private IP address that is assigned to the vPacketGen to communicate with the vLoadBalancer
+  vpg_private_ip_1:
+    type: string
+    label: vPacketGen private IP address towards the ONAP management network
+    description: Private IP address that is assigned to the vPacketGen to communicate with ONAP components
+  vip:
+    type: string
+    label: Virtual Private IP of the vLoadBalancer
+    description: Virtual Private IP that is assigned to the vLoadBalancer's VPP layer
+  gre_ipaddr:
+    type: string
+    label: IP Address of the GRE tunnel
+    description: IP address assigned to the GRE tunnel on the vLoadBalancer
+  pg_int:
+    type: string
+    label: IP Address of the output vPacketGen interface
+    description: IP address assigned to the output interface of the vPacketGen's VPP layer
   vlb_name_0:
     type: string
     label: vLoadBalancer name
@@ -89,6 +121,10 @@ parameters:
     type: string
     label: vDNS name
     description: Name of the vDNS
+  vpg_name_0:
+    type: string
+    label: vPKTGEN name
+    description: Name of the vPKTGEN
   vnf_id:
     type: string
     label: VNF ID
@@ -171,6 +207,18 @@ resources:
       network_id: { get_resource: vlb_private_network }
       cidr: { get_param: vlb_private_net_cidr }
 
+  pktgen_private_network:
+    type: OS::Neutron::Net
+    properties:
+      name: { get_param: pktgen_private_net_id }
+
+  pktgen_private_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      name: { get_param: pktgen_private_net_id }
+      network_id: { get_resource: pktgen_private_network }
+      cidr: { get_param: pktgen_private_net_cidr }
+
   vlb_private_0_port:
     type: OS::Neutron::Port
     properties:
@@ -183,6 +231,12 @@ resources:
       network: { get_param: onap_private_net_id }
       fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vlb_private_ip_1 }}]
 
+  vlb_private_2_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: pktgen_private_network }
+      fixed_ips: [{"subnet": { get_resource: pktgen_private_subnet }, "ip_address": { get_param: vlb_private_ip_2 }}]
+
   vlb_0:
     type: OS::Nova::Server
     properties:
@@ -194,6 +248,7 @@ resources:
         - network: { get_param: public_net_id }
         - port: { get_resource: vlb_private_0_port }
         - port: { get_resource: vlb_private_1_port }
+        - port: { get_resource: vlb_private_2_port }
       metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
       user_data_format: RAW
       user_data:
@@ -201,7 +256,11 @@ resources:
           params:
             __dcae_collector_ip__: { get_param: dcae_collector_ip }
             __dcae_collector_port__: { get_param: dcae_collector_port }
-            __local_private_ipaddr__: { get_param: vlb_private_ip_0 }
+            __ip_to_dns_net__: { get_param: vlb_private_ip_0 }
+            __ip_to_pktgen_net__: { get_param: vlb_private_ip_2 }
+            __vip__: { get_param: vip }
+            __gre_ipaddr__: { get_param: gre_ipaddr }
+            __pktgen_ipaddr__: { get_param: vpg_private_ip_0 }
             __oam_private_ipaddr__: { get_param: vlb_private_ip_1 }
             __repo_url_blob__: { get_param: repo_url_blob }
             __repo_url_artifacts__: { get_param: repo_url_artifacts }
@@ -209,6 +268,8 @@ resources:
             __install_script_version__: { get_param: install_script_version }
             __vlb_private_net_cidr__: { get_param: vlb_private_net_cidr }
             __onap_private_net_cidr__: { get_param: onap_private_net_cidr }
+            __pktgen_private_net_cidr__: { get_param: pktgen_private_net_cidr }
+            __pktgen_mac__: { get_attr: [vpg_private_0_port, mac_address] }
             __cloud_env__: { get_param: cloud_env }
           template: |
             #!/bin/bash
@@ -217,14 +278,20 @@ resources:
             mkdir /opt/config
             echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt
             echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt
-            echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt
+            echo "__ip_to_dns_net__" > /opt/config/ip_to_dns_net.txt
+            echo "__ip_to_pktgen_net__" > /opt/config/ip_to_pktgen_net.txt
+            echo "__vip__" > /opt/config/vip.txt
+            echo "__gre_ipaddr__" > /opt/config/gre_ipaddr.txt
+            echo "__pktgen_ipaddr__" > /opt/config/pktgen_ipaddr.txt
             echo "__oam_private_ipaddr__" > /opt/config/oam_private_ipaddr.txt
             echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
             echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
             echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
             echo "__install_script_version__" > /opt/config/install_script_version.txt
             echo "__vlb_private_net_cidr__" > /opt/config/vlb_private_net_cidr.txt
+            echo "__pktgen_private_net_cidr__" > /opt/config/pktgen_private_net_cidr.txt
             echo "__onap_private_net_cidr__" > /opt/config/onap_private_net_cidr.txt
+            echo "__pktgen_mac__" > /opt/config/pktgen_mac.txt
             echo "__cloud_env__" > /opt/config/cloud_env.txt
 
             # Download and run install script
@@ -294,4 +361,68 @@ resources:
             curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh
             cd /opt
             chmod +x v_dns_install.sh
-            ./v_dns_install.sh
\ No newline at end of file
+            ./v_dns_install.sh
+
+
+  vpg_private_0_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: pktgen_private_network }
+      fixed_ips: [{"subnet": { get_resource: pktgen_private_subnet }, "ip_address": { get_param: vpg_private_ip_0 }}]
+
+  vpg_private_1_port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_param: onap_private_net_id }
+      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vpg_private_ip_1 }}]
+
+  vpg_0:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: vlb_image_name }
+      flavor: { get_param: vlb_flavor_name }
+      name: { get_param: vpg_name_0 }
+      key_name: { get_resource: my_keypair }
+      networks:
+        - network: { get_param: public_net_id }
+        - port: { get_resource: vpg_private_0_port }
+        - port: { get_resource: vpg_private_1_port }
+      user_data_format: RAW
+      user_data:
+        str_replace:
+          params:
+            __repo_url_blob__: { get_param: repo_url_blob }
+            __repo_url_artifacts__: { get_param: repo_url_artifacts }
+            __local_private_ipaddr__: { get_param: vpg_private_ip_0 }
+            __oam_private_ipaddr__: { get_param: vpg_private_ip_1 }
+            __onap_private_net_cidr__: { get_param: onap_private_net_cidr }
+            __pktgen_private_net_cidr__: { get_param: pktgen_private_net_cidr }
+            __vlb_ipaddr__: { get_param: vlb_private_ip_2 }
+            __demo_artifacts_version__: { get_param: demo_artifacts_version }
+            __install_script_version__: { get_param: install_script_version }
+            __pg_int__: { get_param: pg_int }
+            __vlb_mac__: { get_attr: [vlb_private_2_port, mac_address] }
+            __cloud_env__: { get_param: cloud_env }
+          template: |
+            #!/bin/bash
+
+            # Create configuration files
+            mkdir /opt/config
+            echo "__oam_private_ipaddr__" > /opt/config/oam_private_ipaddr.txt
+            echo "__onap_private_net_cidr__" > /opt/config/onap_private_net_cidr.txt
+            echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt
+            echo "__pktgen_private_net_cidr__" > /opt/config/pktgen_private_net_cidr.txt
+            echo "__vlb_ipaddr__" > /opt/config/vlb_ipaddr.txt
+            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
+            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
+            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
+            echo "__install_script_version__" > /opt/config/install_script_version.txt
+            echo "__pg_int__" > /opt/config/pg_int.txt
+            echo "__vlb_mac__" > /opt/config/vlb_mac.txt
+            echo "__cloud_env__" > /opt/config/cloud_env.txt
+
+            # Download and run install script
+            curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh
+            cd /opt
+            chmod +x v_packetgen_install.sh
+            ./v_packetgen_install.sh
\ No newline at end of file
diff --git a/heat/vLB/base_vlb_rackspace.env b/heat/vLB/base_vlb_rackspace.env
deleted file mode 100644 (file)
index e4c3184..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-parameters:
-  vlb_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
-  vlb_flavor_name: 4 GB General Purpose v1
-  public_net_id: 00000000-0000-0000-0000-000000000000
-  vlb_private_net_id: zdfw1lb01_private
-  onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  vlb_private_net_cidr: 192.168.10.0/24
-  onap_private_net_cidr: 10.0.0.0/16
-  vlb_private_ip_0: 192.168.10.111
-  vlb_private_ip_1: 10.0.100.4
-  vdns_private_ip_0: 192.168.10.211
-  vdns_private_ip_1: 10.0.100.5
-  vlb_name_0: zdfw1lb01lb01
-  vdns_name_0: zdfw1lb01dns01
-  vnf_id: vLoadBalancer_demo_app
-  vf_module_id: vLoadBalancer
-  dcae_collector_ip: 10.0.4.102
-  dcae_collector_port: 8080
-  repo_url_blob: https://nexus.onap.org/content/sites/raw
-  repo_url_artifacts: https://nexus.onap.org/content/groups/staging
-  demo_artifacts_version: 1.1.0
-  install_script_version: 1.1.0-SNAPSHOT
-  key_name: vlb_key
-  pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: rackspace
diff --git a/heat/vLB/base_vlb_rackspace.yaml b/heat/vLB/base_vlb_rackspace.yaml
deleted file mode 100644 (file)
index 316f4cf..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-##########################################################################
-#
-#==================LICENSE_START==========================================
-# 
-#
-# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#==================LICENSE_END============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-##########################################################################
-
-heat_template_version: 2013-05-23
-
-description: Heat template to deploy vLoadBalancer/vDNS demo app for ONAP
-
-##############
-#            #
-# PARAMETERS #
-#            #
-##############
-
-parameters:
-  vlb_image_name:
-    type: string
-    label: Image name or ID
-    description: Image to be used for compute instance
-  vlb_flavor_name:
-    type: string
-    label: Flavor
-    description: Type of instance (flavor) to be used
-  public_net_id:
-    type: string
-    label: Public network name or ID
-    description: Public network that enables remote connection to VNF
-  vlb_private_net_id:
-    type: string
-    label: vLoadBalancer private network name or ID
-    description: Private network that connects vLoadBalancer with vDNSs
-  onap_private_net_id:
-    type: string
-    label: ONAP management network name or ID
-    description: Private network that connects ONAP components and the VNF
-  onap_private_subnet_id:
-    type: string
-    label: ONAP management sub-network name or ID
-    description: Private sub-network that connects ONAP components and the VNF
-  vlb_private_net_cidr:
-    type: string
-    label: vLoadBalancer private network CIDR
-    description: The CIDR of the vLoadBalancer private network
-  onap_private_net_cidr:
-    type: string
-    label: ONAP private network CIDR
-    description: The CIDR of the protected private network
-  vlb_private_ip_0:
-    type: string
-    label: vLoadBalancer private IP address towards the private network
-    description: Private IP address that is assigned to the vLoadBalancer to communicate with the vDNSs
-  vlb_private_ip_1:
-    type: string
-    label: vLoadBalancer private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components
-  vdns_private_ip_0:
-    type: string
-    label: vDNS private IP address towards the private network
-    description: Private IP address that is assigned to the vDNS to communicate with the vLoadBalancer
-  vdns_private_ip_1:
-    type: string
-    label: vDNS private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vDNS to communicate with ONAP components
-  vlb_name_0:
-    type: string
-    label: vLoadBalancer name
-    description: Name of the vLoadBalancer
-  vdns_name_0:
-    type: string
-    label: vDNS name
-    description: Name of the vDNS
-  vnf_id:
-    type: string
-    label: VNF ID
-    description: The VNF ID is provided by ONAP
-  vf_module_id:
-    type: string
-    label: vFirewall module ID
-    description: The vLoadBalancer Module ID is provided by ONAP
-  dcae_collector_ip:
-    type: string
-    label: DCAE collector IP address
-    description: IP address of the DCAE collector
-  dcae_collector_port:
-    type: string
-    label: DCAE collector port
-    description: Port of the DCAE collector
-  key_name:
-    type: string
-    label: Key pair name
-    description: Public/Private key pair name
-  pub_key:
-    type: string
-    label: Public key
-    description: Public key to be installed on the compute instance
-  repo_url_blob:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  repo_url_artifacts:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  install_script_version:
-    type: string
-    label: Installation script version number
-    description: Version number of the scripts that install the vFW demo app
-  demo_artifacts_version:
-    type: string
-    label: Artifacts version used in demo vnfs
-    description: Artifacts (jar, tar.gz) version used in demo vnfs
-  cloud_env:
-    type: string
-    label: Cloud environment
-    description: Cloud environment (e.g., openstack, rackspace)
-
-#############
-#           #
-# RESOURCES #
-#           #
-#############
-
-resources:
-
-  random-str:
-    type: OS::Heat::RandomString
-    properties:
-      length: 4
-
-  my_keypair:
-    type: OS::Nova::KeyPair
-    properties:
-      name:
-        str_replace:
-          template: base_rand
-          params:
-            base: { get_param: key_name }
-            rand: { get_resource: random-str }
-      public_key: { get_param: pub_key }
-      save_private_key: false
-
-  vlb_private_network:
-    type: OS::Neutron::Net
-    properties:
-      name: { get_param: vlb_private_net_id }
-
-  vlb_private_subnet:
-    type: OS::Neutron::Subnet
-    properties:
-      name: { get_param: vlb_private_net_id }
-      network_id: { get_resource: vlb_private_network }
-      cidr: { get_param: vlb_private_net_cidr }
-
-  # Virtual Load Balancer Instantiation
-  vlb_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: vlb_private_network }
-      fixed_ips: [{"subnet": { get_resource: vlb_private_subnet }, "ip_address": { get_param: vlb_private_ip_0 }}]
-
-  vlb_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vlb_private_ip_1 }}]
-
-  vlb_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vlb_image_name }
-      flavor: { get_param: vlb_flavor_name }
-      name: { get_param: vlb_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vlb_private_0_port }
-        - port: { get_resource: vlb_private_1_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __dcae_collector_ip__: { get_param: dcae_collector_ip }
-            __dcae_collector_port__: { get_param: dcae_collector_port }
-            __local_private_ipaddr__: { get_param: vlb_private_ip_0 }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt
-            echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt
-            echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_lb_install.sh -o /opt/v_lb_install.sh
-            cd /opt
-            chmod +x v_lb_install.sh
-            ./v_lb_install.sh
-
-
-  # Virtual DNS Instantiation
-  vdns_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_resource: vlb_private_network }
-      fixed_ips: [{"subnet": { get_resource: vlb_private_subnet }, "ip_address": { get_param: vdns_private_ip_0 }}]
-
-  vdns_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vdns_private_ip_1 }}]
-
-  vdns_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vlb_image_name }
-      flavor: { get_param: vlb_flavor_name }
-      name: { get_param: vdns_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vdns_private_0_port }
-        - port: { get_resource: vdns_private_1_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __lb_oam_int__ : { get_param: vlb_private_ip_1 }
-            __lb_private_ipaddr__: { get_param: vlb_private_ip_0 }
-            __local_private_ipaddr__: { get_param: vdns_private_ip_0 }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__lb_oam_int__" > /opt/config/lb_oam_int.txt
-            echo "__lb_private_ipaddr__" > /opt/config/lb_private_ipaddr.txt
-            echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh
-            cd /opt
-            chmod +x v_dns_install.sh
-            ./v_dns_install.sh
\ No newline at end of file
similarity index 96%
rename from heat/vLB/dnsscaling_openstack.env
rename to heat/vLB/dnsscaling.env
index 3cc328f..5a7839b 100644 (file)
@@ -20,4 +20,4 @@ parameters:
   install_script_version: 1.1.0-SNAPSHOT
   key_name: vlb_key_scaling
   pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: openstack
+  cloud_env: PUT openstack OR backspace HERE
\ No newline at end of file
diff --git a/heat/vLB/dnsscaling_rackspace.env b/heat/vLB/dnsscaling_rackspace.env
deleted file mode 100644 (file)
index 619b35c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-parameters:
-  vlb_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
-  vlb_flavor_name: 4 GB General Purpose v1
-  public_net_id: 00000000-0000-0000-0000-000000000000
-  vlb_private_net_id: zdfw1lb01_private
-  onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE
-  vlb_private_ip_0: 192.168.10.111
-  vlb_private_ip_1: 10.0.100.4
-  vdns_private_ip_0: 192.168.10.212
-  vdns_private_ip_1: 10.0.100.6
-  vdns_name_0: zdfw1lb01dns02
-  vnf_id: vLoadBalancer_demo_app
-  vf_module_id: vLoadBalancer
-  repo_url_blob: https://nexus.onap.org/content/sites/raw
-  repo_url_artifacts: https://nexus.onap.org/content/groups/staging
-  demo_artifacts_version: 1.1.0
-  install_script_version: 1.1.0-SNAPSHOT
-  key_name: vlb_key_scaling
-  pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: rackspace
diff --git a/heat/vLB/dnsscaling_rackspace.yaml b/heat/vLB/dnsscaling_rackspace.yaml
deleted file mode 100644 (file)
index 7a53a56..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-##########################################################################
-#
-#==================LICENSE_START==========================================
-# 
-#
-# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#==================LICENSE_END============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-##########################################################################
-
-heat_template_version: 2013-05-23
-
-description: Heat template to deploy a vDNS for ONAP (scaling-up scenario)
-
-##############
-#            #
-# PARAMETERS #
-#            #
-##############
-
-parameters:
-  vlb_image_name:
-    type: string
-    label: Image name or ID
-    description: Image to be used for compute instance
-  vlb_flavor_name:
-    type: string
-    label: Flavor
-    description: Type of instance (flavor) to be used
-  public_net_id:
-    type: string
-    label: Public network name or ID
-    description: Public network that enables remote connection to VNF
-  vlb_private_net_id:
-    type: string
-    label: vLoadBalancer private network name or ID
-    description: Private network that connects vLoadBalancer with vDNSs
-  onap_private_net_id:
-    type: string
-    label: ONAP management network name or ID
-    description: Private network that connects ONAP components and the VNF
-  onap_private_subnet_id:
-    type: string
-    label: ONAP management sub-network name or ID
-    description: Private sub-network that connects ONAP components and the VNF
-  vlb_private_ip_0:
-    type: string
-    label: vLoadBalancer private IP address towards the private network
-    description: Private IP address that is assigned to the vLoadBalancer to communicate with the vDNSs
-  vlb_private_ip_1:
-    type: string
-    label: vLoadBalancer private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components
-  vdns_private_ip_0:
-    type: string
-    label: vDNS private IP address towards the private network
-    description: Private IP address that is assigned to the vDNS to communicate with the vLoadBalancer
-  vdns_private_ip_1:
-    type: string
-    label: vDNS private IP address towards the ONAP management network
-    description: Private IP address that is assigned to the vDNS to communicate with ONAP components
-  vdns_name_0:
-    type: string
-    label: vDNS name
-    description: Name of the vDNS
-  vnf_id:
-    type: string
-    label: VNF ID
-    description: The VNF ID is provided by ONAP
-  vf_module_id:
-    type: string
-    label: vFirewall module ID
-    description: The vLoadBalancer Module ID is provided by ONAP
-  key_name:
-    type: string
-    label: Key pair name
-    description: Public/Private key pair name
-  pub_key:
-    type: string
-    label: Public key
-    description: Public key to be installed on the compute instance
-  repo_url_blob:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  repo_url_artifacts:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  install_script_version:
-    type: string
-    label: Installation script version number
-    description: Version number of the scripts that install the vFW demo app
-  demo_artifacts_version:
-    type: string
-    label: Artifacts version used in demo vnfs
-    description: Artifacts (jar, tar.gz) version used in demo vnfs
-  cloud_env:
-    type: string
-    label: Cloud environment
-    description: Cloud environment (e.g., openstack, rackspace)
-
-#############
-#           #
-# RESOURCES #
-#           #
-#############
-
-resources:
-
-  random-str:
-    type: OS::Heat::RandomString
-    properties:
-      length: 4
-
-  my_keypair:
-    type: OS::Nova::KeyPair
-    properties:
-      name:
-        str_replace:
-          template: base_rand
-          params:
-            base: { get_param: key_name }
-            rand: { get_resource: random-str }
-      public_key: { get_param: pub_key }
-      save_private_key: false
-
-  # Virtual DNS Instantiation
-  vdns_private_0_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: vlb_private_net_id }
-      fixed_ips: [{"subnet": { get_param: vlb_private_net_id }, "ip_address": { get_param: vdns_private_ip_0 }}]
-
-  vdns_private_1_port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: onap_private_net_id }
-      fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vdns_private_ip_1 }}]
-
-  vdns_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vlb_image_name }
-      flavor: { get_param: vlb_flavor_name }
-      name: { get_param: vdns_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-        - port: { get_resource: vdns_private_0_port }
-        - port: { get_resource: vdns_private_1_port }
-      metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __lb_oam_int__ : { get_param: vlb_private_ip_1 }
-            __lb_private_ipaddr__: { get_param: vlb_private_ip_0 }
-            __local_private_ipaddr__: { get_param: vdns_private_ip_0 }
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__ : { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__lb_oam_int__" > /opt/config/lb_oam_int.txt
-            echo "__lb_private_ipaddr__" > /opt/config/lb_private_ipaddr.txt
-            echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh
-            cd /opt
-            chmod +x v_dns_install.sh
-            ./v_dns_install.sh
\ No newline at end of file
diff --git a/heat/vLB/packet_gen_vlb.env b/heat/vLB/packet_gen_vlb.env
deleted file mode 100644 (file)
index 362b8a9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-parameters:
-  vpg_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
-  vpg_flavor_name: 4 GB General Purpose v1
-  public_net_id: 00000000-0000-0000-0000-000000000000
-  vlb_ipaddr: INSERT THE PUBLIC ADDRESS OF THE vLB HERE
-  vpg_name_0: ziad1vdnspg01pg01
-  repo_url_blob: https://nexus.onap.org/content/sites/raw
-  repo_url_artifacts: https://nexus.onap.org/content/groups/staging
-  demo_artifacts_version: 1.1.0
-  install_script_version: 1.1.0-SNAPSHOT
-  key_name: dns_packetgen_key
-  pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
-  cloud_env: PUT THE CLOUD ENVIRONMENT HERE (rackspace or openstack)
diff --git a/heat/vLB/packet_gen_vlb.yaml b/heat/vLB/packet_gen_vlb.yaml
deleted file mode 100644 (file)
index e41ede8..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-##########################################################################
-#
-#==================LICENSE_START==========================================
-# 
-#
-# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#==================LICENSE_END============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-##########################################################################
-
-heat_template_version: 2013-05-23
-
-description: Heat template to deploy a packet generator for the vLoadBalancer/vDNS demo app for ONAP
-
-##############
-#            #
-# PARAMETERS #
-#            #
-##############
-
-parameters:
-  public_net_id:
-    type: string
-    label: Public network name or ID
-    description: Public network that enables remote connection to VNF
-  vpg_image_name:
-    type: string
-    label: Image name or ID
-    description: Image to be used for compute instance
-  vpg_flavor_name:
-    type: string
-    label: Flavor
-    description: Type of instance (flavor) to be used
-  vpg_name_0:
-    type: string
-    label: vPacketGenerator name
-    description: Name of the vPacketGenerator
-  key_name:
-    type: string
-    label: Key pair name
-    description: Public/Private key pair name
-  pub_key:
-    type: string
-    label: Public key
-    description: Public key to be installed on the compute instance
-  repo_url_blob:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  repo_url_artifacts:
-    type: string
-    label: Repository URL
-    description: URL of the repository that hosts the demo packages
-  vlb_ipaddr:
-    type: string
-    label: Public IP of the vLoadBalancer to which we want to send traffic
-    description: Public IP of the vLoadBalancer to which we want to send traffic
-  install_script_version:
-    type: string
-    label: Installation script version number
-    description: Version number of the scripts that install the vFW demo app
-  demo_artifacts_version:
-    type: string
-    label: Artifacts version used in demo vnfs
-    description: Artifacts (jar, tar.gz) version used in demo vnfs
-  cloud_env:
-    type: string
-    label: Cloud environment
-    description: Cloud environment (e.g., openstack, rackspace)
-
-#############
-#           #
-# RESOURCES #
-#           #
-#############
-
-resources:
-
-  random-str:
-    type: OS::Heat::RandomString
-    properties:
-      length: 4
-
-  my_keypair:
-    type: OS::Nova::KeyPair
-    properties:
-      name:
-        str_replace:
-          template: base_rand
-          params:
-            base: { get_param: key_name }
-            rand: { get_resource: random-str }
-      public_key: { get_param: pub_key }
-      save_private_key: false
-
-  vpg_0:
-    type: OS::Nova::Server
-    properties:
-      image: { get_param: vpg_image_name }
-      flavor: { get_param: vpg_flavor_name }
-      name: { get_param: vpg_name_0 }
-      key_name: { get_resource: my_keypair }
-      networks:
-        - network: { get_param: public_net_id }
-      user_data_format: RAW
-      user_data:
-        str_replace:
-          params:
-            __repo_url_blob__ : { get_param: repo_url_blob }
-            __repo_url_artifacts__ : { get_param: repo_url_artifacts }
-            __vlb_ipaddr__: { get_param: vlb_ipaddr }
-            __demo_artifacts_version__ : { get_param: demo_artifacts_version }
-            __install_script_version__ : { get_param: install_script_version }
-            __cloud_env__: { get_param: cloud_env }
-          template: |
-            #!/bin/bash
-
-            # Create configuration files
-            mkdir /opt/config
-            echo "__vlb_ipaddr__" > /opt/config/vlb_ipaddr.txt
-            echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt
-            echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt
-            echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt
-            echo "__install_script_version__" > /opt/config/install_script_version.txt
-            echo "__cloud_env__" > /opt/config/cloud_env.txt
-
-            # Download and run install script
-            curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh
-            cd /opt
-            chmod +x v_packetgen_install.sh
-            ./v_packetgen_install.sh
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c2b2bba..de21ce8 100755 (executable)
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
   <groupId>org.onap.demo.vnf</groupId>
   <artifactId>demo-aggregator</artifactId>
   <version>1.1.0-SNAPSHOT</version>
-  <name>demo-aggregator</name>
+  <name>demo</name>
   <packaging>pom</packaging>
   <modelVersion>4.0.0</modelVersion>
   <prerequisites>
     <module>vnfs/vCPE/kea-sdnc-notify-mod</module>
   </modules>
 
+  <properties>
+    <sonar.skip>true</sonar.skip>
+  </properties>
+
   <build>
     <plugins>
       <plugin>
index 9b4dfc0..0b4ed57 100755 (executable)
@@ -2,7 +2,7 @@
 set -ex
 
 source /vagrant/openrc
-cp /demo/heat/OpenECOMP/* .
+cp /demo/heat/ONAP/* .
 
 # Parameters used across all ONAP components
 pub_net=$(openstack network list -f value|grep public | cut -f1 -d' ')
index f96ead2..ba51f78 100644 (file)
@@ -1,5 +1,22 @@
 # Doxyfile 1.6.1
 
+# License
+# -------
+#
+# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
+# 
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#         http://www.apache.org/licenses/LICENSE-2.0
+# 
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project
 #
index 21d7a82..6c0aaad 100644 (file)
 # License
 # -------
 #
-# Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+# Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
+# 
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#         http://www.apache.org/licenses/LICENSE-2.0
+# 
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
 #
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-#    this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-#    this list of conditions and the following disclaimer in the documentation
-#    and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-#    must display the following acknowledgement:  This product includes
-#    software developed by the AT&T.
-# 4. Neither the name of AT&T nor the names of its contributors may be used to
-#    endorse or promote products derived from this software without specific
-#    prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #******************************************************************************
 
 ARCH=$(shell getconf LONG_BIT)
index b1e15e5..d37d0e4 100644 (file)
@@ -140,6 +140,7 @@ API_SOURCES=$(EVELLIB_ROOT)/evel.c \
             $(EVELLIB_ROOT)/evel_throttle.c \
             $(EVELLIB_ROOT)/evel_internal_event.c \
             $(EVELLIB_ROOT)/evel_event_mgr.c \
+            $(EVELLIB_ROOT)/evel_threshold_cross.c \
             $(EVELLIB_ROOT)/evel_voicequality.c \
             $(EVELLIB_ROOT)/evel_logging.c \
             $(EVELLIB_ROOT)/jsmn.c
index be0c5f0..0ae1713 100644 (file)
@@ -738,10 +738,10 @@ MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * mea
 typedef struct measurement_fsys_use {
   char * filesystem_name;
   double block_configured;
-  int block_iops;
+  double block_iops;
   double block_used;
   double ephemeral_configured;
-  int ephemeral_iops;
+  double ephemeral_iops;
   double ephemeral_used;
 } MEASUREMENT_FSYS_USE;
 
@@ -1485,6 +1485,21 @@ size_t evel_write_callback(void *contents,
  *****************************************************************************/
 EVENT_HEADER * evel_new_heartbeat(void);
 
+/**************************************************************************//**
+ * Create a new heartbeat event of given name and type.
+ *
+ * @note that the heartbeat is just a "naked" commonEventHeader!
+ *
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
+ *
+ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
+ *          not used it must be released using ::evel_free_event
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_HEADER * evel_new_heartbeat_nameid(const char* ev_name, const char *ev_id);
+
+
 /**************************************************************************//**
  * Free an event header.
  *
@@ -1560,6 +1575,23 @@ void evel_reporting_entity_name_set(EVENT_HEADER * const header,
 void evel_reporting_entity_id_set(EVENT_HEADER * const header,
                                   const char * const entity_id);
 
+/**************************************************************************//**
+ * Set the NFC Naming code property of the event header.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param nfcnamingcode String
+ *****************************************************************************/
+void evel_nfcnamingcode_set(EVENT_HEADER * const header,
+                         const char * const nfcnam);
+/**************************************************************************//**
+ * Set the NF Naming code property of the event header.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param nfnamingcode String
+ *****************************************************************************/
+void evel_nfnamingcode_set(EVENT_HEADER * const header,
+                         const char * const nfnam);
+
 /*****************************************************************************/
 /*****************************************************************************/
 /*                                                                           */
@@ -1575,6 +1607,8 @@ void evel_reporting_entity_id_set(EVENT_HEADER * const header,
  *          function and are immutable once set.  Optional fields have explicit
  *          setter functions, but again values may only be set once so that the
  *          Fault has immutable properties.
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param   condition   The condition indicated by the Fault.
  * @param   specific_problem  The specific problem triggering the fault.
  * @param   priority    The priority of the event.
@@ -1586,7 +1620,8 @@ void evel_reporting_entity_id_set(EVENT_HEADER * const header,
  *          not used (i.e. posted) it must be released using ::evel_free_fault.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_FAULT * evel_new_fault(const char * const condition,
+EVENT_FAULT * evel_new_fault(const char* ev_name, const char *ev_id,
+                            const char * const condition,
                              const char * const specific_problem,
                              EVEL_EVENT_PRIORITIES priority,
                              EVEL_SEVERITIES severity,
@@ -1678,13 +1713,15 @@ void evel_fault_type_set(EVENT_FAULT * fault, const char * const type);
  *          that the Measurement has immutable properties.
  *
  * @param   measurement_interval
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  *
  * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT.  If the
  *          event is not used (i.e. posted) it must be released using
  *          ::evel_free_event.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval);
+EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval,const char* ev_name, const char *ev_id);
 
 /**************************************************************************//**
  * Free a Measurement.
@@ -1918,10 +1955,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
                                    char * filesystem_name,
                                    double block_configured,
                                    double block_used,
-                                   int block_iops,
+                                   double block_iops,
                                    double ephemeral_configured,
                                    double ephemeral_used,
-                                   int ephemeral_iops);
+                                   double ephemeral_iops);
 
 /**************************************************************************//**
  * Add a Feature usage value name/value pair to the Measurement.
@@ -2557,13 +2594,15 @@ void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement
  *          that the Report has immutable properties.
  *
  * @param   measurement_interval
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  *
  * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
  *          not used (i.e. posted) it must be released using
  *          ::evel_free_report.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_REPORT * evel_new_report(double measurement_interval);
+EVENT_REPORT * evel_new_report(double measurement_interval,const char* ev_name, const char *ev_id);
 
 /**************************************************************************//**
  * Free a Report.
@@ -2637,6 +2676,8 @@ void evel_report_custom_measurement_add(EVENT_REPORT * report,
  *          explicit setter functions, but again values may only be set once so
  *          that the Mobile Flow has immutable properties.
  *
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param   flow_direction
  * @param   gtp_per_flow_metrics
  * @param   ip_protocol_type
@@ -2652,6 +2693,7 @@ void evel_report_custom_measurement_add(EVENT_REPORT * report,
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
 EVENT_MOBILE_FLOW * evel_new_mobile_flow(
+                     const char* ev_name, const char *ev_id,
                       const char * const flow_direction,
                       MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics,
                       const char * const ip_protocol_type,
@@ -3372,6 +3414,8 @@ void evel_mobile_gtp_metrics_qci_cos_count_add(
  *          this factory function and are immutable once set.  Optional fields
  *          have explicit setter functions, but again values may only be set
  *          once so that the event has immutable properties.
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param vendor_name   The vendor id to encode in the event vnf field.
  * @param module        The module to encode in the event.
  * @param vnfname       The Virtual network function to encode in the event.
@@ -3380,7 +3424,8 @@ void evel_mobile_gtp_metrics_qci_cos_count_add(
  *          ::evel_free_signaling.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name,
+EVENT_SIGNALING * evel_new_signaling(const char* ev_name, const char *ev_id,
+                                    const char * const vendor_name,
                                      const char * const correlator,
                                     const char * const local_ip_address,
                                     const char * const local_port,
@@ -3582,6 +3627,8 @@ void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event,
  *          setter functions, but again values may only be set once so that the
  *          Syslog has immutable properties.
  *
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param new_state     The new state of the reporting entity.
  * @param old_state     The old state of the reporting entity.
  * @param interface     The card or port name of the reporting entity.
@@ -3591,7 +3638,8 @@ void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event,
  *          ::evel_free_state_change
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state,
+EVENT_STATE_CHANGE * evel_new_state_change(const char* ev_name, const char *ev_id,
+                                          const EVEL_ENTITY_STATE new_state,
                                            const EVEL_ENTITY_STATE old_state,
                                            const char * const interface);
 
@@ -3656,6 +3704,8 @@ void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change,
  *          setter functions, but again values may only be set once so that the
  *          Syslog has immutable properties.
  *
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param   event_source_type
  * @param   syslog_msg
  * @param   syslog_tag
@@ -3665,7 +3715,8 @@ void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change,
  *          not used it must be released using ::evel_free_syslog
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type,
+EVENT_SYSLOG * evel_new_syslog(const char* ev_name, const char *ev_id,
+                               EVEL_SOURCE_TYPES event_source_type,
                                const char * const syslog_msg,
                                const char * const syslog_tag);
 
@@ -3834,12 +3885,14 @@ void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty)
 /**************************************************************************//**
  * Create a new other event.
  *
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  *
  * @returns pointer to the newly manufactured ::EVENT_OTHER.  If the event is
  *          not used it must be released using ::evel_free_other.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_OTHER * evel_new_other(void);
+EVENT_OTHER * evel_new_other(const char* ev_name, const char *ev_id);
 
 /**************************************************************************//**
  * Free an Other.
@@ -3987,6 +4040,8 @@ typedef struct voice_quality_additional_info {
  *          factory function and are immutable once set.  Optional fields have 
  *          explicit setter functions, but again values may only be set once 
  *          so that the Voice Quality has immutable properties.
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param   calleeSideCodec                    Callee codec for the call.
  * @param   callerSideCodec                    Caller codec for the call.
  * @param   correlator                         Constant across all events on this call.
@@ -3998,7 +4053,8 @@ typedef struct voice_quality_additional_info {
                        ::evel_free_voice_quality.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec,
+EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id,
+       const char * const calleeSideCodec,
        const char * const callerSideCodec, const char * const correlator,
        const char * const midCallRtcp, const char * const vendorVnfNameFields);
 
@@ -4248,6 +4304,8 @@ typedef struct event_threshold_cross {
  *          setter functions, but again values may only be set once so that the
  *          TCA has immutable properties.
  *
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @param char* tcriticality   Performance Counter Criticality MAJ MIN,
  * @param char* tname          Performance Counter Threshold name
  * @param char* tthresholdCrossed  Counter Threshold crossed value
@@ -4265,6 +4323,7 @@ typedef struct event_threshold_cross {
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
 EVENT_THRESHOLD_CROSS * evel_new_threshold_cross(
+                               const char* ev_name, const char *ev_id,
                                char * tcriticality,
                               char * tname,
                               char * tthresholdCrossed,
index 6d025ab..ced29b2 100644 (file)
@@ -52,6 +52,51 @@ void evel_set_next_event_sequence(const int sequence)
   EVEL_EXIT();
 }
 
+
+/**************************************************************************//**
+ * Create a new heartbeat event of given name and type.
+ *
+ * @note that the heartbeat is just a "naked" commonEventHeader!
+ *
+ * @param event_name    Unique Event Name: in format
+ * {DomainAbbreviation}_{AsdcModel or ApplicationPlatform}_{DescriptionOfInfoBeingConveyed}
+ * @param event_id     Uniquely identify event for correlation and analysis
+ *
+ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
+ *          not used it must be released using ::evel_free_event
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_HEADER * evel_new_heartbeat_nameid(const char* ev_name, const char *ev_id)
+{
+  EVENT_HEADER * heartbeat = NULL;
+  EVEL_ENTER();
+
+  assert(ev_name != NULL);
+  assert(ev_id != NULL);
+
+  /***************************************************************************/
+  /* Allocate the header.                                                    */
+  /***************************************************************************/
+  heartbeat = malloc(sizeof(EVENT_HEADER));
+  if (heartbeat == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(heartbeat, 0, sizeof(EVENT_HEADER));
+
+  /***************************************************************************/
+  /* Initialize the header.  Get a new event sequence number.  Note that if  */
+  /* any memory allocation fails in here we will fail gracefully because     */
+  /* everything downstream can cope with NULLs.                              */
+  /***************************************************************************/
+  evel_init_header_nameid(heartbeat,ev_name,ev_id);
+
+exit_label:
+  EVEL_EXIT();
+  return heartbeat;
+}
+
 /**************************************************************************//**
  * Create a new heartbeat event.
  *
@@ -141,6 +186,55 @@ void evel_init_header(EVENT_HEADER * const header,const char *const eventname)
   EVEL_EXIT();
 }
 
+
+/**************************************************************************//**
+ * Initialize a newly created event header.
+ *
+ * @param header  Pointer to the header being initialized.
+ *****************************************************************************/
+void evel_init_header_nameid(EVENT_HEADER * const header,const char *const eventname, const char *eventid)
+{
+  struct timeval tv;
+
+  EVEL_ENTER();
+
+  assert(header != NULL);
+  assert(eventname != NULL);
+  assert(eventid != NULL);
+
+  gettimeofday(&tv, NULL);
+
+  /***************************************************************************/
+  /* Initialize the header.  Get a new event sequence number.  Note that if  */
+  /* any memory allocation fails in here we will fail gracefully because     */
+  /* everything downstream can cope with NULLs.                              */
+  /***************************************************************************/
+  header->event_domain = EVEL_DOMAIN_HEARTBEAT;
+  header->event_id = strdup(eventid);
+  header->event_name = strdup(eventname);
+  header->last_epoch_microsec = tv.tv_usec + 1000000 * tv.tv_sec;
+  header->priority = EVEL_PRIORITY_NORMAL;
+  header->reporting_entity_name = strdup(openstack_vm_name());
+  header->source_name = strdup(openstack_vm_name());
+  header->sequence = event_sequence;
+  header->start_epoch_microsec = header->last_epoch_microsec;
+  header->major_version = EVEL_HEADER_MAJOR_VERSION;
+  header->minor_version = EVEL_HEADER_MINOR_VERSION;
+  event_sequence++;
+
+  /***************************************************************************/
+  /* Optional parameters.                                                    */
+  /***************************************************************************/
+  evel_init_option_string(&header->event_type);
+  evel_init_option_string(&header->nfcnaming_code);
+  evel_init_option_string(&header->nfnaming_code);
+  evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid());
+  evel_force_option_string(&header->source_id, openstack_vm_uuid());
+  evel_init_option_intheader(&header->internal_field);
+
+  EVEL_EXIT();
+}
+
 /**************************************************************************//**
  * Set the Event Type property of the event header.
  *
index de4296d..a96124a 100644 (file)
@@ -144,6 +144,16 @@ EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
   evel_throt_api_url = strdup(throt_api_url);
   assert(evel_throt_api_url != NULL);
 
+
+  curl_version_info_data *d = curl_version_info(CURLVERSION_NOW);
+  /* compare with the 24 bit hex number in 8 bit fields */
+  if(d->version_num >= 0x072100) {
+     /* this is libcurl 7.33.0 or later */
+     EVEL_INFO("7.33 or later Curl version %x.",d->version_num);
+  }
+  else {
+     EVEL_INFO("Old Curl version.");
+  }
   /***************************************************************************/
   /* Start the CURL library. Note that this initialization is not threadsafe */
   /* which imposes a constraint that the EVEL library is initialized before  */
@@ -408,7 +418,7 @@ EVEL_ERR_CODES event_handler_terminate()
     /*************************************************************************/
     /* Make sure that the event handler knows it's time to die.              */
     /*************************************************************************/
-    event = evel_new_internal_event(EVT_CMD_TERMINATE);
+    event = evel_new_internal_event(EVT_CMD_TERMINATE,"EVELinternal","EVELid");
     if (event == NULL)
     {
       /***********************************************************************/
index 7cbadfe..c211f60 100644 (file)
@@ -36,6 +36,8 @@
  *          function and are immutable once set.  Optional fields have explicit
  *          setter functions, but again values may only be set once so that the
  *          Fault has immutable properties.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param   condition   The condition indicated by the Fault.
  * @param   specific_problem  The specific problem triggering the fault.
  * @param   priority    The priority of the event.
@@ -47,7 +49,9 @@
  *          not used (i.e. posted) it must be released using ::evel_free_fault.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_FAULT * evel_new_fault(const char * const condition,
+EVENT_FAULT * evel_new_fault(const char * ev_name,
+                            const char * ev_id,
+                            const char * const condition,
                              const char * const specific_problem,
                             EVEL_EVENT_PRIORITIES priority,
                              EVEL_SEVERITIES severity,
@@ -81,7 +85,7 @@ EVENT_FAULT * evel_new_fault(const char * const condition,
   /* Initialize the header & the fault fields.  Optional string values are   */
   /* uninitialized (NULL).                                                   */
   /***************************************************************************/
-  evel_init_header(&fault->header,"Fault");
+  evel_init_header_nameid(&fault->header,ev_name,ev_id);
   fault->header.event_domain = EVEL_DOMAIN_FAULT;
   fault->header.priority = priority;
   fault->major_version = EVEL_FAULT_MAJOR_VERSION;
index 73773ed..872af1f 100644 (file)
@@ -35,6 +35,8 @@
  *          this factory function and are immutable once set.  Optional fields
  *          have explicit setter functions, but again values may only be set
  *          once so that the event has immutable properties.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param vendor_id     The vendor id to encode in the event instance id.
  * @param event_id      The vendor event id to encode in the event instance id.
  * @returns pointer to the newly manufactured ::EVENT_HEARTBEAT_FIELD.  If the event
@@ -42,7 +44,7 @@
  *          ::evel_free_hrtbt_field.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval)
+EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval,const char* ev_name, const char *ev_id)
 {
   EVENT_HEARTBEAT_FIELD * event = NULL;
 
@@ -68,7 +70,7 @@ EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval)
   /***************************************************************************/
   /* Initialize the header & the Heartbeat fields fields.                           */
   /***************************************************************************/
-  evel_init_header(&event->header,"HeartbeatFields");
+  evel_init_header_nameid(&event->header,ev_name,ev_id);
   event->header.event_domain = EVEL_DOMAIN_HEARTBEAT_FIELD;
   event->major_version = EVEL_HEARTBEAT_FIELD_MAJOR_VERSION;
   event->minor_version = EVEL_HEARTBEAT_FIELD_MINOR_VERSION;
index f057fe8..46f71af 100644 (file)
@@ -226,7 +226,7 @@ EVEL_ERR_CODES event_handler_run();
  *          ::evel_free_event.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command);
+EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command,const char* ev_name, const char *ev_id);
 
 /**************************************************************************//**
  * Free an internal event.
index 511c7d5..cb56c88 100644 (file)
  *          setter functions, but again values may only be set once so that the
  *          Fault has immutable properties.
  * @param   command   The condition indicated by the event.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @returns pointer to the newly manufactured ::EVENT_INTERNAL.  If the event
  *          is not used (i.e. posted) it must be released using
  *          ::evel_free_event.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command)
+EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command,const char* ev_name, const char *ev_id)
 {
   EVENT_INTERNAL * event = NULL;
   EVEL_ENTER();
@@ -73,7 +75,7 @@ EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command)
   /***************************************************************************/
   /* Initialize the header & the event fields.                               */
   /***************************************************************************/
-  evel_init_header(&event->header,NULL);
+  evel_init_header_nameid(&event->header,ev_name,ev_id);
   event->header.event_domain = EVEL_DOMAIN_INTERNAL;
   event->command = command;
 
index 0716e45..5085d6a 100644 (file)
@@ -80,6 +80,8 @@ void evel_json_encode_mobile_flow_gtp_flow_metrics(
  *          factory function and are immutable once set.  Optional fields have
  *          explicit setter functions, but again values may only be set once so
  *          that the Mobile Flow has immutable properties.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param   flow_direction              Flow direction.
  * @param   gtp_per_flow_metrics        GTP per-flow metrics.
  * @param   ip_protocol_type            IP protocol type.
@@ -93,7 +95,7 @@ void evel_json_encode_mobile_flow_gtp_flow_metrics(
  *          ::evel_free_mobile_flow.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_MOBILE_FLOW * evel_new_mobile_flow(
+EVENT_MOBILE_FLOW * evel_new_mobile_flow(const char* ev_name, const char *ev_id,
                             const char * const flow_direction,
                             MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics,
                             const char * const ip_protocol_type,
@@ -134,7 +136,7 @@ EVENT_MOBILE_FLOW * evel_new_mobile_flow(
   /* Initialize the header & the Mobile Flow fields.  Optional string values */
   /* are uninitialized (NULL).                                               */
   /***************************************************************************/
-  evel_init_header(&mobile_flow->header,"MobileFlow");
+  evel_init_header_nameid(&mobile_flow->header,ev_name,ev_id);
   mobile_flow->header.event_domain = EVEL_DOMAIN_MOBILE_FLOW;
   mobile_flow->major_version = EVEL_MOBILE_FLOW_MAJOR_VERSION;
   mobile_flow->minor_version = EVEL_MOBILE_FLOW_MINOR_VERSION;
index 447ac9a..c7a227b 100644 (file)
@@ -39,7 +39,7 @@
  *          not used (i.e. posted) it must be released using ::evel_free_other.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_OTHER * evel_new_other()
+EVENT_OTHER * evel_new_other(const char *ev_name, const char *ev_id)
 {
   EVENT_OTHER * other = NULL;
   EVEL_ENTER();
@@ -64,7 +64,7 @@ EVENT_OTHER * evel_new_other()
   /* Initialize the header & the Other fields.  Optional string values are   */
   /* uninitialized (NULL).                                                   */
   /***************************************************************************/
-  evel_init_header(&other->header,"OtherEvent");
+  evel_init_header_nameid(&other->header,ev_name,ev_id);
   other->header.event_domain = EVEL_DOMAIN_OTHER;
   other->major_version = EVEL_OTHER_EVENT_MAJOR_VERSION;
   other->minor_version = EVEL_OTHER_EVENT_MINOR_VERSION;
index a739723..38a1731 100644 (file)
  *          that the Report has immutable properties.
  *
  * @param   measurement_interval
-
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc
  * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
  *          not used (i.e. posted) it must be released using ::evel_free_event.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_REPORT * evel_new_report(double measurement_interval)
+EVENT_REPORT * evel_new_report(double measurement_interval,const char *ev_name, const char *ev_id)
 {
   EVENT_REPORT * report = NULL;
 
@@ -75,7 +76,7 @@ EVENT_REPORT * evel_new_report(double measurement_interval)
   /***************************************************************************/
   /* Initialize the header & the report fields.                              */
   /***************************************************************************/
-  evel_init_header(&report->header,"Report");
+  evel_init_header_nameid(&report->header,ev_name,ev_id);
   report->header.event_domain = EVEL_DOMAIN_REPORT;
   report->measurement_interval = measurement_interval;
 
@@ -328,7 +329,7 @@ void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
       {
         evel_json_open_object(jbuf);
         evel_enc_kv_string(jbuf, "name", measurement_group->name);
-        evel_json_open_named_list(jbuf, "measurements");
+        evel_json_open_named_list(jbuf, "arrayOfFields");
 
         /*********************************************************************/
         /* Measurements list.                                                */
index f1b38e3..7920d81 100644 (file)
  *          that the Measurement has immutable properties.
  *
  * @param   measurement_interval
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  *
  * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT.  If the
  *          event is not used (i.e. posted) it must be released using
  *          ::evel_free_event.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval)
+EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval, const char* ev_name, const char *ev_id)
 {
   EVENT_MEASUREMENT * measurement = NULL;
 
@@ -69,7 +71,7 @@ EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval)
   /***************************************************************************/
   /* Initialize the header & the measurement fields.                         */
   /***************************************************************************/
-  evel_init_header(&measurement->header,"vnfScalingMeasurement");
+  evel_init_header_nameid(&measurement->header,ev_name,ev_id);
   measurement->header.event_domain = EVEL_DOMAIN_MEASUREMENT;
   measurement->measurement_interval = measurement_interval;
   dlist_initialize(&measurement->additional_info);
@@ -1531,10 +1533,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
                                    char * filesystem_name,
                                    double block_configured,
                                    double block_used,
-                                   int block_iops,
+                                   double block_iops,
                                    double ephemeral_configured,
                                    double ephemeral_used,
-                                   int ephemeral_iops)
+                                   double ephemeral_iops)
 {
   MEASUREMENT_FSYS_USE * fsys_use = NULL;
   EVEL_ENTER();
@@ -1547,10 +1549,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
   assert(filesystem_name != NULL);
   assert(block_configured >= 0.0);
   assert(block_used >= 0.0);
-  assert(block_iops >= 0);
+  assert(block_iops >= 0.0);
   assert(ephemeral_configured >= 0.0);
   assert(ephemeral_used >= 0.0);
-  assert(ephemeral_iops >= 0);
+  assert(ephemeral_iops >= 0.0);
 
   /***************************************************************************/
   /* Allocate a container for the value and push onto the list.              */
@@ -1563,7 +1565,7 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
   fsys_use->block_configured = block_configured;
   fsys_use->block_used = block_used;
   fsys_use->block_iops = block_iops;
-  fsys_use->ephemeral_configured = block_configured;
+  fsys_use->ephemeral_configured = ephemeral_configured;
   fsys_use->ephemeral_used = ephemeral_used;
   fsys_use->ephemeral_iops = ephemeral_iops;
 
@@ -3201,15 +3203,15 @@ void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf,
                                           fsys_use->filesystem_name))
       {
         evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "filesystemName", fsys_use->filesystem_name);
         evel_enc_kv_double(
           jbuf, "blockConfigured", fsys_use->block_configured);
-        evel_enc_kv_int(jbuf, "blockIops", fsys_use->block_iops);
+        evel_enc_kv_double(jbuf, "blockIops", fsys_use->block_iops);
         evel_enc_kv_double(jbuf, "blockUsed", fsys_use->block_used);
         evel_enc_kv_double(
           jbuf, "ephemeralConfigured", fsys_use->ephemeral_configured);
-        evel_enc_kv_int(jbuf, "ephemeralIops", fsys_use->ephemeral_iops);
+        evel_enc_kv_double(jbuf, "ephemeralIops", fsys_use->ephemeral_iops);
         evel_enc_kv_double(jbuf, "ephemeralUsed", fsys_use->ephemeral_used);
-        evel_enc_kv_string(jbuf, "filesystemName", fsys_use->filesystem_name);
         evel_json_close_object(jbuf);
         item_added = true;
       }
@@ -3516,7 +3518,7 @@ void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf,
       {
         evel_json_open_object(jbuf);
         evel_enc_kv_string(jbuf, "name", measurement_group->name);
-        evel_json_open_opt_named_list(jbuf, "measurements");
+        evel_json_open_opt_named_list(jbuf, "arrayOfFields");
 
         /*********************************************************************/
         /* Measurements list.                                                */
@@ -3711,3 +3713,4 @@ void evel_free_measurement(EVENT_MEASUREMENT * event)
 
   EVEL_EXIT();
 }
+
index 09c95cd..45f5348 100644 (file)
@@ -33,6 +33,8 @@
  *          this factory function and are immutable once set.  Optional fields
  *          have explicit setter functions, but again values may only be set
  *          once so that the event has immutable properties.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param vendor_name   The vendor id to encode in the event vnf field.
  * @param module        The module to encode in the event.
  * @param vnfname       The Virtual network function to encode in the event.
@@ -41,7 +43,8 @@
  *          ::evel_free_signaling.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name,
+EVENT_SIGNALING * evel_new_signaling(const char* ev_name, const char *ev_id,
+                                    const char * const vendor_name,
                                      const char * const correlator,
                                      const char * const local_ip_address,
                                      const char * const local_port,
@@ -72,7 +75,7 @@ EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name,
   /***************************************************************************/
   /* Initialize the header & the Signaling fields.                           */
   /***************************************************************************/
-  evel_init_header(&event->header,"SipSignaling");
+  evel_init_header_nameid(&event->header,ev_name,ev_id);
   event->header.event_domain = EVEL_DOMAIN_SIPSIGNALING;
   event->major_version = EVEL_SIGNALING_MAJOR_VERSION;
   event->minor_version = EVEL_SIGNALING_MINOR_VERSION;
index c9de506..8915afa 100644 (file)
@@ -34,6 +34,8 @@
  *          explicit setter functions, but again values may only be set once
  *          so that the State Change has immutable properties.
  *
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param new_state     The new state of the reporting entity.
  * @param old_state     The old state of the reporting entity.
  * @param interface     The card or port name of the reporting entity.
@@ -43,7 +45,9 @@
  *          ::evel_free_state_change
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state,
+EVENT_STATE_CHANGE * evel_new_state_change(const char* ev_name,
+                                           const char *ev_id,
+                                          const EVEL_ENTITY_STATE new_state,
                                            const EVEL_ENTITY_STATE old_state,
                                            const char * const interface)
 {
@@ -73,7 +77,7 @@ EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state,
   /* Initialize the header & the State Change fields.  Optional string       */
   /* values are uninitialized (NULL).                                        */
   /***************************************************************************/
-  evel_init_header(&state_change->header,"StateChange");
+  evel_init_header_nameid(&state_change->header,ev_name,ev_id);
   state_change->header.event_domain = EVEL_DOMAIN_STATE_CHANGE;
   state_change->major_version = EVEL_STATE_CHANGE_MAJOR_VERSION;
   state_change->minor_version = EVEL_STATE_CHANGE_MINOR_VERSION;
index fb22df9..85b0ec9 100644 (file)
@@ -33,6 +33,8 @@
  *          function and are immutable once set.  Optional fields have explicit
  *          setter functions, but again values may only be set once so that the
  *          Syslog has immutable properties.
+ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param   event_source_type  The type of Syslog event source.
  * @param   syslog_msg         The Syslog event message.
  * @param   syslog_tag         The messgaeId identifying the type of message.
@@ -41,7 +43,8 @@
  *          ::evel_free_syslog.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type,
+EVENT_SYSLOG * evel_new_syslog(const char* ev_name, const char *ev_id,
+                              EVEL_SOURCE_TYPES event_source_type,
                                const char * const syslog_msg,
                                const char * const syslog_tag)
 {
@@ -71,7 +74,7 @@ EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type,
   /* Initialize the header & the Syslog fields.  Optional string values are  */
   /* uninitialized (NULL).                                                   */
   /***************************************************************************/
-  evel_init_header(&syslog->header,"Syslog");
+  evel_init_header_nameid(&syslog->header,ev_name,ev_id);
   syslog->header.event_domain = EVEL_DOMAIN_SYSLOG;
   syslog->major_version = EVEL_SYSLOG_MAJOR_VERSION;
   syslog->minor_version = EVEL_SYSLOG_MINOR_VERSION;
index a0a9cc3..f4fa620 100644 (file)
@@ -35,6 +35,8 @@
  *          setter functions, but again values may only be set once so that the
  *          TCA has immutable properties.
  *
+ * @param event_name  Unique Event Name confirming Domain AsdcVnfModel Description
+ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
  * @param char* tcriticality   Performance Counter Criticality MAJ MIN,
  * @param char* tname          Performance Counter Threshold name
  * @param char* tthresholdCrossed  Counter Threshold crossed value
@@ -51,7 +53,8 @@
  *          ::evel_free_threshold_cross
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( char *  tcriticality,
+EVENT_THRESHOLD_CROSS * evel_new_threshold_cross(const char * ev_name, const char * ev_id,
+                          char *  tcriticality,
                            char *  tname,
                            char *  tthresholdCrossed,
                            char *  tvalue,
@@ -87,7 +90,7 @@ EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( char *  tcriticality,
   /***************************************************************************/
   /* Initialize the header & the threshold crossing fields.                  */
   /***************************************************************************/
-  evel_init_header(&event->header,"thresholdCrossingAlert");
+  evel_init_header_nameid(&event->header,ev_name,ev_id);
   event->header.event_domain = EVEL_DOMAIN_THRESHOLD_CROSS;
   event->major_version = EVEL_THRESHOLD_CROSS_MAJOR_VERSION;
   event->minor_version = EVEL_THRESHOLD_CROSS_MINOR_VERSION;
index c3826ca..cf2ec87 100644 (file)
@@ -34,6 +34,8 @@
  *          factory function and are immutable once set.  Optional fields have 
  *          explicit setter functions, but again values may only be set once 
  *          so that the Voice Quality has immutable properties.
+ * @param event_name    Unique Event Name
+ * @param event_id    A universal identifier of the event for analysis etc.
  * @param   calleeSideCodec         Callee codec for the call.
  * @param   callerSideCodec         Caller codec for the call.
  * @param   correlator              Constant across all events on this call.
@@ -45,7 +47,8 @@
             ::evel_free_voice_quality.
  * @retval  NULL  Failed to create the event.
  *****************************************************************************/
-EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec,
+EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id,
+                                       const char * const calleeSideCodec,
     const char * const callerSideCodec, const char * const correlator,
     const char * const midCallRtcp, const char * const vendorName) {
     
@@ -82,7 +85,7 @@ EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec,
         /* Initialize the header & the fault fields.  Optional integer values are   */
         /* initialized as 0.                                                        */
         /***************************************************************************/
-        evel_init_header(&voiceQuality->header,"voiceQuality");
+        evel_init_header_nameid(&voiceQuality->header,ev_name,ev_id);
         voiceQuality->header.event_domain = EVEL_DOMAIN_VOICE_QUALITY;
         voiceQuality->major_version = EVEL_VOICEQ_MAJOR_VERSION;
         voiceQuality->minor_version = EVEL_VOICEQ_MINOR_VERSION;
diff --git a/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc b/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc
deleted file mode 100644 (file)
index 7a084e5..0000000
Binary files a/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc and /dev/null differ
index 986ed8f..160add5 100644 (file)
@@ -2,48 +2,37 @@
     "$schema": "http://json-schema.org/draft-04/schema#",\r
        \r
        "definitions": {\r
-               "attCopyrightNotice": {\r
-                       "description": "Copyright (c) <2016>, AT&T Intellectual Property.  All other rights reserved",\r
-                       "type": "object",\r
-                       "properties": {\r
-                               "useAndRedistribution": {\r
-                                       "description": "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:",\r
-                                       "type": "string"\r
-                               },\r
-                               "condition1": {\r
-                                       "description": "Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.",\r
-                                       "type": "string"\r
-                               },\r
-                               "condition2": {\r
-                                       "description": "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.",\r
-                                       "type": "string"\r
-                               },\r
-                               "condition3": {\r
-                                       "description": "All advertising materials mentioning features or use of this software must display the following acknowledgement:  This product includes software developed by the AT&T.",\r
-                                       "type": "string"\r
-                               },\r
-                               "condition4": {\r
-                                       "description": "Neither the name of AT&T nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.",\r
-                                       "type": "string"\r
-                               },\r
-                               "disclaimerLine1": {\r
-                                       "description": "THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS",\r
-                                       "type": "string"\r
-                               },\r
-                               "disclaimerLine2": {\r
-                                       "description": "FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES",\r
-                                       "type": "string"\r
-                               },\r
-                               "disclaimerLine3": {\r
-                                       "description": "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,",\r
-                                       "type": "string"\r
+                       "attCopyrightNotice": {\r
+                               "description": "Copyright (c) <2017>, AT&T Intellectual Property. All rights reserved. Licensed under the Apache License, Version 2.0 (the License)",\r
+                               "type": "object",\r
+                               "properties": {\r
+                                       "useAndRedistribution": {\r
+                                               "description": "You may not use this file except in compliance with the License.You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0",\r
+                                               "type": "string"\r
+                                       },\r
+                                       "licenseLink": "http://www.apache.org/licenses/LICENSE-2.0",\r
+                                       "condition1": {\r
+                                               "description": "Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an AS IS BASIS,",\r
+                                               "type": "string"\r
+                                       },\r
+                                       "condition2": {\r
+                                               "description": "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.",\r
+                                               "type": "string"\r
+                                       },\r
+                                       "condition3": {\r
+                                               "description": "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",\r
+                                               "type": "string"\r
+                                       },\r
+                                       "condition4": {\r
+                                               "description": "See the License for the specific language governing permissions and limitations under the License.",\r
+                                               "type": "string"\r
+                                       },\r
+                                       "Trademarks": {\r
+                                               "description": "ECOMP and OpenECOMP are trademarks and service marks of AT&T Intellectual Property.",\r
+                                               "type": "string"\r
+                                       }\r
+                                  }\r
                                },\r
-                               "disclaimerLine4": {\r
-                                       "description": "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",\r
-                                       "type": "string"\r
-                               }\r
-                       }\r
-               },\r
                "codecsInUse": {\r
                        "description": "number of times an identified codec was used over the measurementInterval",\r
                        "type": "object",\r
                                        "type": "string"\r
                                },\r
                                "vfModuleName": {\r
-                                       "description": "ASDC vfModuleName for the vfModule generating the event",\r
+                                       "description": "SDC vfModuleName for the vfModule generating the event",\r
                                        "type": "string"\r
                                },\r
                                "vnfName": {\r
-                                       "description": "ASDC modelName for the VNF generating the event",\r
+                                       "description": "SDC modelName for the VNF generating the event",\r
                                        "type": "string"\r
                                }\r
                        },\r
index 05f52af..8604d0c 100644 (file)
@@ -245,7 +245,7 @@ int main(int argc, char** argv)
       packets_out_this_round = 0;
     }
 
-    vpp_m = evel_new_measurement(READ_INTERVAL);
+    vpp_m = evel_new_measurement(READ_INTERVAL,"Measurement_vVNF","TrafficStats_1.2.3.4");
     vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance("eth0", "true");
     evel_meas_vnic_performance_add(vpp_m, vnic_performance);
 
@@ -277,6 +277,8 @@ int main(int argc, char** argv)
       evel_last_epoch_set(&vpp_m->header, epoch_now);
       epoch_start = epoch_now;
 
+      evel_nfcnamingcode_set(&vpp_m->header, "vVNF");
+      evel_nfnamingcode_set(&vpp_m->header, "vVNF");
       //strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available");
       //strcpy(vpp_m_header->reporting_entity_name, hostname);
       evel_reporting_entity_name_set(&vpp_m->header, "fwll");
index afbbce8..98450f0 100644 (file)
@@ -206,7 +206,7 @@ int main(int argc, char** argv)
       packets_out_this_round = 0;
     }
 
-    vpp_m = evel_new_measurement(READ_INTERVAL);
+    vpp_m = evel_new_measurement(READ_INTERVAL,"Measurement_vVNF","TrafficStats_1.2.3.4");
     vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance("eth0", "true");
     evel_meas_vnic_performance_add(vpp_m, vnic_performance);
 
@@ -237,9 +237,11 @@ int main(int argc, char** argv)
       evel_last_epoch_set(&vpp_m->header, epoch_now);
       epoch_start = epoch_now;
 
+      evel_nfcnamingcode_set(&vpp_m->header, "vVNF");
+      evel_nfnamingcode_set(&vpp_m->header, "vVNF");
       //strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available");
       //strcpy(vpp_m_header->reporting_entity_name, hostname);
-      evel_reporting_entity_name_set(&vpp_m->header, hostname);
+      evel_reporting_entity_name_set(&vpp_m->header, "lbll");
       evel_reporting_entity_id_set(&vpp_m->header, "No UUID available");
       evel_rc = evel_post_event(vpp_m_header);
 
index 1a8ee2e..6fd0984 100644 (file)
@@ -1,3 +1,4 @@
-{"url": "http://localhost/sdnc.php?macaddr=",
+{
+ "url": "http://DMAAP_IPADDR:3904/events/VCPE-DHCP-EVENT/",
  "siaddr": "siaddr"
 }
diff --git a/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test b/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test
new file mode 100644 (file)
index 0000000..beba0f1
--- /dev/null
@@ -0,0 +1,4 @@
+{
+ "url": "http://localhost/sdnc.php",
+ "siaddr": "siaddr"
+}
index 231a0a8..70d8628 100644 (file)
@@ -84,10 +84,12 @@ int pkt4_send(CalloutHandle& handle) {
     hwaddr = hwaddr_ptr->toText(false);
     yiaddr = new_yiaddr.toText();
     msg_name = response4_ptr->getName();
-    post_data = "{ macaddr=" + hwaddr + "&yiaddr=" + yiaddr + "&msg=" + msg_name + "}";
-    final_url = json_params[0] + hwaddr;
+    /* POST string for DMaaP */
+    post_data = "{\n\"macaddr\":\"" + hwaddr + "\",\n\"yiaddr\":\"" + yiaddr + "\",\n\"msg_name\":\"" + msg_name + "\"\n}";
+    final_url = json_params[0] ;
     LOG_DEBUG(logger, 0, "SNL_BASE").arg(final_url);
     LOG_DEBUG(logger, 0, "SNL_BASE").arg(yiaddr);
+    LOG_DEBUG(logger, 0, "SNL_BASE").arg(post_data);
 
 
     if ( msg_name == "DHCPACK")
@@ -106,6 +108,7 @@ int pkt4_send(CalloutHandle& handle) {
         return(1);
     }
 
+    list = curl_slist_append(list, "Content-type: application/json");
     list = curl_slist_append(list, "Accept: application/json");
     if (list == NULL) {
         curl_easy_cleanup(curl);
@@ -126,15 +129,11 @@ int pkt4_send(CalloutHandle& handle) {
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
 
-    // If we don't set a timeout, curl will try for 300 seconds by default.
+    // Default curl timeout is 300 seconds 
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L);
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1L);
-    // libcurl's docs say to cast as void, don't blame me.
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response_memfile);
-    // CURLOPT_URL takes a char*
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_URL, (final_url).c_str());
-    
-    // let curl use strlen
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L );
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str() );
     curl_opt_res += curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
diff --git a/vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf b/vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf
new file mode 100644 (file)
index 0000000..3e2287d
--- /dev/null
@@ -0,0 +1,59 @@
+{
+"Dhcp4":
+  {
+# For testing, you can use veth pair as described in README.md
+  "interfaces-config": {
+    "interfaces": ["eth0" ]
+  },
+
+  "lease-database": {
+    "type": "memfile"
+  },
+
+  "expired-leases-processing": {
+    "reclaim-timer-wait-time": 10,
+    "flush-reclaimed-timer-wait-time": 25,
+    "hold-reclaimed-time": 3600,
+    "max-reclaim-leases": 100,
+    "max-reclaim-time": 250,
+    "unwarned-reclaim-cycles": 5
+  },
+
+  "valid-lifetime": 300,
+
+# Ensure you set some sensible defaults for the siaddr and option-data,
+# otherwise the options won't be added at all.
+# Also keep in mind that if kea doesn't receive the desired values for some
+# reason, these values will be sent to the client.
+  "subnet4": [
+      {        "subnet": "10.2.0.0/24",
+             "pools" : [ { "pool": "10.2.0.2 - 10.2.0.255"} ],
+            "next-server": "10.2.0.1",
+            "option-data": [
+                 {"name": "tftp-server-name",
+                  "data": "10.2.0.1"},
+                      {"name": "boot-file-name",
+                  "data": "/dev/null"}
+               ]
+      }
+  ]
+
+},
+
+"Logging":
+{
+  "loggers": [
+    {
+      "name": "kea-dhcp4",
+      "output_options": [
+          {
+            "output": "/var/log/kea-dhcp4.log"
+          }
+      ],
+      "severity": "DEBUG",
+      "debuglevel": 0
+    },
+  ]
+}
+
+}
index 1a8ee2e..6fd0984 100644 (file)
@@ -1,3 +1,4 @@
-{"url": "http://localhost/sdnc.php?macaddr=",
+{
+ "url": "http://DMAAP_IPADDR:3904/events/VCPE-DHCP-EVENT/",
  "siaddr": "siaddr"
 }
index a4a34ac..797da69 100644 (file)
@@ -48,9 +48,10 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
 # Download DHCP config files
@@ -62,6 +63,9 @@ chmod +x v_aaa.sh
 mv v_aaa.sh /etc/init.d
 update-rc.d v_aaa.sh defaults
 
+# Download and install FreeRADIUS as AAA server
+apt-get install -y freeradius
+
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
 then
index a9bf588..6fb2ead 100644 (file)
@@ -1 +1,4 @@
 #!/bin/bash
+
+systemctl start vpp
+
index dad8b2f..02025b2 100644 (file)
@@ -4,6 +4,9 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt)
 REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt)
 DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
+VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt)
+VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt)
+VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 
 # Convert Network CIDR to Netmask
@@ -68,11 +71,280 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
+# Install the tools required for download codes
+apt-get install -y expect git patch
+
+#Download and build the VPP codes
+cd /opt
+git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp
+wget -O Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch ${VPP_PATCH_URL}
+
+cd vpp
+patch -p1 < Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch
+expect -c "
+        set timeout 60;
+        spawn make install-dep;
+        expect {
+                \"Do you want to continue?*\" {send \"Y\r\"; interact}
+        }
+"
+
+cd build-root
+./bootstrap.sh
+make V=0 PLATFORM=vpp TAG=vpp install-deb
+
+# Install the FreeRADIUS client since we need the lib
+cd /opt
+git clone https://github.com/FreeRADIUS/freeradius-client.git
+cd freeradius-client
+./configure
+make && make install
+cd /usr/local/lib && ln -s -f libfreeradius-client.so.2.0.0 libfreeradiusclient.so
+ldconfig
+
+# Install the VPP package
+cd /opt/vpp/build-root
+dpkg -i *.deb
+systemctl stop vpp
+
+# Auto-start configuration for the VPP
+cat > /etc/vpp/startup.conf << EOF
+
+unix {
+  nodaemon
+  log /tmp/vpp.log
+  full-coredump
+  cli-listen localhost:5002
+  startup-config /etc/vpp/setup.gate
+}
+
+api-trace {
+  on
+}
+
+api-segment {
+  gid vpp
+}
+
+cpu {
+       ## In the VPP there is one main thread and optionally the user can create worker(s)
+       ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+       ## Manual pinning of thread(s) to CPU core(s)
+
+       ## Set logical CPU core where main thread runs
+       # main-core 1
+
+       ## Set logical CPU core(s) where worker threads are running
+       # corelist-workers 2-3,18-19
+
+       ## Automatic pinning of thread(s) to CPU core(s)
+
+       ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+       ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+       ## The main thread is automatically pinned to the first available CPU core and worker(s)
+       ## are pinned to next free CPU core(s) after core assigned to main thread
+       # skip-cores 4
+
+       ## Specify a number of workers to be created
+       ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+       ## and main thread's CPU core
+       # workers 2
+
+       ## Set scheduling policy and priority of main and worker threads
+
+       ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+       ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+       # scheduler-policy fifo
+
+       ## Scheduling priority is used only for "real-time policies (fifo and rr),
+       ## and has to be in the range of priorities supported for a particular policy
+       # scheduler-priority 50
+}
+
+# dpdk {
+       ## Change default settings for all intefaces
+       # dev default {
+               ## Number of receive queues, enables RSS
+               ## Default is 1
+               # num-rx-queues 3
+
+               ## Number of transmit queues, Default is equal
+               ## to number of worker threads or 1 if no workers treads
+               # num-tx-queues 3
+
+               ## Number of descriptors in transmit and receive rings
+               ## increasing or reducing number can impact performance
+               ## Default is 1024 for both rx and tx
+               # num-rx-desc 512
+               # num-tx-desc 512
+
+               ## VLAN strip offload mode for interface
+               ## Default is off
+               # vlan-strip-offload on
+       # }
+
+       ## Whitelist specific interface by specifying PCI address
+       # dev 0000:02:00.0
+
+       ## Whitelist specific interface by specifying PCI address and in
+       ## addition specify custom parameters for this interface
+       # dev 0000:02:00.1 {
+       #       num-rx-queues 2
+       # }
+
+       ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci
+       ## and uio_pci_generic (default)
+       # uio-driver vfio-pci
+
+       ## Disable mutli-segment buffers, improves performance but
+       ## disables Jumbo MTU support
+       # no-multi-seg
+
+       ## Increase number of buffers allocated, needed only in scenarios with
+       ## large number of interfaces and worker threads. Value is per CPU socket.
+       ## Default is 16384
+       # num-mbufs 128000
+
+       ## Change hugepages allocation per-socket, needed only if there is need for
+       ## larger number of mbufs. Default is 256M on each detected CPU socket
+       # socket-mem 2048,2048
+# }
+
+EOF
+
+cat > /etc/vpp/setup.gate << EOF
+set int state GigabitEthernet0/8/0 up
+set interface ip address GigabitEthernet0/8/0 10.4.0.4/24
+
+set int state GigabitEthernet0/9/0 up
+set interface ip address GigabitEthernet0/9/0 10.4.0.3/24
+
+set vbng dhcp4 remote 10.4.0.1 local 10.4.0.3
+set vbng aaa config /etc/vpp/vbng-aaa.cfg nas-port 5060
+EOF
+
+cat > /etc/vpp/vbng-aaa.cfg << EOF
+# General settings
+
+# specify which authentication comes first respectively which
+# authentication is used. possible values are: "radius" and "local".
+# if you specify "radius,local" then the RADIUS server is asked
+# first then the local one. if only one keyword is specified only
+# this server is asked.
+auth_order     radius,local
+
+# maximum login tries a user has
+login_tries    2
+
+# timeout for all login tries
+# if this time is exceeded the user is kicked out
+login_timeout  5
+
+# name of the nologin file which when it exists disables logins.
+# it may be extended by the ttyname which will result in
+# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
+# logins on /dev/ttyS2)
+nologin /etc/nologin
+
+# name of the issue file. it's only display when no username is passed
+# on the radlogin command line
+issue  /usr/local/etc/radiusclient/issue
+
+# RADIUS settings
+
+# RADIUS server to use for authentication requests. this config
+# item can appear more then one time. if multiple servers are
+# defined they are tried in a round robin fashion if one
+# server is not answering.
+# optionally you can specify a the port number on which is remote
+# RADIUS listens separated by a colon from the hostname. if
+# no port is specified /etc/services is consulted of the radius
+# service. if this fails also a compiled in default is used.
+#authserver    10.4.0.2
+authserver      localhost
+
+# RADIUS server to use for accouting requests. All that I
+# said for authserver applies, too. 
+#
+#acctserver    10.4.0.2
+acctserver     localhost
+
+# file holding shared secrets used for the communication
+# between the RADIUS client and server
+servers                /usr/local/etc/radiusclient/servers
+
+# dictionary of allowed attributes and values
+# just like in the normal RADIUS distributions
+dictionary     /usr/local/etc/radiusclient/dictionary
+
+# program to call for a RADIUS authenticated login
+login_radius   /usr/local/sbin/login.radius
+
+# file which holds sequence number for communication with the
+# RADIUS server
+seqfile                /var/run/radius.seq
+
+# file which specifies mapping between ttyname and NAS-Port attribute
+mapfile                /usr/local/etc/radiusclient/port-id-map
+
+# default authentication realm to append to all usernames if no
+# realm was explicitly specified by the user
+# the radiusd directly form Livingston doesnt use any realms, so leave
+# it blank then
+default_realm
+
+# time to wait for a reply from the RADIUS server
+radius_timeout 10
+
+# resend request this many times before trying the next server
+radius_retries 3
+
+# The length of time in seconds that we skip a nonresponsive RADIUS
+# server for transaction requests.  Server(s) being in the "dead" state
+# are tried only after all other non-dead servers have been tried and
+# failed or timeouted.  The deadtime interval starts when the server
+# does not respond to an authentication/accounting request transmissions. 
+# When the interval expires, the "dead" server would be re-tried again,
+# and if it's still down then it will be considered "dead" for another
+# such interval and so on. This option is no-op if there is only one
+# server in the list. Set to 0 in order to disable the feature.
+radius_deadtime        0
+
+# local address from which radius packets have to be sent
+bindaddr *
+
+# LOCAL settings
+
+# program to execute for local login
+# it must support the -f flag for preauthenticated login
+login_local    /bin/login
+EOF
+
+cat >> /usr/local/etc/radiusclient/dictionary << EOF
+
+#
+#      DHCP Proxy/Relay attributes
+#
+ATTRIBUTE      DHCP-Agent-Circuit-Id   82.1    integer
+ATTRIBUTE      DHCP-Agent-Remote-Id    82.2    string
+ATTRIBUTE      DHCP-Relay-Circuit-Id   82.1    integer
+ATTRIBUTE      DHCP-Relay-Remote-Id    82.2    string
+
+EOF
+
+cat >> /usr/local/etc/radiusclient/servers << EOF
+10.4.0.2                                       testing123
+localhost/localhost                            testing123
+
+EOF
+
 # Download DHCP config files
 cd /opt
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_bng_init.sh
@@ -94,4 +366,4 @@ then
        reboot
 fi
 
-./v_bng_init.sh
\ No newline at end of file
+./v_bng_init.sh
index a9bf588..1bf8a50 100644 (file)
@@ -1 +1,6 @@
 #!/bin/bash
+
+systemctl start vpp
+systemctl start honeycomb
+
+/opt/set_nat.sh
index 10976da..c4626a4 100644 (file)
@@ -4,6 +4,11 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt)
 REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt)
 DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
+VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt)
+VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt)
+VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt)
+HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt)
+HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 
 # Convert Network CIDR to Netmask
@@ -38,11 +43,347 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
+# Install the tools required for download codes
+apt-get install -y expect git patch
+
+#Download and build the VPP codes
+cd /opt
+git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp
+wget -O VPP-Add-Option82-Nat-Filter-For-vBRG.patch ${VPP_PATCH_URL} 
+
+cd vpp
+patch -p1 < ../VPP-Add-Option82-Nat-Filter-For-vBRG.patch
+expect -c "
+        set timeout 60;
+        spawn make install-dep;
+        expect {
+                \"Do you want to continue?*\" {send \"Y\r\"; interact}
+        }
+"
+
+cd build-root
+./bootstrap.sh
+make V=0 PLATFORM=vpp TAG=vpp install-deb
+
+# Install the VPP package
+dpkg -i *.deb
+systemctl stop vpp
+
+# Auto-start configuration for the VPP
+cat > /etc/vpp/startup.conf << EOF
+
+unix {
+  nodaemon
+  log /tmp/vpp.log
+  full-coredump
+  cli-listen localhost:5002
+  startup-config /etc/vpp/setup.gate
+}
+
+api-trace {
+  on
+}
+
+api-segment {
+  gid vpp
+}
+
+cpu {
+       ## In the VPP there is one main thread and optionally the user can create worker(s)
+       ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+       ## Manual pinning of thread(s) to CPU core(s)
+
+       ## Set logical CPU core where main thread runs
+       # main-core 1
+
+       ## Set logical CPU core(s) where worker threads are running
+       # corelist-workers 2-3,18-19
+
+       ## Automatic pinning of thread(s) to CPU core(s)
+
+       ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+       ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+       ## The main thread is automatically pinned to the first available CPU core and worker(s)
+       ## are pinned to next free CPU core(s) after core assigned to main thread
+       # skip-cores 4
+
+       ## Specify a number of workers to be created
+       ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+       ## and main thread's CPU core
+       # workers 2
+
+       ## Set scheduling policy and priority of main and worker threads
+
+       ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+       ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+       # scheduler-policy fifo
+
+       ## Scheduling priority is used only for "real-time policies (fifo and rr),
+       ## and has to be in the range of priorities supported for a particular policy
+       # scheduler-priority 50
+}
+
+# dpdk {
+       ## Change default settings for all intefaces
+       # dev default {
+               ## Number of receive queues, enables RSS
+               ## Default is 1
+               # num-rx-queues 3
+
+               ## Number of transmit queues, Default is equal
+               ## to number of worker threads or 1 if no workers treads
+               # num-tx-queues 3
+
+               ## Number of descriptors in transmit and receive rings
+               ## increasing or reducing number can impact performance
+               ## Default is 1024 for both rx and tx
+               # num-rx-desc 512
+               # num-tx-desc 512
+
+               ## VLAN strip offload mode for interface
+               ## Default is off
+               # vlan-strip-offload on
+       # }
+
+       ## Whitelist specific interface by specifying PCI address
+       # dev 0000:02:00.0
+
+       ## Whitelist specific interface by specifying PCI address and in
+       ## addition specify custom parameters for this interface
+       # dev 0000:02:00.1 {
+       #       num-rx-queues 2
+       # }
+
+       ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci
+       ## and uio_pci_generic (default)
+       # uio-driver vfio-pci
+
+       ## Disable mutli-segment buffers, improves performance but
+       ## disables Jumbo MTU support
+       # no-multi-seg
+
+       ## Increase number of buffers allocated, needed only in scenarios with
+       ## large number of interfaces and worker threads. Value is per CPU socket.
+       ## Default is 16384
+       # num-mbufs 128000
+
+       ## Change hugepages allocation per-socket, needed only if there is need for
+       ## larger number of mbufs. Default is 256M on each detected CPU socket
+       # socket-mem 2048,2048
+# }
+
+EOF
+
+cat > /etc/vpp/setup.gate << EOF
+set int state GigabitEthernet0/8/0 up
+set dhcp client intfc GigabitEthernet0/8/0 hostname brg-emulator
+
+tap connect lstack
+set int state tap-0 up
+
+set interface l2 bridge tap-0 10 0
+set bridge-domain arp term 10
+EOF
+
+cat >> /opt/config/ip.txt << EOF
+hcip: 192.168.1.20
+EOF
+
+#set nat rule
+cat > /opt/set_nat.sh << EOF
+#! /bin/bash
+
+while :
+do
+        if [[ ! $(ps -aux | grep [[:alnum:]]*/vpp/startup.conf | wc -l) = 2 ]]; then
+                #echo "vpp not running"
+                continue
+        fi
+        flag=0
+        while read -r line
+        do
+                if [ flag = 0 ]; then
+                        re=${line#*/[0-9]/[0-9]}
+                        if [ "$line" != "$re" ]; then
+                                flag=1
+                        else
+                                flag=0
+                                continue
+                        fi
+                else
+                        ip=${line%/*}
+                        if [[ $ip = *\.*\.*\.* ]]; then
+                                #echo "ip address is $ip"
+                                if [ ! -f /opt/config/ip.txt ]; then
+                                        echo "file /opt/config/ip.txt doesn't exists"
+                                        continue
+                                fi
+                                while read -r tap_ip
+                                do
+                                        if [[ $tap_ip = hcip* ]]; then
+                                                tap_ip=${tap_ip#*" "}
+                                                echo "hc tap ip address is $tap_ip"
+                                                vppctl snat add static mapping local $tap_ip external $ip
+                                                exit 0
+                                        fi
+                                done < /opt/config/ip.txt
+                        else
+                                if [[ ! $ip = */[0-9] ]]; then
+                                        flag=0
+                                        #echo "not correct"
+                                fi
+                        fi
+                fi
+        done < <(vppctl show int addr)
+       sleep 1
+done
+EOF
+# Download and install HC2VPP from source
+cd /opt
+git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp
+
+apt-get install -y maven
+cat > ~/.m2/settings.xml << EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+
+  <profiles>
+    <profile>
+      <id>fd.io-release</id>
+      <repositories>
+        <repository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/groups/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/repositories/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+
+    <profile>
+      <id>fd.io-snapshots</id>
+      <repositories>
+        <repository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>opendaylight-snapshots</id>
+      <repositories>
+        <repository>
+          <id>opendaylight-snapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>opendaylight-shapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+
+  <activeProfiles>
+    <activeProfile>fd.io-release</activeProfile>
+    <activeProfile>fd.io-snapshots</activeProfile>
+    <activeProfile>opendaylight-snapshots</activeProfile>
+  </activeProfiles>
+</settings>
+EOF
+
+cd hc2vpp
+mvn clean install
+l_version=$(cat pom.xml | grep "<version>" | head -1)
+l_version=$(echo "${l_version%<*}")
+l_version=$(echo "${l_version#*>}")
+mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb
+sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json
+
+# Create systemctl service for Honeycomb
+cat > /etc/systemd/system/honeycomb.service << EOF
+[Unit]
+Description=Honeycomb Agent for the VPP control plane
+Documentation=https://wiki.fd.io/view/Honeycomb
+Requires=vpp.service
+After=vpp.service
+
+[Service]
+ExecStart=/opt/honeycomb/honeycomb
+Restart=always
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable /etc/systemd/system/honeycomb.service
+
 # Download DHCP config files
 cd /opt
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_brgemu_init.sh
@@ -64,4 +405,4 @@ then
        reboot
 fi
 
-./v_brgemu_init.sh
\ No newline at end of file
+./v_brgemu_init.sh
index d88ed50..f369704 100644 (file)
@@ -5,6 +5,7 @@ REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt)
 DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
+MR_IP_ADDR=$(cat /opt/config/mr_ip_addr.txt)
 
 # Convert Network CIDR to Netmask
 cdr2mask () {
@@ -48,12 +49,13 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev
 sleep 1
 
-#  download the kea hook
+# Download the kea hook
 cd /opt
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vcpe/kea-sdnc-notify-mod/$DEMO_ARTIFACTS_VERSION/kea-sdnc-notify-mod-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 tar -zxvf kea-sdnc-notify-mod-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
@@ -78,6 +80,7 @@ update-rc.d v_dhcp.sh defaults
 # Configure DHCP
 cp kea-dhcp4.conf /etc/kea-dhcp4-server.conf
 mv kea-dhcp4.conf /etc/kea/kea-dhcp4.conf
+sed -i "s/DMAAP_IPADDR/"$MR_IP_ADDR"/g" kea-sdnc-notify.conf
 mv kea-sdnc-notify.conf /etc/kea/kea-sdnc-notify.conf
 sleep 1
 
index a9bf588..dd85a92 100644 (file)
@@ -1 +1,4 @@
 #!/bin/bash
+
+service kea-dhcp4-server start
+service bind9 restart
\ No newline at end of file
index 02ab69b..feaa770 100644 (file)
@@ -48,20 +48,27 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev
 sleep 1
 
-# Download DHCP config files
+# Download DNS and DHCP config files
 cd /opt
+wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/kea-dhcp4_no_hook.conf
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_dns_init.sh
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_dns.sh
+mv kea-dhcp4_no_hook.conf /etc/kea/kea-dhcp4.conf
 chmod +x v_dns_init.sh
 chmod +x v_dns.sh
 mv v_dns.sh /etc/init.d
 update-rc.d v_dns.sh defaults
 
+# Install Bind
+mkdir /etc/bind/zones
+sed -i "s/OPTIONS=.*/OPTIONS=\"-4 -u bind\"/g" /etc/default/bind9
+
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
 then
index a9bf588..41730d3 100644 (file)
@@ -1 +1,6 @@
 #!/bin/bash
+
+systemctl start vpp
+systemctl start honeycomb
+systemctl start autosave
+
index b43cf7b..9ab8140 100644 (file)
@@ -4,6 +4,12 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt)
 REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt)
 DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
+VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt)
+VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt)
+VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt)
+HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt)
+HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt)
+HC2VPP_PATCH_URL=$(cat /opt/config/hc2vpp_patch_url.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 
 # Convert Network CIDR to Netmask
@@ -58,11 +64,474 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
+# Install the tools required for download codes
+apt-get install -y expect git patch make
+
+#Download and build the VPP codes
+cd /opt
+git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp
+wget -O Vpp-Add-VES-agent-for-vG-MUX.patch ${VPP_PATCH_URL} 
+
+cd vpp
+patch -p1 < ../Vpp-Add-VES-agent-for-vG-MUX.patch
+expect -c "
+        spawn make install-dep;
+        expect {
+                \"Do you want to continue?*\" {send \"Y\r\"; interact}
+        }
+"
+
+# Install the evel-library first since we need the lib
+cd /opt
+apt-get install -y libcurl4-openssl-dev
+git clone http://gerrit.onap.org/r/demo
+cd demo/vnfs/VES5.0/evel/evel-library/bldjobs 
+make
+cp ../libs/x86_64/libevel.so /usr/lib
+ldconfig
+
+cd /opt/vpp/build-root
+./bootstrap.sh
+make V=0 PLATFORM=vpp TAG=vpp install-deb
+
+# Install the VPP package
+apt install -y python-ply-lex-3.5 python-ply-yacc-3.5 python-pycparser python-cffi
+dpkg -i *.deb
+systemctl stop vpp
+
+# Auto-start configuration for the VPP
+cat > /etc/vpp/startup.conf << EOF
+
+unix {
+  nodaemon
+  log /tmp/vpp.log
+  full-coredump
+  cli-listen localhost:5002
+  startup-config /etc/vpp/setup.gate
+}
+
+api-trace {
+  on
+}
+
+api-segment {
+  gid vpp
+}
+
+cpu {
+       ## In the VPP there is one main thread and optionally the user can create worker(s)
+       ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+       ## Manual pinning of thread(s) to CPU core(s)
+
+       ## Set logical CPU core where main thread runs
+       # main-core 1
+
+       ## Set logical CPU core(s) where worker threads are running
+       # corelist-workers 2-3,18-19
+
+       ## Automatic pinning of thread(s) to CPU core(s)
+
+       ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+       ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+       ## The main thread is automatically pinned to the first available CPU core and worker(s)
+       ## are pinned to next free CPU core(s) after core assigned to main thread
+       # skip-cores 4
+
+       ## Specify a number of workers to be created
+       ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+       ## and main thread's CPU core
+       # workers 2
+
+       ## Set scheduling policy and priority of main and worker threads
+
+       ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+       ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+       # scheduler-policy fifo
+
+       ## Scheduling priority is used only for "real-time policies (fifo and rr),
+       ## and has to be in the range of priorities supported for a particular policy
+       # scheduler-priority 50
+}
+
+# dpdk {
+       ## Change default settings for all intefaces
+       # dev default {
+               ## Number of receive queues, enables RSS
+               ## Default is 1
+               # num-rx-queues 3
+
+               ## Number of transmit queues, Default is equal
+               ## to number of worker threads or 1 if no workers treads
+               # num-tx-queues 3
+
+               ## Number of descriptors in transmit and receive rings
+               ## increasing or reducing number can impact performance
+               ## Default is 1024 for both rx and tx
+               # num-rx-desc 512
+               # num-tx-desc 512
+
+               ## VLAN strip offload mode for interface
+               ## Default is off
+               # vlan-strip-offload on
+       # }
+
+       ## Whitelist specific interface by specifying PCI address
+       # dev 0000:02:00.0
+
+       ## Whitelist specific interface by specifying PCI address and in
+       ## addition specify custom parameters for this interface
+       # dev 0000:02:00.1 {
+       #       num-rx-queues 2
+       # }
+
+       ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci
+       ## and uio_pci_generic (default)
+       # uio-driver vfio-pci
+
+       ## Disable mutli-segment buffers, improves performance but
+       ## disables Jumbo MTU support
+       # no-multi-seg
+
+       ## Increase number of buffers allocated, needed only in scenarios with
+       ## large number of interfaces and worker threads. Value is per CPU socket.
+       ## Default is 16384
+       # num-mbufs 128000
+
+       ## Change hugepages allocation per-socket, needed only if there is need for
+       ## larger number of mbufs. Default is 256M on each detected CPU socket
+       # socket-mem 2048,2048
+# }
+
+EOF
+
+cat > /etc/vpp/setup.gate << EOF
+set int state GigabitEthernet0/8/0 up
+set int ip address GigabitEthernet0/8/0 10.1.0.20/24
+
+set int state GigabitEthernet0/9/0 up
+set int ip address GigabitEthernet0/9/0 10.5.0.20/24
+
+create vxlan tunnel src 10.5.0.20 dst 10.5.0.21 vni 100
+EOF
+
+# Download and install HC2VPP from source
+cd /opt
+git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp
+wget -O Hc2vpp-Add-VES-agent-for-vG-MUX.patch ${HC2VPP_PATCH_URL}
+
+apt-get install -y maven
+cat > ~/.m2/settings.xml << EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+
+  <profiles>
+    <profile>
+      <id>fd.io-release</id>
+      <repositories>
+        <repository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/groups/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/repositories/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+
+    <profile>
+      <id>fd.io-snapshots</id>
+      <repositories>
+        <repository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>opendaylight-snapshots</id>
+      <repositories>
+        <repository>
+          <id>opendaylight-snapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>opendaylight-shapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+
+  <activeProfiles>
+    <activeProfile>fd.io-release</activeProfile>
+    <activeProfile>fd.io-snapshots</activeProfile>
+    <activeProfile>opendaylight-snapshots</activeProfile>
+  </activeProfiles>
+</settings>
+EOF
+
+cd hc2vpp
+patch -p1 < ../Hc2vpp-Add-VES-agent-for-vG-MUX.patch
+mvn clean install
+l_version=$(cat pom.xml | grep "<version>" | head -1)
+l_version=$(echo "${l_version%<*}")
+l_version=$(echo "${l_version#*>}")
+mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb
+sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json
+
+# Create systemctl service for Honeycomb
+cat > /etc/systemd/system/honeycomb.service << EOF
+[Unit]
+Description=Honeycomb Agent for the VPP control plane
+Documentation=https://wiki.fd.io/view/Honeycomb
+Requires=vpp.service
+After=vpp.service
+
+[Service]
+ExecStart=/opt/honeycomb/honeycomb
+Restart=always
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable /etc/systemd/system/honeycomb.service
+
+#Create a systemd service for auto-save
+cat > /usr/bin/save_config << EOF
+#!/bin/bash
+
+#########################################################################
+#
+#  Copyright (c) 2017 Intel and/or its affiliates.
+# 
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+##########################################################################
+
+############################### Variables ################################
+VPP_SETUP_GATE=/etc/vpp/setup.gate
+
+############################### Functions ################################
+
+# Write the commands to the startup scripts.
+#
+# We could set VPP configuration to the startup.conf.
+# Write the configuration to the startup scripts so we could
+# restore the system after rebooting.
+#
+write_startup_scripts()
+{
+       local cmd=${2}
+       local is_add=${1}
+
+       if [[ ${is_add} == add ]] ;then
+               while read -r line
+               do
+                       if [[ ${line} == ${cmd} ]] ;then
+                               return 0
+                       fi
+               done < ${VPP_SETUP_GATE}
+
+               echo "${cmd}" >> ${VPP_SETUP_GATE}
+       else
+               while read -r line
+               do
+                       if [[ ${line} == ${cmd} ]] ;then
+                               sed -i "/${line}/d" ${VPP_SETUP_GATE}
+                               return 0
+                       fi
+               done < ${VPP_SETUP_GATE}
+       fi
+}
+
+# Saves the VES agent configuration to the startup script.
+#
+# Get the current VES agent configuration from the bash command:
+# $vppctl show ves agent
+#    Server Addr    Server Port Interval Enabled
+#    127.0.0.1        8080         10    True
+# Set the VES agent configuration with the bash command:
+# $vppctl set ves agent server 127.0.0.1 port 8080 intval 10
+#
+save_ves_config()
+{
+       local server=""
+       local port=""
+       local intval=""
+
+       local ves_config=`vppctl show ves agent | head -2 | tail -1`
+       if [ "${ves_config}" != "" ] ;then
+               server=`echo ${ves_config} | awk '{ print $1 }'`
+               port=`echo ${ves_config} | awk '{ print $2 }'`
+               intval=`echo ${ves_config} | awk '{ print $3 }'`
+               write_startup_scripts add "set ves agent server ${server} port ${port} intval ${intval}"
+       fi
+}
+
+# Save the VxLAN Tunnel Configuration to the startup script.
+#
+# Get the current VxLAN tunnel configuration with bash command:
+# $vppctl show vxlan tunnel
+#  [0] src 10.3.0.2 dst 10.1.0.20 vni 100 sw_if_index 1 encap_fib_index 0 fib_entry_index 7 decap_next l2
+#  [1] src 10.5.0.20 dst 10.5.0.21 vni 100 sw_if_index 2 encap_fib_index 0 fib_entry_index 8 decap_next l2
+# Set the VxLAN Tunnel with the bash command:
+# $vppctl create vxlan tunnel src 10.3.0.2 dst 10.1.0.20 vni 100
+# vxlan_tunnel0
+save_vxlan_tunnel()
+{
+       local src=""
+       local dst=""
+       local vni=""
+
+       vppctl show vxlan tunnel | while read line
+       do
+               if [ "${line}" != "" ] ;then
+                       src=`echo ${line} | awk '{ print $3 }'`
+                       dst=`echo ${line} | awk '{ print $5 }'`
+                       vni=`echo ${line} | awk '{ print $7 }'`
+
+                       write_startup_scripts add "create vxlan tunnel src ${src} dst ${dst} vni ${vni}"
+               fi
+       done
+}
+
+# Save the VxLAN tunnel L2 xconnect configuration to the startup script.
+#
+# Get the Current L2 Address configuration with bash command:
+# $vppctl show int addr
+# local0 (dn):
+# vxlan_tunnel0 (up):
+#   l2 xconnect vxlan_tunnel1
+# vxlan_tunnel1 (up):
+#   l2 xconnect vxlan_tunnel0
+# Save the VxLAN tunnel L2 xconnect configuration with bash command:
+# $vppctl set interface l2 xconnect vxlan_tunnel0 vxlan_tunnel1
+#
+save_vxlan_xconnect()
+{
+       local ingress=""
+       local egress=""
+
+       vppctl show int addr | while read line
+       do
+               if [[ ${line} == vxlan_tunnel* ]] ;then
+                       read next
+                       while [[ ${next} != l2* ]] || [[ ${next} == "" ]]
+                       do
+                               line=`echo ${next}`
+                               read next
+                       done
+                       if [[ ${next} == l2* ]] ;then
+                               ingress=`echo ${line} | awk '{ print $1 }'`
+                               egress=`echo ${next} | awk '{ print $3 }'`
+                               write_startup_scripts add "set interface l2 xconnect ${ingress} ${egress}"
+                       fi
+               fi
+       done
+}
+
+################################# MAIN ###################################
+
+save_ves_config
+
+save_vxlan_tunnel
+
+save_vxlan_xconnect
+
+EOF
+chmod a+x /usr/bin/save_config
+cat > /etc/systemd/system/autosave.service << EOF
+[Unit]
+Description=Run Scripts at Start and Stop
+Requires=vpp.service
+After=vpp.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+ExecStop=/usr/bin/save_config
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable /etc/systemd/system/autosave.service
+
 # Download DHCP config files
 cd /opt
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_gmux_init.sh
@@ -84,4 +553,4 @@ then
        reboot
 fi
 
-./v_gmux_init.sh
\ No newline at end of file
+./v_gmux_init.sh
index a9bf588..344374d 100644 (file)
@@ -1 +1,5 @@
 #!/bin/bash
+
+systemctl start vpp
+systemctl start honeycomb
+
index cafb204..3a12d7e 100644 (file)
@@ -4,6 +4,10 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt)
 REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt)
 DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
+VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt)
+VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt)
+HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt)
+HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 
 # Convert Network CIDR to Netmask
@@ -48,11 +52,314 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
+# Install the tools required for download codes
+apt-get install -y expect git
+
+#Download and build the VPP codes
+cd /opt
+git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp
+
+cd vpp
+expect -c "
+        set timeout 60;
+        spawn make install-dep;
+        expect {
+                \"Do you want to continue?*\" {send \"Y\r\"; interact}
+        }
+"
+
+cd build-root
+./bootstrap.sh
+make V=0 PLATFORM=vpp TAG=vpp install-deb
+
+# Install the VPP package
+dpkg -i *.deb
+systemctl stop vpp
+
+# Auto-start configuration for the VPP
+cat > /etc/vpp/startup.conf << EOF
+
+unix {
+  nodaemon
+  log /tmp/vpp.log
+  full-coredump
+  cli-listen localhost:5002
+  startup-config /etc/vpp/setup.gate
+}
+
+api-trace {
+  on
+}
+
+api-segment {
+  gid vpp
+}
+
+cpu {
+       ## In the VPP there is one main thread and optionally the user can create worker(s)
+       ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+       ## Manual pinning of thread(s) to CPU core(s)
+
+       ## Set logical CPU core where main thread runs
+       # main-core 1
+
+       ## Set logical CPU core(s) where worker threads are running
+       # corelist-workers 2-3,18-19
+
+       ## Automatic pinning of thread(s) to CPU core(s)
+
+       ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+       ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+       ## The main thread is automatically pinned to the first available CPU core and worker(s)
+       ## are pinned to next free CPU core(s) after core assigned to main thread
+       # skip-cores 4
+
+       ## Specify a number of workers to be created
+       ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+       ## and main thread's CPU core
+       # workers 2
+
+       ## Set scheduling policy and priority of main and worker threads
+
+       ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+       ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+       # scheduler-policy fifo
+
+       ## Scheduling priority is used only for "real-time policies (fifo and rr),
+       ## and has to be in the range of priorities supported for a particular policy
+       # scheduler-priority 50
+}
+
+# dpdk {
+       ## Change default settings for all intefaces
+       # dev default {
+               ## Number of receive queues, enables RSS
+               ## Default is 1
+               # num-rx-queues 3
+
+               ## Number of transmit queues, Default is equal
+               ## to number of worker threads or 1 if no workers treads
+               # num-tx-queues 3
+
+               ## Number of descriptors in transmit and receive rings
+               ## increasing or reducing number can impact performance
+               ## Default is 1024 for both rx and tx
+               # num-rx-desc 512
+               # num-tx-desc 512
+
+               ## VLAN strip offload mode for interface
+               ## Default is off
+               # vlan-strip-offload on
+       # }
+
+       ## Whitelist specific interface by specifying PCI address
+       # dev 0000:02:00.0
+
+       ## Whitelist specific interface by specifying PCI address and in
+       ## addition specify custom parameters for this interface
+       # dev 0000:02:00.1 {
+       #       num-rx-queues 2
+       # }
+
+       ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci
+       ## and uio_pci_generic (default)
+       # uio-driver vfio-pci
+
+       ## Disable mutli-segment buffers, improves performance but
+       ## disables Jumbo MTU support
+       # no-multi-seg
+
+       ## Increase number of buffers allocated, needed only in scenarios with
+       ## large number of interfaces and worker threads. Value is per CPU socket.
+       ## Default is 16384
+       # num-mbufs 128000
+
+       ## Change hugepages allocation per-socket, needed only if there is need for
+       ## larger number of mbufs. Default is 256M on each detected CPU socket
+       # socket-mem 2048,2048
+# }
+
+EOF
+
+cat > /etc/vpp/setup.gate << EOF
+set int state GigabitEthernet0/8/0 up
+set int ip address GigabitEthernet0/8/0 10.5.0.21/24
+
+set int state GigabitEthernet0/9/0 up
+set dhcp client intfc GigabitEthernet0/9/0 hostname vg-1
+
+tap connect lstack address 192.168.1.1/24
+set int state tap-0 up
+
+create vxlan tunnel src 10.5.0.21 dst 10.5.0.20 vni 100
+
+set interface l2 bridge tap-0 10 0
+set interface l2 bridge vxlan_tunnel0 10 1
+set bridge-domain arp term 10
+
+set int ip address vxlan_tunnel0 192.168.1.254/24
+set interface snat in vxlan_tunnel0 out GigabitEthernet0/9/0
+EOF
+
+# Download and install HC2VPP from source
+cd /opt
+git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp
+
+apt-get install -y maven
+cat > ~/.m2/settings.xml << EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+
+  <profiles>
+    <profile>
+      <id>fd.io-release</id>
+      <repositories>
+        <repository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/groups/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/repositories/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+
+    <profile>
+      <id>fd.io-snapshots</id>
+      <repositories>
+        <repository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>opendaylight-snapshots</id>
+      <repositories>
+        <repository>
+          <id>opendaylight-snapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>opendaylight-shapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+
+  <activeProfiles>
+    <activeProfile>fd.io-release</activeProfile>
+    <activeProfile>fd.io-snapshots</activeProfile>
+    <activeProfile>opendaylight-snapshots</activeProfile>
+  </activeProfiles>
+</settings>
+EOF
+
+cd hc2vpp
+mvn clean install
+l_version=$(cat pom.xml | grep "<version>" | head -1)
+l_version=$(echo "${l_version%<*}")
+l_version=$(echo "${l_version#*>}")
+mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb
+sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json
+
+# Create systemctl service for Honeycomb
+cat > /etc/systemd/system/honeycomb.service << EOF
+[Unit]
+Description=Honeycomb Agent for the VPP control plane
+Documentation=https://wiki.fd.io/view/Honeycomb
+Requires=vpp.service
+After=vpp.service
+
+[Service]
+ExecStart=/opt/honeycomb/honeycomb
+Restart=always
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable /etc/systemd/system/honeycomb.service
+
+# Install the DHCP server and config
+apt-get install -y isc-dhcp-server
+cat >> /etc/dhcp/dhcpd.conf << EOF
+subnet 192.168.1.0 netmask 255.255.255.0 {
+  range 192.168.1.2 192.168.1.253;
+  option subnet-mask 255.255.255.0;
+  option routers 192.168.1.254;
+  option broadcast-address 192.168.1.255;
+  default-lease-time 600;
+  max-lease-time 7200;
+}
+EOF
+
 # Download DHCP config files
 cd /opt
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_gw_init.sh
@@ -74,4 +381,4 @@ then
        reboot
 fi
 
-./v_gw_init.sh
\ No newline at end of file
+./v_gw_init.sh
index 94d3ebd..e207dd0 100644 (file)
@@ -48,9 +48,10 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev
 sleep 1
 
 # Download DHCP config files
@@ -62,6 +63,19 @@ chmod +x v_web.sh
 mv v_web.sh /etc/init.d
 update-rc.d v_web.sh defaults
 
+# Install Apache2 web server
+apt-get update
+apt install -y apache2
+mv /var/www/html/index.html /var/www/html/index.html.example
+cat > /var/www/html/index.html << EOF
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<center><h1>Welcome to the vCPE Use Case Web Server!</h1><center>
+</body>
+</html>
+EOF
+
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
 then
diff --git a/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch b/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch
new file mode 100755 (executable)
index 0000000..73b1915
--- /dev/null
@@ -0,0 +1,99 @@
+diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c
+index 5c12b47..f7c7caf 100644
+--- a/src/plugins/snat/out2in.c
++++ b/src/plugins/snat/out2in.c
+@@ -1,3 +1,4 @@
++
+ /*
+  * Copyright (c) 2016 Cisco and/or its affiliates.
+  * Licensed under the Apache License, Version 2.0 (the "License");
+@@ -658,6 +659,26 @@ snat_out2in_node_fn (vlib_main_t * vm,
+   n_left_from = frame->n_vectors;
+   next_index = node->cached_next_index;
++  //FOR BRG
++  ip4_address_t * sdnc_addr = malloc(4);
++  char line_input[128];
++  char * path = "/opt/config/ip.txt";
++  FILE * f = fopen(path, "r");
++  if (f == NULL)
++    printf("cannot open such file\n");
++
++  while (fgets(line_input, 128, f) != NULL){
++    if (!strcmp(strtok(line_input, " "),"sdnc_ip:")){
++      char * ip = strtok(NULL, " ");
++      char * num = strtok(ip, ".");
++      sdnc_addr->data[0] = atoi(num);
++      for (int i = 1; i < 4; i ++){
++        num = strtok(NULL, ".");
++        sdnc_addr->data[i] = atoi(num);
++      }
++    }
++  }
++
+   while (n_left_from > 0)
+     {
+       u32 n_left_to_next;
+@@ -733,6 +754,13 @@ snat_out2in_node_fn (vlib_main_t * vm,
+           proto0 = ip_proto_to_snat_proto (ip0->protocol);
++          //for BRG
++          if (PREDICT_TRUE (ip0->src_address.data_u32 != sdnc_addr->data_u32))
++            {
++              next0 = SNAT_OUT2IN_NEXT_LOOKUP;
++              goto trace0;
++            }
++
+           if (PREDICT_FALSE (proto0 == ~0))
+             {
+               snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0);
+@@ -871,6 +899,13 @@ snat_out2in_node_fn (vlib_main_t * vm,
+           proto1 = ip_proto_to_snat_proto (ip1->protocol);
++        //for BRG
++          if (PREDICT_TRUE (ip1->src_address.data_u32 != sdnc_addr->data_u32))
++            {
++              next1 = SNAT_OUT2IN_NEXT_LOOKUP;
++              goto trace1;
++            }
++
+           if (PREDICT_FALSE (proto1 == ~0))
+             {
+               snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1);
+@@ -1033,6 +1068,13 @@ snat_out2in_node_fn (vlib_main_t * vm,
+           proto0 = ip_proto_to_snat_proto (ip0->protocol);
++        //for BRG
++          if (PREDICT_TRUE (ip0->src_address.data_u32 != sdnc_addr->data_u32))
++            {
++              next0 = SNAT_OUT2IN_NEXT_LOOKUP;
++              goto trace00;
++            }
++
+           if (PREDICT_FALSE (proto0 == ~0))
+             {
+               snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0);
+diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c
+index 014f17a..296e1a7 100644
+--- a/src/vnet/dhcp/client.c
++++ b/src/vnet/dhcp/client.c
+@@ -427,6 +427,16 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
+   clib_memcpy (o->data, c->option_55_data, vec_len(c->option_55_data));
+   o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
++  /*send option 82*/
++  u8 sub2_len = vec_len(hw->hw_address);
++  o->option = 82;
++  o->length = sub2_len + 2;
++  u8 sub_option = 2;
++  clib_memcpy (o->data, &sub_option, 1);
++  clib_memcpy (o->data + 1,&sub2_len, 1);
++  clib_memcpy (o->data + 2, hw->hw_address, vec_len(hw->hw_address));
++  o = (dhcp_option_t *) (((uword) o) + (o->length +2));
++
+   /* End of list */
+   o->option = 0xff;
+   o->length = 0;
diff --git a/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch b/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch
new file mode 100644 (file)
index 0000000..4a9218b
--- /dev/null
@@ -0,0 +1,13239 @@
+From 0a97fd92483349178a6750ec4a232fea4f9864df Mon Sep 17 00:00:00 2001
+From: Johnson Li <johnson.li@intel.com>
+Date: Fri, 8 Sep 2017 17:09:58 +0800
+Subject: [PATCH] Integrate FreeRADIUS Client for vBNG
+
+Signed-off-by: Johnson Li <johnson.li@intel.com>
+
+diff --git a/src/configure.ac b/src/configure.ac
+index fb2ead6d..ef5537da 100644
+--- a/src/configure.ac
++++ b/src/configure.ac
+@@ -152,6 +152,7 @@ PLUGIN_ENABLED(ioam)
+ PLUGIN_ENABLED(ixge)
+ PLUGIN_ENABLED(lb)
+ PLUGIN_ENABLED(memif)
++PLUGIN_ENABLED(vbng)
+ PLUGIN_ENABLED(sixrd)
+ PLUGIN_ENABLED(snat)
+diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
+index 623892e7..d6f607fc 100644
+--- a/src/plugins/Makefile.am
++++ b/src/plugins/Makefile.am
+@@ -61,6 +61,10 @@ if ENABLE_MEMIF_PLUGIN
+ include memif.am
+ endif
++if ENABLE_VBNG_PLUGIN
++include vbng.am
++endif
++
+ if ENABLE_SIXRD_PLUGIN
+ include sixrd.am
+ endif
+diff --git a/src/plugins/vbng.am b/src/plugins/vbng.am
+new file mode 100644
+index 00000000..99398f49
+--- /dev/null
++++ b/src/plugins/vbng.am
+@@ -0,0 +1,32 @@
++# Copyright (c) 2017 Intel and/or its affiliates.
++# Licensed under the Apache License, Version 2.0 (the "License");
++# you may not use this file except in compliance with the License.
++# You may obtain a copy of the License at:
++#
++#     http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++
++vppplugins_LTLIBRARIES += vbng_plugin.la
++
++vbng_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lfreeradiusclient
++
++vbng_plugin_la_SOURCES = vbng/vbng_dhcp4_node.c       \
++                       vbng/vbng_dhcp4.c      \
++                       vbng/vbng_api.c        \
++                       vbng/vbng_aaa.c
++
++BUILT_SOURCES += vbng/vbng.api.h              \
++               vbng/vbng.api.json
++
++API_FILES += vbng/vbng.api
++
++nobase_apiinclude_HEADERS += vbng/vbng_all_api_h.h    \
++                           vbng/vbng_msg_enum.h       \
++                           vbng/vbng.api.h
++
++# vi:syntax=automake
+diff --git a/src/plugins/vbng/etc/dictionary b/src/plugins/vbng/etc/dictionary
+new file mode 100644
+index 00000000..45f4189c
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary
+@@ -0,0 +1,274 @@
++#
++# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
++#
++#     This file contains dictionary translations for parsing
++#     requests and generating responses.  All transactions are
++#     composed of Attribute/Value Pairs.  The value of each attribute
++#     is specified as one of 4 data types.  Valid data types are:
++#
++#     string - 0-253 octets
++#     ipaddr - 4 octets in network byte order
++#     integer - 32 bit value in big endian order (high byte first)
++#     date - 32 bit value in big endian order - seconds since
++#                                     00:00:00 GMT,  Jan.  1,  1970
++#
++#     Enumerated values are stored in the user file with dictionary
++#     VALUE translations for easy administration.
++#
++#     Example:
++#
++#     ATTRIBUTE         VALUE
++#     ---------------   -----
++#     Framed-Protocol = PPP
++#     7               = 1     (integer encoding)
++#
++
++#
++#     Following are the proper new names. Use these.
++#
++ATTRIBUTE     User-Name               1       string
++ATTRIBUTE     Password                2       string
++ATTRIBUTE     CHAP-Password           3       string
++ATTRIBUTE     NAS-IP-Address          4       ipaddr
++ATTRIBUTE     NAS-Port-Id             5       integer
++ATTRIBUTE     Service-Type            6       integer
++ATTRIBUTE     Framed-Protocol         7       integer
++ATTRIBUTE     Framed-IP-Address       8       ipaddr
++ATTRIBUTE     Framed-IP-Netmask       9       ipaddr
++ATTRIBUTE     Framed-Routing          10      integer
++ATTRIBUTE     Filter-Id               11      string
++ATTRIBUTE     Framed-MTU              12      integer
++ATTRIBUTE     Framed-Compression      13      integer
++ATTRIBUTE     Login-IP-Host           14      ipaddr
++ATTRIBUTE     Login-Service           15      integer
++ATTRIBUTE     Login-TCP-Port          16      integer
++ATTRIBUTE     Reply-Message           18      string
++ATTRIBUTE     Callback-Number         19      string
++ATTRIBUTE     Callback-Id             20      string
++ATTRIBUTE     Framed-Route            22      string
++ATTRIBUTE     Framed-IPX-Network      23      ipaddr
++ATTRIBUTE     State                   24      string
++ATTRIBUTE     Class                   25      string
++ATTRIBUTE     Vendor-Specific         26      string
++ATTRIBUTE     Session-Timeout         27      integer
++ATTRIBUTE     Idle-Timeout            28      integer
++ATTRIBUTE     Termination-Action      29      integer
++ATTRIBUTE     Called-Station-Id       30      string
++ATTRIBUTE     Calling-Station-Id      31      string
++ATTRIBUTE     NAS-Identifier          32      string
++ATTRIBUTE     Proxy-State             33      string
++ATTRIBUTE     Login-LAT-Service       34      string
++ATTRIBUTE     Login-LAT-Node          35      string
++ATTRIBUTE     Login-LAT-Group         36      string
++ATTRIBUTE     Framed-AppleTalk-Link   37      integer
++ATTRIBUTE     Framed-AppleTalk-Network        38      integer
++ATTRIBUTE     Framed-AppleTalk-Zone   39      string
++ATTRIBUTE     Acct-Status-Type        40      integer
++ATTRIBUTE     Acct-Delay-Time         41      integer
++ATTRIBUTE     Acct-Input-Octets       42      integer
++ATTRIBUTE     Acct-Output-Octets      43      integer
++ATTRIBUTE     Acct-Session-Id         44      string
++ATTRIBUTE     Acct-Authentic          45      integer
++ATTRIBUTE     Acct-Session-Time       46      integer
++ATTRIBUTE     Acct-Input-Packets      47      integer
++ATTRIBUTE     Acct-Output-Packets     48      integer
++ATTRIBUTE     Acct-Terminate-Cause    49      integer
++ATTRIBUTE     Acct-Multi-Session-Id   50      string
++ATTRIBUTE     Acct-Link-Count         51      integer
++ATTRIBUTE     Acct-Input-Gigawords    52      integer
++ATTRIBUTE     Acct-Output-Gigawords   53      integer
++ATTRIBUTE     Event-Timestamp         55      integer
++ATTRIBUTE     CHAP-Challenge          60      string
++ATTRIBUTE     NAS-Port-Type           61      integer
++ATTRIBUTE     Port-Limit              62      integer
++ATTRIBUTE     Login-LAT-Port          63      integer
++ATTRIBUTE     Connect-Info            77      string
++
++#
++#     RFC3162 IPv6 attributes
++#
++ATTRIBUTE     NAS-IPv6-Address        95      string
++ATTRIBUTE     Framed-Interface-Id     96      string
++ATTRIBUTE     Framed-IPv6-Prefix      97      ipv6prefix
++ATTRIBUTE     Login-IPv6-Host         98      string
++ATTRIBUTE     Framed-IPv6-Route       99      string
++ATTRIBUTE     Framed-IPv6-Pool        100     string
++
++#
++#     RFC6911 IPv6 attributes
++#
++ATTRIBUTE     Framed-IPv6-Address     168     ipv6addr
++ATTRIBUTE     DNS-Server-IPv6-Address 169     ipv6addr
++ATTRIBUTE     Route-IPv6-Information  170     ipv6prefix
++
++#
++#     Experimental Non Protocol Attributes used by Cistron-Radiusd
++#
++ATTRIBUTE     Huntgroup-Name          221     string
++ATTRIBUTE     User-Category           1029    string
++ATTRIBUTE     Group-Name              1030    string
++ATTRIBUTE     Simultaneous-Use        1034    integer
++ATTRIBUTE     Strip-User-Name         1035    integer
++ATTRIBUTE     Fall-Through            1036    integer
++ATTRIBUTE     Add-Port-To-IP-Address  1037    integer
++ATTRIBUTE     Exec-Program            1038    string
++ATTRIBUTE     Exec-Program-Wait       1039    string
++ATTRIBUTE     Hint                    1040    string
++
++#
++#     Non-Protocol Attributes
++#     These attributes are used internally by the server
++#
++ATTRIBUTE     Expiration                21    date
++ATTRIBUTE     Auth-Type               1000    integer
++ATTRIBUTE     Menu                    1001    string
++ATTRIBUTE     Termination-Menu        1002    string
++ATTRIBUTE     Prefix                  1003    string
++ATTRIBUTE     Suffix                  1004    string
++ATTRIBUTE     Group                   1005    string
++ATTRIBUTE     Crypt-Password          1006    string
++ATTRIBUTE     Connect-Rate            1007    integer
++
++#
++#     Integer Translations
++#
++
++#     User Types
++
++VALUE         Service-Type            Login-User              1
++VALUE         Service-Type            Framed-User             2
++VALUE         Service-Type            Callback-Login-User     3
++VALUE         Service-Type            Callback-Framed-User    4
++VALUE         Service-Type            Outbound-User           5
++VALUE         Service-Type            Administrative-User     6
++VALUE         Service-Type            NAS-Prompt-User         7
++VALUE         Service-Type            Authenticate-Only       8
++VALUE         Service-Type            Callback-NAS-Prompt     9
++VALUE         Service-Type            Call-Check              10
++VALUE         Service-Type            Callback-Administrative 11
++
++#     Framed Protocols
++
++VALUE         Framed-Protocol         PPP                     1
++VALUE         Framed-Protocol         SLIP                    2
++VALUE         Framed-Protocol         ARAP                    3
++VALUE         Framed-Protocol         GANDALF-SLMLP           4
++VALUE         Framed-Protocol         XYLOGICS-IPX-SLIP       5
++VALUE         Framed-Protocol         X75                     6
++
++#     Framed Routing Values
++
++VALUE         Framed-Routing          None                    0
++VALUE         Framed-Routing          Broadcast               1
++VALUE         Framed-Routing          Listen                  2
++VALUE         Framed-Routing          Broadcast-Listen        3
++
++#     Framed Compression Types
++
++VALUE         Framed-Compression      None                    0
++VALUE         Framed-Compression      Van-Jacobson-TCP-IP     1
++VALUE         Framed-Compression      IPX-Header              2
++VALUE         Framed-Compression      Stac-LZS                3
++
++#     Login Services
++
++VALUE         Login-Service           Telnet                  0
++VALUE         Login-Service           Rlogin                  1
++VALUE         Login-Service           TCP-Clear               2
++VALUE         Login-Service           PortMaster              3
++VALUE         Login-Service           LAT                     4
++VALUE         Login-Service           X.25-PAD                5
++VALUE         Login-Service           X.25-T3POS              6
++VALUE         Login-Service           TCP-Clear-Quiet         8
++
++#     Status Types
++
++VALUE         Acct-Status-Type        Start                   1
++VALUE         Acct-Status-Type        Stop                    2
++VALUE         Acct-Status-Type        Alive                   3
++VALUE         Acct-Status-Type        Accounting-On           7
++VALUE         Acct-Status-Type        Accounting-Off          8
++
++#     Authentication Types
++
++VALUE         Acct-Authentic          RADIUS                  1
++VALUE         Acct-Authentic          Local                   2
++VALUE         Acct-Authentic          Remote                  3
++
++#     Termination Options
++
++VALUE         Termination-Action      Default                 0
++VALUE         Termination-Action      RADIUS-Request          1
++
++#     NAS Port Types, available in 3.3.1 and later
++
++VALUE         NAS-Port-Type           Async                   0
++VALUE         NAS-Port-Type           Sync                    1
++VALUE         NAS-Port-Type           ISDN                    2
++VALUE         NAS-Port-Type           ISDN-V120               3
++VALUE         NAS-Port-Type           ISDN-V110               4
++VALUE         NAS-Port-Type           Virtual                 5
++VALUE         NAS-Port-Type           PIAFS                   6
++VALUE         NAS-Port-Type           HDLC-Clear-Channel      7
++VALUE         NAS-Port-Type           X.25                    8
++VALUE         NAS-Port-Type           X.75                    9
++VALUE         NAS-Port-Type           G.3-Fax                 10
++VALUE         NAS-Port-Type           SDSL                    11
++VALUE         NAS-Port-Type           ADSL-CAP                12
++VALUE         NAS-Port-Type           ADSL-DMT                13
++VALUE         NAS-Port-Type           IDSL                    14
++VALUE         NAS-Port-Type           Ethernet                15
++
++#     Acct Terminate Causes, available in 3.3.2 and later
++
++VALUE           Acct-Terminate-Cause    User-Request            1
++VALUE           Acct-Terminate-Cause    Lost-Carrier            2
++VALUE           Acct-Terminate-Cause    Lost-Service            3
++VALUE           Acct-Terminate-Cause    Idle-Timeout            4
++VALUE           Acct-Terminate-Cause    Session-Timeout         5
++VALUE           Acct-Terminate-Cause    Admin-Reset             6
++VALUE           Acct-Terminate-Cause    Admin-Reboot            7
++VALUE           Acct-Terminate-Cause    Port-Error              8
++VALUE           Acct-Terminate-Cause    NAS-Error               9
++VALUE           Acct-Terminate-Cause    NAS-Request             10
++VALUE           Acct-Terminate-Cause    NAS-Reboot              11
++VALUE           Acct-Terminate-Cause    Port-Unneeded           12
++VALUE           Acct-Terminate-Cause    Port-Preempted          13
++VALUE           Acct-Terminate-Cause    Port-Suspended          14
++VALUE           Acct-Terminate-Cause    Service-Unavailable     15
++VALUE           Acct-Terminate-Cause    Callback                16
++VALUE           Acct-Terminate-Cause    User-Error              17
++VALUE           Acct-Terminate-Cause    Host-Request            18
++
++#
++#     Non-Protocol Integer Translations
++#
++
++VALUE         Auth-Type               Local                   0
++VALUE         Auth-Type               System                  1
++VALUE         Auth-Type               SecurID                 2
++VALUE         Auth-Type               Crypt-Local             3
++VALUE         Auth-Type               Reject                  4
++
++#
++#     Cistron extensions
++#
++VALUE         Auth-Type               Pam                     253
++VALUE         Auth-Type               Accept                  254
++
++#
++#     Experimental Non-Protocol Integer Translations for Cistron-Radiusd
++#
++VALUE         Fall-Through            No                      0
++VALUE         Fall-Through            Yes                     1
++VALUE         Add-Port-To-IP-Address  No                      0
++VALUE         Add-Port-To-IP-Address  Yes                     1
++
++#
++#     Configuration Values
++#     uncomment these two lines to turn account expiration on
++#
++
++#VALUE                Server-Config           Password-Expiration     30
++#VALUE                Server-Config           Password-Warning        5
++
+diff --git a/src/plugins/vbng/etc/dictionary.ascend b/src/plugins/vbng/etc/dictionary.ascend
+new file mode 100644
+index 00000000..a02c207d
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary.ascend
+@@ -0,0 +1,297 @@
++#
++# Ascend dictionary.
++#
++#             Enable by putting the line "$INCLUDE dictionary.ascend" into
++#             the main dictionary file.
++#
++# Version:    1.00  21-Jul-1997  Jens Glaser <jens@regio.net>
++#
++
++
++#
++#     Ascend specific extensions
++#     Used by ASCEND MAX/Pipeline products
++#
++ATTRIBUTE     Ascend-FCP-Parameter            119     string
++ATTRIBUTE     Ascend-Modem-PortNo             120     integer
++ATTRIBUTE     Ascend-Modem-SlotNo             121     integer
++ATTRIBUTE     Ascend-Modem-ShelfNo            122     integer
++ATTRIBUTE     Ascend-Call-Attempt-Limit       123     integer
++ATTRIBUTE     Ascend-Call-Block-Duration      124     integer
++ATTRIBUTE     Ascend-Maximum-Call-Duration    125     integer
++ATTRIBUTE     Ascend-Temporary-Rtes           126     integer
++ATTRIBUTE       Tunneling-Protocol              127     integer
++ATTRIBUTE       Ascend-Shared-Profile-Enable    128     integer
++ATTRIBUTE     Ascend-Primary-Home-Agent       129     string
++ATTRIBUTE     Ascend-Secondary-Home-Agent     130     string
++ATTRIBUTE     Ascend-Dialout-Allowed          131     integer
++ATTRIBUTE     Ascend-Client-Gateway           132     ipaddr
++ATTRIBUTE     Ascend-BACP-Enable              133     integer
++ATTRIBUTE     Ascend-DHCP-Maximum-Leases      134     integer
++ATTRIBUTE     Ascend-Client-Primary-DNS       135     ipaddr
++ATTRIBUTE     Ascend-Client-Secondary-DNS     136     ipaddr
++ATTRIBUTE     Ascend-Client-Assign-DNS        137     integer
++ATTRIBUTE     Ascend-User-Acct-Type           138     integer
++ATTRIBUTE     Ascend-User-Acct-Host           139     ipaddr
++ATTRIBUTE     Ascend-User-Acct-Port           140     integer
++ATTRIBUTE     Ascend-User-Acct-Key            141     string
++ATTRIBUTE     Ascend-User-Acct-Base           142     integer
++ATTRIBUTE     Ascend-User-Acct-Time           143     integer
++ATTRIBUTE     Ascend-Assign-IP-Client         144     ipaddr
++ATTRIBUTE     Ascend-Assign-IP-Server         145     ipaddr
++ATTRIBUTE     Ascend-Assign-IP-Global-Pool    146     string
++ATTRIBUTE     Ascend-DHCP-Reply               147     integer
++ATTRIBUTE     Ascend-DHCP-Pool-Number         148     integer
++ATTRIBUTE     Ascend-Expect-Callback          149     integer
++ATTRIBUTE     Ascend-Event-Type               150     integer
++ATTRIBUTE     Ascend-Session-Svr-Key          151     string
++ATTRIBUTE     Ascend-Multicast-Rate-Limit     152     integer
++ATTRIBUTE     Ascend-IF-Netmask               153     ipaddr
++ATTRIBUTE     Ascend-Remote-Addr              154     ipaddr
++ATTRIBUTE     Ascend-Multicast-Client         155     integer
++ATTRIBUTE     Ascend-FR-Circuit-Name          156     string
++ATTRIBUTE     Ascend-FR-LinkUp                157     integer
++ATTRIBUTE     Ascend-FR-Nailed-Grp            158     integer
++ATTRIBUTE     Ascend-FR-Type                  159     integer
++ATTRIBUTE     Ascend-FR-Link-Mgt              160     integer
++ATTRIBUTE     Ascend-FR-N391                  161     integer
++ATTRIBUTE     Ascend-FR-DCE-N392              162     integer
++ATTRIBUTE     Ascend-FR-DTE-N392              163     integer
++ATTRIBUTE     Ascend-FR-DCE-N393              164     integer
++ATTRIBUTE     Ascend-FR-DTE-N393              165     integer
++ATTRIBUTE     Ascend-FR-T391                  166     integer
++ATTRIBUTE     Ascend-FR-T392                  167     integer
++ATTRIBUTE     Ascend-Bridge-Address           168     string
++ATTRIBUTE       Ascend-TS-Idle-Limit            169     integer
++ATTRIBUTE       Ascend-TS-Idle-Mode             170     integer
++ATTRIBUTE     Ascend-DBA-Monitor              171     integer
++ATTRIBUTE     Ascend-Base-Channel-Count       172     integer
++ATTRIBUTE     Ascend-Minimum-Channels         173     integer
++ATTRIBUTE     Ascend-IPX-Route                174     string
++ATTRIBUTE     Ascend-FT1-Caller               175     integer
++ATTRIBUTE     Ascend-Backup                   176     string
++ATTRIBUTE     Ascend-Call-Type                177     integer
++ATTRIBUTE     Ascend-Group                    178     string
++ATTRIBUTE     Ascend-FR-DLCI                  179     integer
++ATTRIBUTE     Ascend-FR-Profile-Name          180     string
++ATTRIBUTE     Ascend-Ara-PW                   181     string
++ATTRIBUTE     Ascend-IPX-Node-Addr            182     string
++ATTRIBUTE     Ascend-Home-Agent-IP-Addr       183     ipaddr
++ATTRIBUTE     Ascend-Home-Agent-Password      184     string
++ATTRIBUTE     Ascend-Home-Network-Name        185     string
++ATTRIBUTE     Ascend-Home-Agent-UDP-Port      186     integer
++ATTRIBUTE     Ascend-Multilink-ID             187     integer
++ATTRIBUTE     Ascend-Num-In-Multilink         188     integer
++ATTRIBUTE     Ascend-First-Dest               189     ipaddr
++ATTRIBUTE     Ascend-Pre-Input-Octets         190     integer
++ATTRIBUTE     Ascend-Pre-Output-Octets        191     integer
++ATTRIBUTE     Ascend-Pre-Input-Packets        192     integer
++ATTRIBUTE     Ascend-Pre-Output-Packets       193     integer
++ATTRIBUTE     Ascend-Maximum-Time             194     integer
++ATTRIBUTE     Ascend-Disconnect-Cause         195     integer
++ATTRIBUTE     Ascend-Connect-Progress         196     integer
++ATTRIBUTE     Ascend-Data-Rate                197     integer
++ATTRIBUTE     Ascend-PreSession-Time          198     integer
++ATTRIBUTE     Ascend-Token-Idle               199     integer
++ATTRIBUTE     Ascend-Token-Immediate          200     integer
++ATTRIBUTE     Ascend-Require-Auth             201     integer
++ATTRIBUTE     Ascend-Number-Sessions          202     string
++ATTRIBUTE     Ascend-Authen-Alias             203     string
++ATTRIBUTE     Ascend-Token-Expiry             204     integer
++ATTRIBUTE     Ascend-Menu-Selector            205     string
++ATTRIBUTE     Ascend-Menu-Item                206     string
++ATTRIBUTE     Ascend-PW-Warntime              207     integer
++ATTRIBUTE     Ascend-PW-Lifetime              208     integer
++ATTRIBUTE     Ascend-IP-Direct                209     ipaddr
++ATTRIBUTE     Ascend-PPP-VJ-Slot-Comp         210     integer
++ATTRIBUTE     Ascend-PPP-VJ-1172              211     integer
++ATTRIBUTE     Ascend-PPP-Async-Map            212     integer
++ATTRIBUTE     Ascend-Third-Prompt             213     string
++ATTRIBUTE     Ascend-Send-Secret              214     string
++ATTRIBUTE     Ascend-Receive-Secret           215     string
++ATTRIBUTE     Ascend-IPX-Peer-Mode            216     integer
++ATTRIBUTE     Ascend-IP-Pool-Definition       217     string
++ATTRIBUTE     Ascend-Assign-IP-Pool           218     integer
++ATTRIBUTE     Ascend-FR-Direct                219     integer
++ATTRIBUTE     Ascend-FR-Direct-Profile        220     string
++ATTRIBUTE     Ascend-FR-Direct-DLCI           221     integer
++ATTRIBUTE     Ascend-Handle-IPX               222     integer
++ATTRIBUTE     Ascend-Netware-timeout          223     integer
++ATTRIBUTE     Ascend-IPX-Alias                224     integer
++ATTRIBUTE     Ascend-Metric                   225     integer
++ATTRIBUTE     Ascend-PRI-Number-Type          226     integer
++ATTRIBUTE     Ascend-Dial-Number              227     string
++ATTRIBUTE     Ascend-Route-IP                 228     integer
++ATTRIBUTE     Ascend-Route-IPX                229     integer
++ATTRIBUTE     Ascend-Bridge                   230     integer
++ATTRIBUTE     Ascend-Send-Auth                231     integer
++ATTRIBUTE     Ascend-Send-Passwd              232     string
++ATTRIBUTE     Ascend-Link-Compression         233     integer
++ATTRIBUTE     Ascend-Target-Util              234     integer
++ATTRIBUTE     Ascend-Maximum-Channels         235     integer
++ATTRIBUTE     Ascend-Inc-Channel-Count        236     integer
++ATTRIBUTE     Ascend-Dec-Channel-Count        237     integer
++ATTRIBUTE     Ascend-Seconds-Of-History       238     integer
++ATTRIBUTE     Ascend-History-Weigh-Type       239     integer
++ATTRIBUTE     Ascend-Add-Seconds              240     integer
++ATTRIBUTE     Ascend-Remove-Seconds           241     integer
++ATTRIBUTE     Ascend-Idle-Limit               244     integer
++ATTRIBUTE     Ascend-Preempt-Limit            245     integer
++ATTRIBUTE     Ascend-Callback                 246     integer
++ATTRIBUTE     Ascend-Data-Svc                 247     integer
++ATTRIBUTE     Ascend-Force-56                 248     integer
++ATTRIBUTE     Ascend-Billing-Number           249     string
++ATTRIBUTE     Ascend-Call-By-Call             250     integer
++ATTRIBUTE     Ascend-Transit-Number           251     string
++ATTRIBUTE     Ascend-Host-Info                252     string
++ATTRIBUTE     Ascend-PPP-Address              253     ipaddr
++ATTRIBUTE     Ascend-MPP-Idle-Percent         254     integer
++ATTRIBUTE     Ascend-Xmit-Rate                255     integer
++
++
++
++# Ascend protocols
++VALUE         Service-Type            Dialout-Framed-User     5
++VALUE         Framed-Protocol         ARA                     255
++VALUE         Framed-Protocol         MPP                     256
++VALUE         Framed-Protocol         EURAW                   257
++VALUE         Framed-Protocol         EUUI                    258
++VALUE         Framed-Protocol         X25                     259
++VALUE         Framed-Protocol         COMB                    260
++VALUE         Framed-Protocol         FR                      261
++VALUE         Framed-Protocol         MP                      262
++VALUE         Framed-Protocol         FR-CIR                  263
++
++
++#
++#     Ascend specific extensions
++#     Used by ASCEND MAX/Pipeline products (see above)
++#
++
++VALUE         Ascend-FR-Direct        FR-Direct-No            0
++VALUE         Ascend-FR-Direct        FR-Direct-Yes           1
++VALUE         Ascend-Handle-IPX       Handle-IPX-None         0
++VALUE         Ascend-Handle-IPX       Handle-IPX-Client       1
++VALUE         Ascend-Handle-IPX       Handle-IPX-Server       2
++VALUE         Ascend-IPX-Peer-Mode    IPX-Peer-Router         0
++VALUE         Ascend-IPX-Peer-Mode    IPX-Peer-Dialin         1
++VALUE         Ascend-Call-Type        Nailed                  1
++VALUE         Ascend-Call-Type        Nailed/Mpp              2
++VALUE         Ascend-Call-Type        Perm/Switched           3
++VALUE         Ascend-FT1-Caller       FT1-No                  0
++VALUE         Ascend-FT1-Caller       FT1-Yes                 1
++VALUE         Ascend-PRI-Number-Type  Unknown-Number          0
++VALUE         Ascend-PRI-Number-Type  Intl-Number             1
++VALUE         Ascend-PRI-Number-Type  National-Number         2
++VALUE         Ascend-PRI-Number-Type  Local-Number            4
++VALUE         Ascend-PRI-Number-Type  Abbrev-Number           5
++VALUE         Ascend-Route-IPX        Route-IPX-No            0
++VALUE         Ascend-Route-IPX        Route-IPX-Yes           1
++VALUE         Ascend-Bridge           Bridge-No               0
++VALUE         Ascend-Bridge           Bridge-Yes              1
++VALUE                 Ascend-TS-Idle-Mode     TS-Idle-None            0
++VALUE         Ascend-TS-Idle-Mode     TS-Idle-Input           1
++VALUE                 Ascend-TS-Idle-Mode     TS-Idle-Input-Output    2
++VALUE         Ascend-Send-Auth        Send-Auth-None          0
++VALUE         Ascend-Send-Auth        Send-Auth-PAP           1
++VALUE         Ascend-Send-Auth        Send-Auth-CHAP          2
++VALUE         Ascend-Send-Auth        Send-Auth-MS-CHAP       3
++VALUE         Ascend-Link-Compression Link-Comp-None          0
++VALUE         Ascend-Link-Compression Link-Comp-Stac          1
++VALUE         Ascend-Link-Compression Link-Comp-Stac-Draft-9  2
++VALUE         Ascend-Link-Compression Link-Comp-MS-Stac       3
++VALUE         Ascend-History-Weigh-Type       History-Constant        0
++VALUE         Ascend-History-Weigh-Type       History-Linear          1
++VALUE         Ascend-History-Weigh-Type       History-Quadratic       2
++VALUE         Ascend-Callback         Callback-No             0
++VALUE         Ascend-Callback         Callback-Yes            1
++VALUE         Ascend-Expect-Callback  Expect-Callback-No      0
++VALUE         Ascend-Expect-Callback  Expect-Callback-Yes     1
++VALUE         Ascend-Data-Svc         Switched-Voice-Bearer   0
++VALUE         Ascend-Data-Svc         Switched-56KR           1
++VALUE         Ascend-Data-Svc         Switched-64K            2
++VALUE         Ascend-Data-Svc         Switched-64KR           3
++VALUE         Ascend-Data-Svc         Switched-56K            4
++VALUE         Ascend-Data-Svc         Switched-384KR          5
++VALUE         Ascend-Data-Svc         Switched-384K           6
++VALUE         Ascend-Data-Svc         Switched-1536K          7
++VALUE         Ascend-Data-Svc         Switched-1536KR         8
++VALUE         Ascend-Data-Svc         Switched-128K           9
++VALUE         Ascend-Data-Svc         Switched-192K           10
++VALUE         Ascend-Data-Svc         Switched-256K           11
++VALUE         Ascend-Data-Svc         Switched-320K           12
++VALUE         Ascend-Data-Svc         Switched-384K-MR        13
++VALUE         Ascend-Data-Svc         Switched-448K           14
++VALUE         Ascend-Data-Svc         Switched-512K           15
++VALUE         Ascend-Data-Svc         Switched-576K           16
++VALUE         Ascend-Data-Svc         Switched-640K           17
++VALUE         Ascend-Data-Svc         Switched-704K           18
++VALUE         Ascend-Data-Svc         Switched-768K           19
++VALUE         Ascend-Data-Svc         Switched-832K           20
++VALUE         Ascend-Data-Svc         Switched-896K           21
++VALUE         Ascend-Data-Svc         Switched-960K           22
++VALUE         Ascend-Data-Svc         Switched-1024K          23
++VALUE         Ascend-Data-Svc         Switched-1088K          24
++VALUE         Ascend-Data-Svc         Switched-1152K          25
++VALUE         Ascend-Data-Svc         Switched-1216K          26
++VALUE         Ascend-Data-Svc         Switched-1280K          27
++VALUE         Ascend-Data-Svc         Switched-1344K          28
++VALUE         Ascend-Data-Svc         Switched-1408K          29
++VALUE         Ascend-Data-Svc         Switched-1472K          30
++VALUE         Ascend-Data-Svc         Switched-1600K          31
++VALUE         Ascend-Data-Svc         Switched-1664K          32
++VALUE         Ascend-Data-Svc         Switched-1728K          33
++VALUE         Ascend-Data-Svc         Switched-1792K          34
++VALUE         Ascend-Data-Svc         Switched-1856K          35
++VALUE         Ascend-Data-Svc         Switched-1920K          36
++VALUE         Ascend-Data-Svc         Switched-inherited              37
++VALUE         Ascend-Data-Svc         Switched-restricted-bearer-x30  38
++VALUE         Ascend-Data-Svc         Switched-clear-bearer-v110      39
++VALUE         Ascend-Data-Svc         Switched-restricted-64-x30      40
++VALUE         Ascend-Data-Svc         Switched-clear-56-v110          41
++VALUE         Ascend-Data-Svc         Switched-modem                  42
++VALUE         Ascend-Data-Svc         Switched-atmodem                43
++VALUE         Ascend-Data-Svc         Nailed-56KR             1
++VALUE         Ascend-Data-Svc         Nailed-64K              2
++VALUE         Ascend-Force-56         Force-56-No             0
++VALUE         Ascend-Force-56         Force-56-Yes            1
++VALUE         Ascend-PW-Lifetime      Lifetime-In-Days        0
++VALUE         Ascend-PW-Warntime      Days-Of-Warning         0
++VALUE         Ascend-PPP-VJ-1172      PPP-VJ-1172             1
++VALUE         Ascend-PPP-VJ-Slot-Comp VJ-Slot-Comp-No         1
++VALUE         Ascend-Require-Auth     Not-Require-Auth        0
++VALUE         Ascend-Require-Auth     Require-Auth            1
++VALUE         Ascend-Token-Immediate  Tok-Imm-No              0
++VALUE         Ascend-Token-Immediate  Tok-Imm-Yes             1
++VALUE         Ascend-DBA-Monitor              DBA-Transmit            0
++VALUE                 Ascend-DBA-Monitor      DBA-Transmit-Recv       1
++VALUE         Ascend-DBA-Monitor      DBA-None                2
++VALUE         Ascend-FR-Type          Ascend-FR-DTE           0
++VALUE         Ascend-FR-Type          Ascend-FR-DCE           1
++VALUE         Ascend-FR-Type          Ascend-FR-NNI           2
++VALUE         Ascend-FR-Link-Mgt      Ascend-FR-No-Link-Mgt   0
++VALUE         Ascend-FR-Link-Mgt      Ascend-FR-T1-617D       1
++VALUE         Ascend-FR-Link-Mgt      Ascend-FR-Q-933A        2
++VALUE         Ascend-FR-LinkUp        Ascend-LinkUp-Default   0
++VALUE         Ascend-FR-LinkUp        Ascend-LinkUp-AlwaysUp  1
++VALUE         Ascend-Multicast-Client Multicast-No            0
++VALUE         Ascend-Multicast-Client Multicast-Yes           1
++VALUE         Ascend-User-Acct-Type   Ascend-User-Acct-None   0
++VALUE         Ascend-User-Acct-Type   Ascend-User-Acct-User   1
++VALUE         Ascend-User-Acct-Type   Ascend-User-Acct-User-Default   2
++VALUE         Ascend-User-Acct-Base   Base-10                 0
++VALUE         Ascend-User-Acct-Base   Base-16                 1
++VALUE         Ascend-DHCP-Reply       DHCP-Reply-No           0
++VALUE         Ascend-DHCP-Reply       DHCP-Reply-Yes          1
++VALUE         Ascend-Client-Assign-DNS        DNS-Assign-No           0
++VALUE         Ascend-Client-Assign-DNS        DNS-Assign-Yes          1
++VALUE         Ascend-Event-Type       Ascend-ColdStart        1
++VALUE         Ascend-Event-Type       Ascend-Session-Event    2
++VALUE         Ascend-BACP-Enable      BACP-No                 0
++VALUE         Ascend-BACP-Enable      BACP-Yes                1
++VALUE         Ascend-Dialout-Allowed  Dialout-Not-Allowed     0
++VALUE         Ascend-Dialout-Allowed  Dialout-Allowed         1
++VALUE         Ascend-Shared-Profile-Enable    Shared-Profile-No       0
++VALUE         Ascend-Shared-Profile-Enable    Shared-Profile-Yes      1
++VALUE         Ascend-Temporary-Rtes   Temp-Rtes-No            0
++VALUE         Ascend-Temporary-Rtes   Temp-Rtes-Yes           1
+diff --git a/src/plugins/vbng/etc/dictionary.compat b/src/plugins/vbng/etc/dictionary.compat
+new file mode 100644
+index 00000000..4c85ea87
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary.compat
+@@ -0,0 +1,47 @@
++#
++#     Obsolete names for backwards compatibility with older users files.
++#     Move the $INCLUDE in the main dictionary file to the end if you want
++#     these names to be used in the "details" logfile.
++#
++ATTRIBUTE     Client-Id               4       ipaddr
++ATTRIBUTE     Client-Port-Id          5       integer
++ATTRIBUTE     User-Service-Type       6       integer
++ATTRIBUTE     Framed-Address          8       ipaddr
++ATTRIBUTE     Framed-Netmask          9       ipaddr
++ATTRIBUTE     Framed-Filter-Id        11      string
++ATTRIBUTE     Login-Host              14      ipaddr
++ATTRIBUTE     Login-Port              16      integer
++ATTRIBUTE     Old-Password            17      string
++ATTRIBUTE     Port-Message            18      string
++ATTRIBUTE     Dialback-No             19      string
++ATTRIBUTE     Dialback-Name           20      string
++ATTRIBUTE     Challenge-State         24      string
++VALUE         Framed-Compression      Van-Jacobsen-TCP-IP     1
++VALUE         Framed-Compression      VJ-TCP-IP               1
++VALUE         Service-Type            Shell-User              6
++VALUE         Auth-Type               Unix                    1
++VALUE         Service-Type            Dialback-Login-User     3
++VALUE         Service-Type            Dialback-Framed-User    4
++
++#
++#     For compatibility with MERIT users files.
++#
++ATTRIBUTE     NAS-Port                5       integer
++ATTRIBUTE     Login-Host              14      ipaddr
++ATTRIBUTE     Login-Callback-Number   19      string
++ATTRIBUTE     Framed-Callback-Id      20      string
++ATTRIBUTE     Client-Port-DNIS        30      string
++ATTRIBUTE     Caller-ID               31      string
++VALUE         Service-Type            Login                   1
++VALUE         Service-Type            Framed                  2
++VALUE         Service-Type            Callback-Login          3
++VALUE         Service-Type            Callback-Framed         4
++VALUE         Service-Type            Exec-User               7
++
++#
++#     For compatibility with ESVA RADIUS, Old Cistron RADIUS
++#
++ATTRIBUTE     Session                 1034    integer
++ATTRIBUTE     User-Name-Is-Star       1035    integer
++VALUE         User-Name-Is-Star       No                      0
++VALUE         User-Name-Is-Star       Yes                     1
+diff --git a/src/plugins/vbng/etc/dictionary.dhcp b/src/plugins/vbng/etc/dictionary.dhcp
+new file mode 100644
+index 00000000..cf329348
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary.dhcp
+@@ -0,0 +1,440 @@
++# -*- text -*-
++# Copyright (C) 2011 The FreeRADIUS Server project and contributors
++##############################################################################
++#
++#     DHCP to RADUS gateway dictionary.
++#
++#     http://www.iana.org/assignments/bootp-dhcp-parameters
++#
++#     Also http://www.networksorcery.com/enp/protocol/bootp/options.htm
++#
++#     http://www.bind9.net/rfc-dhcp
++#
++#     $Id: 73632c57d3860bb30749a1df4dad2320d5f79f31 $
++#
++##############################################################################
++
++#
++
++#     This is really Apollo's number, but since they're out of business,
++#     I don't think they'll be needing this.
++#
++#     HP owns the Apollo assets, but let's not worry about that.
++#
++#     The vendor codes are 2 octets, because we need 256 numbers
++#     for the base DHCP options, PLUS a few for the DHCP headers,
++#     which aren't in option format.
++#
++#     On top of that, a number of options are really TLV's.
++#     We need to be able to understand them, too.
++#
++VENDOR                DHCP                            54      format=2,1
++
++BEGIN-VENDOR  DHCP
++
++ATTRIBUTE     DHCP-Opcode                             256     byte
++ATTRIBUTE     DHCP-Hardware-Type                      257     byte
++ATTRIBUTE     DHCP-Hardware-Address-Length            258     byte
++ATTRIBUTE     DHCP-Hop-Count                          259     byte
++ATTRIBUTE     DHCP-Transaction-Id                     260     integer
++ATTRIBUTE     DHCP-Number-of-Seconds                  261     short
++ATTRIBUTE     DHCP-Flags                              262     short
++ATTRIBUTE     DHCP-Client-IP-Address                  263     ipaddr
++ATTRIBUTE     DHCP-Your-IP-Address                    264     ipaddr
++ATTRIBUTE     DHCP-Server-IP-Address                  265     ipaddr
++ATTRIBUTE     DHCP-Gateway-IP-Address                 266     ipaddr
++ATTRIBUTE     DHCP-Client-Hardware-Address            267     ether     # 16 octets
++ATTRIBUTE     DHCP-Server-Host-Name                   268     string    # 64 octets
++ATTRIBUTE     DHCP-Boot-Filename                      269     string    # 128 octets
++
++ATTRIBUTE     DHCP-Relay-To-IP-Address                270     ipaddr
++ATTRIBUTE     DHCP-Relay-Max-Hop-Count                271     integer
++
++# This is copied from the request packet, giaddr, and
++# added to the reply packet by the server core.
++ATTRIBUTE     DHCP-Relay-IP-Address                   272     ipaddr
++
++VALUE DHCP-Flags                      Broadcast               0x8000
++
++VALUE DHCP-Hardware-Type              Ethernet                1
++VALUE DHCP-Hardware-Type              Experiemental-Ethernet  2
++VALUE DHCP-Hardware-Type              AX.25                   3
++VALUE DHCP-Hardware-Type              Proteon-Token-Ring      4
++VALUE DHCP-Hardware-Type              Chaos                   5
++VALUE DHCP-Hardware-Type              IEEE-802                6
++VALUE DHCP-Hardware-Type              Arcnet                  7
++VALUE DHCP-Hardware-Type              Hyperchannel            8
++VALUE DHCP-Hardware-Type              Lanstar                 9
++VALUE DHCP-Hardware-Type              Autonet-Short-Address   10
++VALUE DHCP-Hardware-Type              LocalTalk               11
++VALUE DHCP-Hardware-Type              LocalNet                12
++VALUE DHCP-Hardware-Type              Ultra-Link              13
++VALUE DHCP-Hardware-Type              SMDS                    14
++VALUE DHCP-Hardware-Type              Frame-Relay             15
++VALUE DHCP-Hardware-Type              ATM-16                  16
++VALUE DHCP-Hardware-Type              HDLC                    17
++VALUE DHCP-Hardware-Type              Fibre-Channel           18
++VALUE DHCP-Hardware-Type              ATM-19                  19
++VALUE DHCP-Hardware-Type              Serial-Line             20
++VALUE DHCP-Hardware-Type              ATM-21                  21
++VALUE DHCP-Hardware-Type              MIL-STD-188-220         22
++VALUE DHCP-Hardware-Type              Metricom                23
++VALUE DHCP-Hardware-Type              IEEE-1394               24
++VALUE DHCP-Hardware-Type              MAPOS                   25
++VALUE DHCP-Hardware-Type              Twinaxial               26
++VALUE DHCP-Hardware-Type              EUI-64                  27
++VALUE DHCP-Hardware-Type              HIPARP                  28
++VALUE DHCP-Hardware-Type              IP-Over-ISO-7816-3      29
++VALUE DHCP-Hardware-Type              ARPSec                  30
++VALUE DHCP-Hardware-Type              IPSec-Tunnel            31
++VALUE DHCP-Hardware-Type              Infiniband              32
++VALUE DHCP-Hardware-Type              CAI-TIA-102             33
++
++##############################################################################
++#
++#     DHCP Options, with comments.  For now, many are "octets",
++#     as FreeRADIUS doesn't handle complex data structures.
++#
++##############################################################################
++
++#ATTRIBUTE    DHCP-Pad                                0       octets
++ATTRIBUTE     DHCP-Subnet-Mask                        1       ipaddr
++# Time Offset in twos-complement notation.
++ATTRIBUTE     DHCP-Time-Offset                        2       integer
++ATTRIBUTE     DHCP-Router-Address                     3       ipaddr array
++ATTRIBUTE     DHCP-Time-Server                        4       ipaddr array
++ATTRIBUTE     DHCP-IEN-116-Name-Server                5       ipaddr array
++ATTRIBUTE     DHCP-Domain-Name-Server                 6       ipaddr array
++# Logging-Server addresses
++ATTRIBUTE     DHCP-Log-Server                         7       ipaddr array
++ATTRIBUTE     DHCP-Quotes-Server                      8       ipaddr array
++ATTRIBUTE     DHCP-LPR-Server                         9       ipaddr array
++ATTRIBUTE     DHCP-Impress-Server                     10      ipaddr array
++ATTRIBUTE     DHCP-RLP-Server                         11      ipaddr array
++# Hostname string
++ATTRIBUTE     DHCP-Hostname                           12      string
++# Size of boot file in 512 byte
++ATTRIBUTE     DHCP-Boot-File-Size                     13      short
++# Client to dump and name
++ATTRIBUTE     DHCP-Merit-Dump-File                    14      octets
++ATTRIBUTE     DHCP-Domain-Name                        15      string
++ATTRIBUTE     DHCP-Swap-Server                        16      ipaddr
++# Path name for root disk
++ATTRIBUTE     DHCP-Root-Path                          17      string
++ATTRIBUTE     DHCP-Bootp-Extensions-Path              18      string
++ATTRIBUTE     DHCP-IP-Forward-Enable                  19      byte
++ATTRIBUTE     DHCP-Source-Route-Enable                20      byte
++# Routing Policy Filters
++ATTRIBUTE     DHCP-Policy-Filter                      21      octets
++ATTRIBUTE     DHCP-Max-Datagram-Reassembly-Sz         22      short
++ATTRIBUTE     DHCP-Default-IP-TTL                     23      octets
++ATTRIBUTE     DHCP-Path-MTU-Aging-Timeout             24      integer
++ATTRIBUTE     DHCP-Path-MTU-Plateau-Table             25      short array
++ATTRIBUTE     DHCP-Interface-MTU-Size                 26      short
++ATTRIBUTE     DHCP-All-Subnets-Are-Local              27      byte
++ATTRIBUTE     DHCP-Broadcast-Address                  28      ipaddr
++ATTRIBUTE     DHCP-Perform-Mask-Discovery             29      byte
++ATTRIBUTE     DHCP-Provide-Mask-To-Others             30      byte
++ATTRIBUTE     DHCP-Perform-Router-Discovery           31      byte
++ATTRIBUTE     DHCP-Router-Solicitation-Address        32      ipaddr
++# first is destination address, second is router.
++ATTRIBUTE     DHCP-Static-Routes                      33      ipaddr array
++ATTRIBUTE     DHCP-Trailer-Encapsulation              34      byte
++ATTRIBUTE     DHCP-ARP-Cache-Timeout                  35      integer
++ATTRIBUTE     DHCP-Ethernet-Encapsulation             36      byte
++ATTRIBUTE     DHCP-Default-TCP-TTL                    37      byte
++ATTRIBUTE     DHCP-Keep-Alive-Interval                38      integer
++ATTRIBUTE     DHCP-Keep-Alive-Garbage                 39      byte
++ATTRIBUTE     DHCP-NIS-Domain-Name                    40      string
++ATTRIBUTE     DHCP-NIS-Servers                        41      ipaddr array
++ATTRIBUTE     DHCP-NTP-Servers                        42      ipaddr array
++# N Vendor Specific Information
++ATTRIBUTE     DHCP-Vendor                             43      octets # tlv
++ATTRIBUTE     DHCP-NETBIOS-Name-Servers               44      ipaddr array
++ATTRIBUTE     DHCP-NETBIOS-Dgm-Dist-Servers           45      ipaddr array
++ATTRIBUTE     DHCP-NETBIOS-Node-Type                  46      byte
++# N NETBIOS Scope
++ATTRIBUTE     DHCP-NETBIOS                            47      octets
++ATTRIBUTE     DHCP-X-Window-Font-Server               48      ipaddr array
++ATTRIBUTE     DHCP-X-Window-Display-Mgr               49      ipaddr array
++ATTRIBUTE     DHCP-Requested-IP-Address               50      ipaddr
++ATTRIBUTE     DHCP-IP-Address-Lease-Time              51      integer
++# Overload "sname" or "file"
++ATTRIBUTE     DHCP-Overload                           52      byte
++ATTRIBUTE     DHCP-Message-Type                       53      byte
++ATTRIBUTE     DHCP-DHCP-Server-Identifier             54      ipaddr
++
++# Array of 1-byte numbers indicating which options the client
++# would like to see in the response.
++ATTRIBUTE     DHCP-Parameter-Request-List             55      byte array
++ATTRIBUTE     DHCP-DHCP-Error-Message                 56      octets
++ATTRIBUTE     DHCP-DHCP-Maximum-Msg-Size              57      short
++ATTRIBUTE     DHCP-Renewal-Time                       58      integer
++ATTRIBUTE     DHCP-Rebinding-Time                     59      integer
++ATTRIBUTE     DHCP-Vendor-Class-Identifier            60      string
++
++# Client Identifier
++# First octets is DHCP-Hardware-Type, rest are type-specific data,
++# e.g. MAC address.
++ATTRIBUTE     DHCP-Client-Identifier                  61      ether
++ATTRIBUTE     DHCP-Netware-Domain-Name                62      octets
++ATTRIBUTE     DHCP-Netware-Sub-Options                63      octets
++ATTRIBUTE     DHCP-NIS-Client-Domain-Name             64      octets
++ATTRIBUTE     DHCP-NIS-Server-Address                 65      ipaddr
++ATTRIBUTE     DHCP-TFTP-Server-Name                   66      string
++ATTRIBUTE     DHCP-Boot-File-Name                     67      string
++# Home Agent Addresses
++ATTRIBUTE     DHCP-Home-Agent-Address                 68      octets
++ATTRIBUTE     DHCP-SMTP-Server-Address                69      ipaddr array
++ATTRIBUTE     DHCP-POP3-Server-Address                70      ipaddr array
++ATTRIBUTE     DHCP-NNTP-Server-Address                71      ipaddr array
++ATTRIBUTE     DHCP-WWW-Server-Address                 72      ipaddr array
++ATTRIBUTE     DHCP-Finger-Server-Address              73      ipaddr array
++ATTRIBUTE     DHCP-IRC-Server-Address                 74      ipaddr array
++ATTRIBUTE     DHCP-StreetTalk-Server-Address          75      ipaddr array
++ATTRIBUTE     DHCP-STDA-Server-Address                76      ipaddr array
++# User Class Information
++ATTRIBUTE     DHCP-User-Class                         77      octets
++# directory agent information
++ATTRIBUTE     DHCP-Directory-Agent                    78      octets
++# service location agent scope
++ATTRIBUTE     DHCP-Service-Scope                      79      octets
++# Rapid Commit
++ATTRIBUTE     DHCP-Rapid-Commit                       80      octets
++# Fully Qualified Domain Name
++ATTRIBUTE     DHCP-Client-FQDN                        81      string
++# Relay Agent Information
++ATTRIBUTE     DHCP-Relay-Agent-Information            82      tlv
++
++ATTRIBUTE     DHCP-Agent-Circuit-Id                   82.1    octets
++ATTRIBUTE     DHCP-Agent-Remote-Id                    82.2    octets
++
++ATTRIBUTE     DHCP-Relay-Circuit-Id                   82.1    octets
++ATTRIBUTE     DHCP-Relay-Remote-Id                    82.2    octets
++
++# 3 is reserved and shouldn't be used for anything
++ATTRIBUTE     DHCP-Docsis-Device-Class                82.4    integer
++ATTRIBUTE     DHCP-Relay-Link-Selection               82.5    ipaddr
++ATTRIBUTE     DHCP-Subscriber-Id                      82.6    string
++
++# AGH!  RADIUS inside of DHCP!
++ATTRIBUTE     DHCP-RADIUS-Attributes                  82.7    octets
++
++# Horribly complicated
++ATTRIBUTE     DHCP-Authentication-Information         82.8    octets
++ATTRIBUTE     DHCP-Vendor-Specific-Information        82.9    octets
++ATTRIBUTE     DHCP-Relay-Agent-Flags                  82.10   byte
++ATTRIBUTE     DHCP-Server-Identifier-Override         82.11   ipaddr
++
++# Internet Storage Name Service
++ATTRIBUTE     DHCP-iSNS                               83      octets
++# Novell Directory Services
++ATTRIBUTE     DHCP-NDS-Servers                        85      octets
++# Novell Directory Services
++ATTRIBUTE     DHCP-NDS-Tree-Name                      86      octets
++# Novell Directory Services
++ATTRIBUTE     DHCP-NDS-Context                        87      octets
++# Authentication
++ATTRIBUTE     DHCP-Authentication                     90      octets
++
++ATTRIBUTE     DHCP-Client-Last-Txn-Time               91      octets
++
++ATTRIBUTE     DHCP-associated-ip                      92      octets
++# Client System Architecture
++ATTRIBUTE     DHCP-Client-System                      93      octets
++# Client Network Device Interface
++ATTRIBUTE     DHCP-Client-NDI                         94      octets
++# Lightweight Directory Access Protocol
++ATTRIBUTE     DHCP-LDAP                               95      octets
++# UUID/GUID-based Client Identifier
++ATTRIBUTE     DHCP-UUID/GUID                          97      octets
++# Open Group's User Authentication
++ATTRIBUTE     DHCP-User-Auth                          98      octets
++# NetInfo Parent-Server Address
++ATTRIBUTE     DHCP-Netinfo-Address                    112     octets
++# NetInfo Parent-Server Tag
++ATTRIBUTE     DHCP-Netinfo-Tag                        113     octets
++# URL
++ATTRIBUTE     DHCP-URL                                114     octets
++# DHCP Auto-Configuration
++ATTRIBUTE     DHCP-Auto-Config                        116     byte
++# Name Service Search
++ATTRIBUTE     DHCP-Name-Service-Search                117     octets
++# Subnet Selection Option
++ATTRIBUTE     DHCP-Subnet-Selection-Option            118     octets
++# DNS domain serach list
++ATTRIBUTE     DHCP-Domain-Search                      119     octets
++# SIP-Servers DHCP Option
++ATTRIBUTE     DHCP-SIP-Servers-DHCP-Option            120     octets
++# Classless Static Route Option
++ATTRIBUTE     DHCP-Classless-Static-Route             121     octets
++# CableLabs Client Configuration
++ATTRIBUTE     DHCP-CCC                                122     octets
++# 16 GeoConf Option
++ATTRIBUTE     DHCP-GeoConf-Option                     123     octets
++
++# Vendor Class
++#
++# String name that defines the vendor space used for the TLV's
++# in option 125.
++#
++ATTRIBUTE     DHCP-V-I-Vendor-Class                   124     octets
++# Vendor-Specific
++ATTRIBUTE     DHCP-V-I-Vendor-Specific                125     octets # tlv
++ATTRIBUTE     DHCP-Etherboot                          128     ether
++# (for IP Phone software load)
++ATTRIBUTE     DHCP-TFTP-Server-IP-Address             128     octets
++
++ATTRIBUTE     DHCP-Call-Server-IP-address             129     octets
++
++ATTRIBUTE     DHCP-Ethernet-Interface                 130     octets
++
++ATTRIBUTE     DHCP-Vendor-Discrimination-Str          130     octets
++
++ATTRIBUTE     DHCP-Remote-Stats-Svr-IP-Address        131     octets
++
++ATTRIBUTE     DHCP-IEEE-802.1Q-L2-Priority            132     octets
++
++ATTRIBUTE     DHCP-IEEE-802.1P-VLAN-ID                133     octets
++
++ATTRIBUTE     DHCP-Diffserv-Code-Point                134     octets
++
++ATTRIBUTE     DHCP-HTTP-Proxy                         135     octets
++
++ATTRIBUTE     DHCP-Cisco-TFTP-Server-IP-Addresses     150     ipaddr array
++
++ATTRIBUTE     DHCP-End-Of-Options                     255     byte
++
++VALUE DHCP-Opcode                     Client-Message          1
++VALUE DHCP-Opcode                     Server-Message          2
++
++VALUE DHCP-Message-Type               DHCP-Do-Not-Respond     0
++VALUE DHCP-Message-Type               DHCP-Discover           1
++VALUE DHCP-Message-Type               DHCP-Offer              2
++VALUE DHCP-Message-Type               DHCP-Request            3
++VALUE DHCP-Message-Type               DHCP-Decline            4
++VALUE DHCP-Message-Type               DHCP-Ack                5
++VALUE DHCP-Message-Type               DHCP-NAK                6
++VALUE DHCP-Message-Type               DHCP-Release            7
++VALUE DHCP-Message-Type               DHCP-Inform             8
++VALUE DHCP-Message-Type               DHCP-Force-Renew        9
++
++VALUE DHCP-Parameter-Request-List     DHCP-Subnet-Mask        1
++VALUE DHCP-Parameter-Request-List     DHCP-Time-Offset        2
++VALUE DHCP-Parameter-Request-List     DHCP-Router-Address     3
++VALUE DHCP-Parameter-Request-List     DHCP-Time-Server        4
++VALUE DHCP-Parameter-Request-List     DHCP-IEN-116-Name-Server 5
++VALUE DHCP-Parameter-Request-List     DHCP-Domain-Name-Server 6
++VALUE DHCP-Parameter-Request-List     DHCP-Log-Server         7
++VALUE DHCP-Parameter-Request-List     DHCP-Quotes-Server      8
++VALUE DHCP-Parameter-Request-List     DHCP-LPR-Server         9
++VALUE DHCP-Parameter-Request-List     DHCP-Impress-Server     10
++VALUE DHCP-Parameter-Request-List     DHCP-RLP-Server         11
++VALUE DHCP-Parameter-Request-List     DHCP-Hostname           12
++VALUE DHCP-Parameter-Request-List     DHCP-Boot-File-Size     13
++VALUE DHCP-Parameter-Request-List     DHCP-Merit-Dump-File    14
++VALUE DHCP-Parameter-Request-List     DHCP-Domain-Name        15
++VALUE DHCP-Parameter-Request-List     DHCP-Swap-Server        16
++VALUE DHCP-Parameter-Request-List     DHCP-Root-Path          17
++VALUE DHCP-Parameter-Request-List     DHCP-Bootp-Extensions-Path 18
++VALUE DHCP-Parameter-Request-List     DHCP-IP-Forward-Enable  19
++VALUE DHCP-Parameter-Request-List     DHCP-Source-Route-Enable 20
++VALUE DHCP-Parameter-Request-List     DHCP-Policy-Filter      21
++VALUE DHCP-Parameter-Request-List     DHCP-Max-Datagram-Reassembly-Sz 22
++VALUE DHCP-Parameter-Request-List     DHCP-Default-IP-TTL     23
++VALUE DHCP-Parameter-Request-List     DHCP-Path-MTU-Aging-Timeout 24
++VALUE DHCP-Parameter-Request-List     DHCP-Path-MTU-Plateau-Table 25
++VALUE DHCP-Parameter-Request-List     DHCP-Interface-MTU-Size 26
++VALUE DHCP-Parameter-Request-List     DHCP-All-Subnets-Are-Local 27
++VALUE DHCP-Parameter-Request-List     DHCP-Broadcast-Address  28
++VALUE DHCP-Parameter-Request-List     DHCP-Perform-Mask-Discovery 29
++VALUE DHCP-Parameter-Request-List     DHCP-Provide-Mask-To-Others 30
++VALUE DHCP-Parameter-Request-List     DHCP-Perform-Router-Discovery 31
++VALUE DHCP-Parameter-Request-List     DHCP-Router-Solicitation-Address 32
++VALUE DHCP-Parameter-Request-List     DHCP-Static-Routes      33
++VALUE DHCP-Parameter-Request-List     DHCP-Trailer-Encapsulation 34
++VALUE DHCP-Parameter-Request-List     DHCP-ARP-Cache-Timeout  35
++VALUE DHCP-Parameter-Request-List     DHCP-Ethernet-Encapsulation 36
++VALUE DHCP-Parameter-Request-List     DHCP-Default-TCP-TTL    37
++VALUE DHCP-Parameter-Request-List     DHCP-Keep-Alive-Interval 38
++VALUE DHCP-Parameter-Request-List     DHCP-Keep-Alive-Garbage 39
++VALUE DHCP-Parameter-Request-List     DHCP-NIS-Domain-Name    40
++VALUE DHCP-Parameter-Request-List     DHCP-NIS-Servers        41
++VALUE DHCP-Parameter-Request-List     DHCP-NTP-Servers        42
++VALUE DHCP-Parameter-Request-List     DHCP-Vendor             43
++VALUE DHCP-Parameter-Request-List     DHCP-NETBIOS-Name-Servers 44
++VALUE DHCP-Parameter-Request-List     DHCP-NETBIOS-Dgm-Dist-Servers 45
++VALUE DHCP-Parameter-Request-List     DHCP-NETBIOS-Node-Type  46
++VALUE DHCP-Parameter-Request-List     DHCP-NETBIOS            47
++VALUE DHCP-Parameter-Request-List     DHCP-X-Window-Font-Server 48
++VALUE DHCP-Parameter-Request-List     DHCP-X-Window-Display-Mgr 49
++VALUE DHCP-Parameter-Request-List     DHCP-Requested-IP-Address 50
++VALUE DHCP-Parameter-Request-List     DHCP-IP-Address-Lease-Time 51
++VALUE DHCP-Parameter-Request-List     DHCP-Overload           52
++VALUE DHCP-Parameter-Request-List     DHCP-Message-Type       53
++VALUE DHCP-Parameter-Request-List     DHCP-DHCP-Server-Identifier 54
++VALUE DHCP-Parameter-Request-List     DHCP-Parameter-Request-List 55
++VALUE DHCP-Parameter-Request-List     DHCP-DHCP-Error-Message 56
++VALUE DHCP-Parameter-Request-List     DHCP-DHCP-Maximum-Msg-Size 57
++VALUE DHCP-Parameter-Request-List     DHCP-Renewal-Time       58
++VALUE DHCP-Parameter-Request-List     DHCP-Rebinding-Time     59
++VALUE DHCP-Parameter-Request-List     DHCP-Class-Identifier   60
++VALUE DHCP-Parameter-Request-List     DHCP-Client-Identifier  61
++VALUE DHCP-Parameter-Request-List     DHCP-Netware-Domain-Name 62
++VALUE DHCP-Parameter-Request-List     DHCP-Netware-Sub-Options 63
++VALUE DHCP-Parameter-Request-List     DHCP-NIS-Client-Domain-Name 64
++VALUE DHCP-Parameter-Request-List     DHCP-NIS-Server-Address 65
++VALUE DHCP-Parameter-Request-List     DHCP-TFTP-Server-Name   66
++VALUE DHCP-Parameter-Request-List     DHCP-Boot-File-Name     67
++VALUE DHCP-Parameter-Request-List     DHCP-Home-Agent-Address 68
++VALUE DHCP-Parameter-Request-List     DHCP-SMTP-Server-Address 69
++VALUE DHCP-Parameter-Request-List     DHCP-POP3-Server-Address 70
++VALUE DHCP-Parameter-Request-List     DHCP-NNTP-Server-Address 71
++VALUE DHCP-Parameter-Request-List     DHCP-WWW-Server-Address 72
++VALUE DHCP-Parameter-Request-List     DHCP-Finger-Server-Address 73
++VALUE DHCP-Parameter-Request-List     DHCP-IRC-Server-Address 74
++VALUE DHCP-Parameter-Request-List     DHCP-StreetTalk-Server-Address 75
++VALUE DHCP-Parameter-Request-List     DHCP-STDA-Server-Address 76
++VALUE DHCP-Parameter-Request-List     DHCP-User-Class         77
++VALUE DHCP-Parameter-Request-List     DHCP-Directory-Agent    78
++VALUE DHCP-Parameter-Request-List     DHCP-Service-Scope      79
++VALUE DHCP-Parameter-Request-List     DHCP-Rapid-Commit       80
++VALUE DHCP-Parameter-Request-List     DHCP-Client-FQDN        81
++VALUE DHCP-Parameter-Request-List     DHCP-Relay-Agent-Information 82
++VALUE DHCP-Parameter-Request-List     DHCP-iSNS               83
++VALUE DHCP-Parameter-Request-List     DHCP-NDS-Servers        85
++VALUE DHCP-Parameter-Request-List     DHCP-NDS-Tree-Name      86
++VALUE DHCP-Parameter-Request-List     DHCP-NDS-Context        87
++VALUE DHCP-Parameter-Request-List     DHCP-Authentication     90
++VALUE DHCP-Parameter-Request-List     DHCP-Client-Last-Txn-Time 91
++VALUE DHCP-Parameter-Request-List     DHCP-associated-ip      92
++VALUE DHCP-Parameter-Request-List     DHCP-Client-System      93
++VALUE DHCP-Parameter-Request-List     DHCP-Client-NDI         94
++VALUE DHCP-Parameter-Request-List     DHCP-LDAP               95
++VALUE DHCP-Parameter-Request-List     DHCP-UUID/GUID          97
++VALUE DHCP-Parameter-Request-List     DHCP-User-Auth          98
++VALUE DHCP-Parameter-Request-List     DHCP-Netinfo-Address    112
++VALUE DHCP-Parameter-Request-List     DHCP-Netinfo-Tag        113
++VALUE DHCP-Parameter-Request-List     DHCP-URL                114
++VALUE DHCP-Parameter-Request-List     DHCP-Auto-Config        116
++VALUE DHCP-Parameter-Request-List     DHCP-Name-Service-Search 117
++VALUE DHCP-Parameter-Request-List     DHCP-Subnet-Selection-Option 118
++VALUE DHCP-Parameter-Request-List     DHCP-Domain-Search      119
++VALUE DHCP-Parameter-Request-List     DHCP-SIP-Servers-DHCP-Option 120
++VALUE DHCP-Parameter-Request-List     DHCP-Classless-Static-Route 121
++VALUE DHCP-Parameter-Request-List     DHCP-CCC                122
++VALUE DHCP-Parameter-Request-List     DHCP-GeoConf-Option     123
++VALUE DHCP-Parameter-Request-List     DHCP-V-I-Vendor-Class   124
++VALUE DHCP-Parameter-Request-List     DHCP-V-I-Vendor-Specific 125
++VALUE DHCP-Parameter-Request-List     DHCP-Etherboot          128
++VALUE DHCP-Parameter-Request-List     DHCP-TFTP-Server-IP-Address 128
++VALUE DHCP-Parameter-Request-List     DHCP-Call-Server-IP-address 129
++VALUE DHCP-Parameter-Request-List     DHCP-Ethernet-Interface 130
++VALUE DHCP-Parameter-Request-List     DHCP-Vendor-Discrimination-Str 130
++VALUE DHCP-Parameter-Request-List     DHCP-Remote-Stats-Svr-IP-Address 131
++VALUE DHCP-Parameter-Request-List     DHCP-IEEE-802.1P-VLAN-ID 132
++VALUE DHCP-Parameter-Request-List     DHCP-IEEE-802.1Q-L2-Priority 133
++VALUE DHCP-Parameter-Request-List     DHCP-Diffserv-Code-Point 134
++VALUE DHCP-Parameter-Request-List     DHCP-HTTP-Proxy         135
++
++END-VENDOR    DHCP
+diff --git a/src/plugins/vbng/etc/dictionary.merit b/src/plugins/vbng/etc/dictionary.merit
+new file mode 100644
+index 00000000..7d675e50
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary.merit
+@@ -0,0 +1,17 @@
++#
++#     Experimental extensions, configuration only (for check-items)
++#     Names/numbers as per the MERIT extensions (if possible).
++#
++ATTRIBUTE     NAS-Identifier          32      string
++ATTRIBUTE     Proxy-State             33      string
++ATTRIBUTE     Login-LAT-Service       34      string
++ATTRIBUTE     Login-LAT-Node          35      string
++ATTRIBUTE     Login-LAT-Group         36      string
++ATTRIBUTE     Framed-AppleTalk-Link   37      integer
++ATTRIBUTE     Framed-AppleTalk-Network 38     integer
++ATTRIBUTE     Framed-AppleTalk-Zone   39      string
++ATTRIBUTE       Acct-Input-Packets    47      integer
++ATTRIBUTE       Acct-Output-Packets   48      integer
++# 8 is a MERIT extension.
++VALUE         Service-Type            Authenticate-Only       8
++
+diff --git a/src/plugins/vbng/etc/dictionary.sip b/src/plugins/vbng/etc/dictionary.sip
+new file mode 100644
+index 00000000..149fa4cb
+--- /dev/null
++++ b/src/plugins/vbng/etc/dictionary.sip
+@@ -0,0 +1,77 @@
++#
++# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
++#
++#     This file contains dictionary translations for parsing
++#     requests and generating responses.  All transactions are
++#     composed of Attribute/Value Pairs.  The value of each attribute
++#     is specified as one of 4 data types.  Valid data types are:
++#
++#     string - 0-253 octets
++#     ipaddr - 4 octets in network byte order
++#     integer - 32 bit value in big endian order (high byte first)
++#     date - 32 bit value in big endian order - seconds since
++#                                     00:00:00 GMT,  Jan.  1,  1970
++#
++#     Enumerated values are stored in the user file with dictionary
++#     VALUE translations for easy administration.
++#
++#     Example:
++#
++#     ATTRIBUTE         VALUE
++#     ---------------   -----
++#     Framed-Protocol = PPP
++#     7               = 1     (integer encoding)
++#
++
++#
++#     Experimental SIP Attributes/Values (draft-sterman-aaa-sip-00.txt etc)
++#
++ATTRIBUTE     Sip-Method              101     integer
++ATTRIBUTE     Sip-Response-Code       102     integer
++ATTRIBUTE     Sip-CSeq                103     string
++ATTRIBUTE     Sip-To-Tag              104     string
++ATTRIBUTE     Sip-From-Tag            105     string
++ATTRIBUTE     Sip-Branch-ID           106     string
++ATTRIBUTE     Sip-Translated-Request-URI      107     string
++ATTRIBUTE     Sip-Source-IP-Address   108     ipaddr
++ATTRIBUTE     Sip-Source-Port         109     integer
++ATTRIBUTE     Sip-User-ID             110     string
++ATTRIBUTE     Sip-User-Realm          111     string
++ATTRIBUTE     Sip-User-Nonce          112     string
++ATTRIBUTE     Sip-User-Method         113     string
++ATTRIBUTE     Sip-User-Digest-URI     114     string
++ATTRIBUTE     Sip-User-Nonce-Count    115     string
++ATTRIBUTE     Sip-User-QOP            116     string
++ATTRIBUTE     Sip-User-Opaque         117     string
++ATTRIBUTE     Sip-User-Response       118     string
++ATTRIBUTE     Sip-User-CNonce         119     string
++ATTRIBUTE     Sip-URI-User            208     string
++ATTRIBUTE     Sip-Req-URI             210     string
++ATTRIBUTE     Sip-CC                  212     string
++ATTRIBUTE     Sip-RPId                213     string
++ATTRIBUTE     Digest-Response         206     string
++ATTRIBUTE     Digest-Attributes       207     string
++ATTRIBUTE     Digest-Realm            1063    string
++ATTRIBUTE     Digest-Nonce            1064    string
++ATTRIBUTE     Digest-Method           1065    string
++ATTRIBUTE     Digest-URI              1066    string
++ATTRIBUTE     Digest-QOP              1067    string
++ATTRIBUTE     Digest-Algorithm        1068    string
++ATTRIBUTE     Digest-Body-Digest      1069    string
++ATTRIBUTE     Digest-CNonce           1070    string
++ATTRIBUTE     Digest-Nonce-Count      1071    string
++ATTRIBUTE     Digest-User-Name        1072    string
++
++VALUE         Service-Type            SIP                     15
++
++VALUE         Sip-Method              Other                   0
++VALUE         Sip-Method              Invite                  1
++VALUE         Sip-Method              Cancel                  2
++VALUE         Sip-Method              Ack                     3
++VALUE         Sip-Method              Bye                     4
++
++VALUE         Sip-Response-Code       Other                   0
++VALUE         Sip-Response-Code       Invite                  1
++VALUE         Sip-Response-Code       Cancel                  2
++VALUE         Sip-Response-Code       Ack                     3
++VALUE         Sip-Response-Code       Bye                     4
+diff --git a/src/plugins/vbng/etc/issue b/src/plugins/vbng/etc/issue
+new file mode 100644
+index 00000000..62544873
+--- /dev/null
++++ b/src/plugins/vbng/etc/issue
+@@ -0,0 +1,5 @@
++(\I)
++-----------------------------------------------------
++\S \R (\N) (port \L)
++-----------------------------------------------------
++
+diff --git a/src/plugins/vbng/etc/port-id-map b/src/plugins/vbng/etc/port-id-map
+new file mode 100644
+index 00000000..9088a0b9
+--- /dev/null
++++ b/src/plugins/vbng/etc/port-id-map
+@@ -0,0 +1,24 @@
++#
++# port-id-map
++#
++# This file describes the ttyname to port id mapping. The port id
++# is reported as part of a RADIUS authentication or accouting request.
++#
++#ttyname (as returned by ttyname(3))  port-id
++/dev/tty1     1
++/dev/tty2     2
++/dev/tty3     3
++/dev/tty4     4
++/dev/tty5     5
++/dev/tty6     6
++/dev/tty7     7
++/dev/tty8     8
++/dev/ttyS0    9
++/dev/ttyS1    10
++/dev/ttyS2    11
++/dev/ttyS3    12
++/dev/ttyS4    13
++/dev/ttyS5    14
++/dev/ttyS6    15
++/dev/ttyS7    16
++ 
+\ No newline at end of file
+diff --git a/src/plugins/vbng/etc/radiusclient.conf b/src/plugins/vbng/etc/radiusclient.conf
+new file mode 100644
+index 00000000..3a315b46
+--- /dev/null
++++ b/src/plugins/vbng/etc/radiusclient.conf
+@@ -0,0 +1,92 @@
++# General settings
++
++# specify which authentication comes first respectively which
++# authentication is used. possible values are: "radius" and "local".
++# if you specify "radius,local" then the RADIUS server is asked
++# first then the local one. if only one keyword is specified only
++# this server is asked.
++auth_order    radius,local
++
++# maximum login tries a user has
++login_tries   4
++
++# timeout for all login tries
++# if this time is exceeded the user is kicked out
++login_timeout 60
++
++# name of the nologin file which when it exists disables logins.
++# it may be extended by the ttyname which will result in
++# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
++# logins on /dev/ttyS2)
++nologin /etc/nologin
++
++# name of the issue file. it's only display when no username is passed
++# on the radlogin command line
++issue /usr/local/etc/radiusclient/issue
++
++# RADIUS settings
++
++# RADIUS server to use for authentication requests. this config
++# item can appear more then one time. if multiple servers are
++# defined they are tried in a round robin fashion if one
++# server is not answering.
++# optionally you can specify a the port number on which is remote
++# RADIUS listens separated by a colon from the hostname. if
++# no port is specified /etc/services is consulted of the radius
++# service. if this fails also a compiled in default is used.
++authserver    localhost
++
++# RADIUS server to use for accouting requests. All that I
++# said for authserver applies, too. 
++#
++acctserver    localhost
++
++# file holding shared secrets used for the communication
++# between the RADIUS client and server
++servers               /usr/local/etc/radiusclient/servers
++
++# dictionary of allowed attributes and values
++# just like in the normal RADIUS distributions
++dictionary    /usr/local/etc/radiusclient/dictionary
++
++# program to call for a RADIUS authenticated login
++login_radius  /usr/local/sbin/login.radius
++
++# file which holds sequence number for communication with the
++# RADIUS server
++seqfile               /var/run/radius.seq
++
++# file which specifies mapping between ttyname and NAS-Port attribute
++mapfile               /usr/local/etc/radiusclient/port-id-map
++
++# default authentication realm to append to all usernames if no
++# realm was explicitly specified by the user
++# the radiusd directly form Livingston doesnt use any realms, so leave
++# it blank then
++default_realm
++
++# time to wait for a reply from the RADIUS server
++radius_timeout        10
++
++# resend request this many times before trying the next server
++radius_retries        3
++
++# The length of time in seconds that we skip a nonresponsive RADIUS
++# server for transaction requests.  Server(s) being in the "dead" state
++# are tried only after all other non-dead servers have been tried and
++# failed or timeouted.  The deadtime interval starts when the server
++# does not respond to an authentication/accounting request transmissions. 
++# When the interval expires, the "dead" server would be re-tried again,
++# and if it's still down then it will be considered "dead" for another
++# such interval and so on. This option is no-op if there is only one
++# server in the list. Set to 0 in order to disable the feature.
++radius_deadtime       0
++
++# local address from which radius packets have to be sent
++bindaddr *
++
++# LOCAL settings
++
++# program to execute for local login
++# it must support the -f flag for preauthenticated login
++login_local   /bin/login
+diff --git a/src/plugins/vbng/etc/radiusclient.conf.in b/src/plugins/vbng/etc/radiusclient.conf.in
+new file mode 100644
+index 00000000..fdf62e6d
+--- /dev/null
++++ b/src/plugins/vbng/etc/radiusclient.conf.in
+@@ -0,0 +1,92 @@
++# General settings
++
++# specify which authentication comes first respectively which
++# authentication is used. possible values are: "radius" and "local".
++# if you specify "radius,local" then the RADIUS server is asked
++# first then the local one. if only one keyword is specified only
++# this server is asked.
++auth_order    radius,local
++
++# maximum login tries a user has
++login_tries   4
++
++# timeout for all login tries
++# if this time is exceeded the user is kicked out
++login_timeout 60
++
++# name of the nologin file which when it exists disables logins.
++# it may be extended by the ttyname which will result in
++# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
++# logins on /dev/ttyS2)
++nologin /etc/nologin
++
++# name of the issue file. it's only display when no username is passed
++# on the radlogin command line
++issue @pkgsysconfdir@/issue
++
++# RADIUS settings
++
++# RADIUS server to use for authentication requests. this config
++# item can appear more then one time. if multiple servers are
++# defined they are tried in a round robin fashion if one
++# server is not answering.
++# optionally you can specify a the port number on which is remote
++# RADIUS listens separated by a colon from the hostname. if
++# no port is specified /etc/services is consulted of the radius
++# service. if this fails also a compiled in default is used.
++authserver    localhost
++
++# RADIUS server to use for accouting requests. All that I
++# said for authserver applies, too. 
++#
++acctserver    localhost
++
++# file holding shared secrets used for the communication
++# between the RADIUS client and server
++servers               @pkgsysconfdir@/servers
++
++# dictionary of allowed attributes and values
++# just like in the normal RADIUS distributions
++dictionary    @pkgsysconfdir@/dictionary
++
++# program to call for a RADIUS authenticated login
++login_radius  @sbindir@/login.radius
++
++# file which holds sequence number for communication with the
++# RADIUS server
++seqfile               /var/run/radius.seq
++
++# file which specifies mapping between ttyname and NAS-Port attribute
++mapfile               @pkgsysconfdir@/port-id-map
++
++# default authentication realm to append to all usernames if no
++# realm was explicitly specified by the user
++# the radiusd directly form Livingston doesnt use any realms, so leave
++# it blank then
++default_realm
++
++# time to wait for a reply from the RADIUS server
++radius_timeout        10
++
++# resend request this many times before trying the next server
++radius_retries        3
++
++# The length of time in seconds that we skip a nonresponsive RADIUS
++# server for transaction requests.  Server(s) being in the "dead" state
++# are tried only after all other non-dead servers have been tried and
++# failed or timeouted.  The deadtime interval starts when the server
++# does not respond to an authentication/accounting request transmissions. 
++# When the interval expires, the "dead" server would be re-tried again,
++# and if it's still down then it will be considered "dead" for another
++# such interval and so on. This option is no-op if there is only one
++# server in the list. Set to 0 in order to disable the feature.
++radius_deadtime       0
++
++# local address from which radius packets have to be sent
++bindaddr *
++
++# LOCAL settings
++
++# program to execute for local login
++# it must support the -f flag for preauthenticated login
++login_local   /bin/login
+diff --git a/src/plugins/vbng/etc/servers b/src/plugins/vbng/etc/servers
+new file mode 100644
+index 00000000..50eddd39
+--- /dev/null
++++ b/src/plugins/vbng/etc/servers
+@@ -0,0 +1,10 @@
++## Server Name or Client/Server pair          Key             
++## ----------------                           ---------------
++#
++#portmaster.elemental.net                     hardlyasecret
++#portmaster2.elemental.net                    donttellanyone
++#
++## uncomment the following line for simple testing of radlogin
++## with freeradius-server
++#
++#localhost/localhost                          testing123
+diff --git a/src/plugins/vbng/include/freeradius-client.h b/src/plugins/vbng/include/freeradius-client.h
+new file mode 100644
+index 00000000..96c75460
+--- /dev/null
++++ b/src/plugins/vbng/include/freeradius-client.h
+@@ -0,0 +1,528 @@
++/*
++ * $Id: freeradius-client.h,v 1.18 2010/06/15 09:22:51 aland Exp $
++ *
++ * Copyright (C) 1995,1996,1997,1998 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#ifndef FREERADIUS_CLIENT_H
++#define FREERADIUS_CLIENT_H
++
++#ifdef CP_DEBUG
++#define               DEBUG(args, ...)        rc_log(## args)
++#else
++#define               DEBUG(args, ...)        ;
++#endif
++
++#include      <sys/types.h>
++/*
++ * Include for C99 uintX_t defines is stdint.h on most systems.  Solaris uses
++ * inttypes.h instead.  Comment out the stdint include if you get an error,
++ * and uncomment the inttypes.h include.
++ */
++#include      <stdint.h>
++/* #include   <inttypes.h> */
++#include      <stdio.h>
++#include      <time.h>
++
++#undef __BEGIN_DECLS
++#undef __END_DECLS
++#ifdef __cplusplus
++# define __BEGIN_DECLS extern "C" {
++# define __END_DECLS }
++#else
++# define __BEGIN_DECLS /* empty */
++# define __END_DECLS /* empty */
++#endif
++
++#define AUTH_VECTOR_LEN               16
++#define AUTH_PASS_LEN         (3 * 16) /* multiple of 16 */
++#define AUTH_ID_LEN           64
++#define AUTH_STRING_LEN               253      /* maximum of 253 */
++
++#define       BUFFER_LEN              8192
++
++#define NAME_LENGTH           32
++#define       GETSTR_LENGTH           128     /* must be bigger than AUTH_PASS_LEN */
++
++#define       MAX_SECRET_LENGTH       (3 * 16) /* MUST be multiple of 16 */
++
++#define       VENDOR(x)               (((x) >> 16) & 0xffff)
++#define       ATTRID(x)               ((x) & 0xffff)
++
++#define PW_MAX_MSG_SIZE               4096
++
++/* codes for radius_buildreq, radius_getport, etc. */
++#define AUTH                  0
++#define ACCT                  1
++
++/* defines for config.c */
++
++#define SERVER_MAX 8
++
++#define AUTH_LOCAL_FST        (1<<0)
++#define AUTH_RADIUS_FST (1<<1)
++#define AUTH_LOCAL_SND  (1<<2)
++#define AUTH_RADIUS_SND (1<<3)
++
++typedef struct server {
++      int max;
++      char *name[SERVER_MAX];
++      uint16_t port[SERVER_MAX];
++      char *secret[SERVER_MAX];
++      double deadtime_ends[SERVER_MAX];
++} SERVER;
++
++typedef struct pw_auth_hdr
++{
++      uint8_t          code;
++      uint8_t          id;
++      uint16_t         length;
++      uint8_t          vector[AUTH_VECTOR_LEN];
++      uint8_t          data[2];
++} AUTH_HDR;
++
++struct rc_conf
++{
++      struct _option          *config_options;
++      uint32_t                        this_host_ipaddr;
++      uint32_t                        *this_host_bind_ipaddr;
++      struct map2id_s         *map2id_list;
++      struct dict_attr        *dictionary_attributes;
++      struct dict_value       *dictionary_values;
++      struct dict_vendor      *dictionary_vendors;
++      char                    buf[GETSTR_LENGTH];
++      char                    buf1[14];
++      char                    ifname[512];
++};
++
++typedef struct rc_conf rc_handle;
++
++#define AUTH_HDR_LEN                  20
++#define CHAP_VALUE_LENGTH             16
++
++#define PW_AUTH_UDP_PORT              1645
++#define PW_ACCT_UDP_PORT              1646
++
++#define PW_TYPE_STRING                        0
++#define PW_TYPE_INTEGER                       1
++#define PW_TYPE_IPADDR                        2
++#define PW_TYPE_DATE                  3
++#define PW_TYPE_IPV6ADDR              4
++#define PW_TYPE_IPV6PREFIX            5
++
++/* standard RADIUS codes */
++
++#define       PW_ACCESS_REQUEST               1
++#define       PW_ACCESS_ACCEPT                2
++#define       PW_ACCESS_REJECT                3
++#define       PW_ACCOUNTING_REQUEST           4
++#define       PW_ACCOUNTING_RESPONSE          5
++#define       PW_ACCOUNTING_STATUS            6
++#define       PW_PASSWORD_REQUEST             7
++#define       PW_PASSWORD_ACK                 8
++#define       PW_PASSWORD_REJECT              9
++#define       PW_ACCOUNTING_MESSAGE           10
++#define       PW_ACCESS_CHALLENGE             11
++#define       PW_STATUS_SERVER                12
++#define       PW_STATUS_CLIENT                13
++
++
++/* standard RADIUS attribute-value pairs */
++
++#define       PW_USER_NAME                    1       /* string */
++#define       PW_USER_PASSWORD                2       /* string */
++#define       PW_CHAP_PASSWORD                3       /* string */
++#define       PW_NAS_IP_ADDRESS               4       /* ipaddr */
++#define       PW_NAS_PORT                     5       /* integer */
++#define       PW_SERVICE_TYPE                 6       /* integer */
++#define       PW_FRAMED_PROTOCOL              7       /* integer */
++#define       PW_FRAMED_IP_ADDRESS            8       /* ipaddr */
++#define       PW_FRAMED_IP_NETMASK            9       /* ipaddr */
++#define       PW_FRAMED_ROUTING               10      /* integer */
++#define       PW_FILTER_ID                    11      /* string */
++#define       PW_FRAMED_MTU                   12      /* integer */
++#define       PW_FRAMED_COMPRESSION           13      /* integer */
++#define       PW_LOGIN_IP_HOST                14      /* ipaddr */
++#define       PW_LOGIN_SERVICE                15      /* integer */
++#define       PW_LOGIN_PORT                   16      /* integer */
++#define       PW_OLD_PASSWORD                 17      /* string */ /* deprecated */
++#define       PW_REPLY_MESSAGE                18      /* string */
++#define       PW_LOGIN_CALLBACK_NUMBER        19      /* string */
++#define       PW_FRAMED_CALLBACK_ID           20      /* string */
++#define       PW_EXPIRATION                   21      /* date */ /* deprecated */
++#define       PW_FRAMED_ROUTE                 22      /* string */
++#define       PW_FRAMED_IPX_NETWORK           23      /* integer */
++#define       PW_STATE                        24      /* string */
++#define       PW_CLASS                        25      /* string */
++#define       PW_VENDOR_SPECIFIC              26      /* string */
++#define       PW_SESSION_TIMEOUT              27      /* integer */
++#define       PW_IDLE_TIMEOUT                 28      /* integer */
++#define       PW_TERMINATION_ACTION           29      /* integer */
++#define       PW_CALLED_STATION_ID            30      /* string */
++#define       PW_CALLING_STATION_ID           31      /* string */
++#define       PW_NAS_IDENTIFIER               32      /* string */
++#define       PW_PROXY_STATE                  33      /* string */
++#define       PW_LOGIN_LAT_SERVICE            34      /* string */
++#define       PW_LOGIN_LAT_NODE               35      /* string */
++#define       PW_LOGIN_LAT_GROUP              36      /* string */
++#define       PW_FRAMED_APPLETALK_LINK        37      /* integer */
++#define       PW_FRAMED_APPLETALK_NETWORK     38      /* integer */
++#define       PW_FRAMED_APPLETALK_ZONE        39      /* string */
++#define       PW_EVENT_TIMESTAMP              55      /* integer */
++#define       PW_CHAP_CHALLENGE               60      /* string */
++#define       PW_NAS_PORT_TYPE                61      /* integer */
++#define       PW_PORT_LIMIT                   62      /* integer */
++#define PW_LOGIN_LAT_PORT               63      /* string */
++#define PW_CONNECT_INFO                 77      /* string */
++#define PW_MESSAGE_AUTHENTICATOR        80      /* string */
++
++/* RFC3162 IPv6 attributes */
++
++#define PW_NAS_IPV6_ADDRESS             95      /* string */
++#define PW_FRAMED_INTERFACE_ID          96      /* string */
++#define PW_FRAMED_IPV6_PREFIX           97      /* string */
++#define PW_LOGIN_IPV6_HOST              98      /* string */
++#define PW_FRAMED_IPV6_ROUTE            99      /* string */
++#define PW_FRAMED_IPV6_POOL             100     /* string */
++
++/* RFC6911 IPv6 attributes */
++#define PW_FRAMED_IPV6_ADDRESS                168     /* ipaddr6 */
++#define PW_DNS_SERVER_IPV6_ADDRESS    169     /* ipaddr6 */
++#define PW_ROUTE_IPV6_INFORMATION     170     /* ipv6prefix */
++
++/*    Accounting */
++
++#define       PW_ACCT_STATUS_TYPE             40      /* integer */
++#define       PW_ACCT_DELAY_TIME              41      /* integer */
++#define       PW_ACCT_INPUT_OCTETS            42      /* integer */
++#define       PW_ACCT_OUTPUT_OCTETS           43      /* integer */
++#define       PW_ACCT_SESSION_ID              44      /* string */
++#define       PW_ACCT_AUTHENTIC               45      /* integer */
++#define       PW_ACCT_SESSION_TIME            46      /* integer */
++#define       PW_ACCT_INPUT_PACKETS           47      /* integer */
++#define       PW_ACCT_OUTPUT_PACKETS          48      /* integer */
++#define PW_ACCT_TERMINATE_CAUSE               49      /* integer */
++#define PW_ACCT_MULTI_SESSION_ID      50      /* string */
++#define PW_ACCT_LINK_COUNT            51      /* integer */
++#define PW_ACCT_INPUT_GIGAWORDS               52      /* integer */
++#define PW_ACCT_OUTPUT_GIGAWORDS      53      /* integer */
++
++/*    Experimental SIP-specific attributes (draft-sterman-aaa-sip-00.txt etc) */
++
++#define       PW_DIGEST_RESPONSE              206     /* string */
++#define       PW_DIGEST_ATTRIBUTES            207     /* string */
++#define       PW_DIGEST_REALM                 1063    /* string */
++#define       PW_DIGEST_NONCE                 1064    /* string */
++#define       PW_DIGEST_METHOD                1065    /* string */
++#define       PW_DIGEST_URI                   1066    /* string */
++#define       PW_DIGEST_QOP                   1067    /* string */
++#define       PW_DIGEST_ALGORITHM             1068    /* string */
++#define       PW_DIGEST_BODY_DIGEST           1069    /* string */
++#define       PW_DIGEST_CNONCE                1070    /* string */
++#define       PW_DIGEST_NONCE_COUNT           1071    /* string */
++#define       PW_DIGEST_USER_NAME             1072    /* string */
++
++/*    Merit Experimental Extensions */
++
++#define PW_USER_ID                      222     /* string */
++#define PW_USER_REALM                   223     /* string */
++
++/*    Integer Translations */
++
++/*    SERVICE TYPES   */
++
++#define       PW_LOGIN                        1
++#define       PW_FRAMED                       2
++#define       PW_CALLBACK_LOGIN               3
++#define       PW_CALLBACK_FRAMED              4
++#define       PW_OUTBOUND                     5
++#define       PW_ADMINISTRATIVE               6
++#define PW_NAS_PROMPT                   7
++#define PW_AUTHENTICATE_ONLY          8
++#define PW_CALLBACK_NAS_PROMPT          9
++
++/*    FRAMED PROTOCOLS        */
++
++#define       PW_PPP                          1
++#define       PW_SLIP                         2
++#define PW_ARA                          3
++#define PW_GANDALF                      4
++#define PW_XYLOGICS                     5
++
++/*    FRAMED ROUTING VALUES   */
++
++#define       PW_NONE                         0
++#define       PW_BROADCAST                    1
++#define       PW_LISTEN                       2
++#define       PW_BROADCAST_LISTEN             3
++
++/*    FRAMED COMPRESSION TYPES        */
++
++#define       PW_VAN_JACOBSON_TCP_IP          1
++#define       PW_IPX_HEADER_COMPRESSION       2
++
++/*    LOGIN SERVICES  */
++
++#define PW_TELNET                       0
++#define PW_RLOGIN                       1
++#define PW_TCP_CLEAR                    2
++#define PW_PORTMASTER                   3
++#define PW_LAT                          4
++#define PW_X25_PAD                      5
++#define PW_X25_T3POS                    6
++
++/*    TERMINATION ACTIONS     */
++
++#define       PW_DEFAULT                      0
++#define       PW_RADIUS_REQUEST               1
++
++/*    PROHIBIT PROTOCOL  */
++
++#define PW_DUMB               0       /* 1 and 2 are defined in FRAMED PROTOCOLS */
++#define PW_AUTH_ONLY  3
++#define PW_ALL                255
++
++/*    ACCOUNTING STATUS TYPES    */
++
++#define PW_STATUS_START               1
++#define PW_STATUS_STOP                2
++#define PW_STATUS_ALIVE               3
++#define PW_STATUS_MODEM_START 4
++#define PW_STATUS_MODEM_STOP  5
++#define PW_STATUS_CANCEL      6
++#define PW_ACCOUNTING_ON      7
++#define PW_ACCOUNTING_OFF     8
++
++/*      ACCOUNTING TERMINATION CAUSES   */
++
++#define PW_USER_REQUEST         1
++#define PW_LOST_CARRIER         2
++#define PW_LOST_SERVICE         3
++#define PW_ACCT_IDLE_TIMEOUT    4
++#define PW_ACCT_SESSION_TIMEOUT 5
++#define PW_ADMIN_RESET          6
++#define PW_ADMIN_REBOOT         7
++#define PW_PORT_ERROR           8
++#define PW_NAS_ERROR            9
++#define PW_NAS_REQUEST          10
++#define PW_NAS_REBOOT           11
++#define PW_PORT_UNNEEDED        12
++#define PW_PORT_PREEMPTED       13
++#define PW_PORT_SUSPENDED       14
++#define PW_SERVICE_UNAVAILABLE  15
++#define PW_CALLBACK             16
++#define PW_USER_ERROR           17
++#define PW_HOST_REQUEST         18
++
++/*     NAS PORT TYPES    */
++
++#define PW_ASYNC              0
++#define PW_SYNC                       1
++#define PW_ISDN_SYNC          2
++#define PW_ISDN_SYNC_V120     3
++#define PW_ISDN_SYNC_V110     4
++#define PW_VIRTUAL            5
++
++/*       AUTHENTIC TYPES */
++#define PW_RADIUS     1
++#define PW_LOCAL      2
++#define PW_REMOTE     3
++
++/* Server data structures */
++
++typedef struct dict_attr
++{
++      char              name[NAME_LENGTH + 1];        /* attribute name */
++      int               value;                        /* attribute index */
++      int               type;                         /* string, int, etc. */
++      struct dict_attr *next;
++} DICT_ATTR;
++
++typedef struct dict_value
++{
++      char               attrname[NAME_LENGTH +1];
++      char               name[NAME_LENGTH + 1];
++      int                value;
++      struct dict_value *next;
++} DICT_VALUE;
++
++typedef struct dict_vendor
++{
++      char               vendorname[NAME_LENGTH +1];
++      int                vendorpec;
++      struct dict_vendor *next;
++} DICT_VENDOR;
++
++typedef struct value_pair
++{
++      char               name[NAME_LENGTH + 1];
++      int                attribute;
++      int                type;
++      uint32_t           lvalue;
++      char               strvalue[AUTH_STRING_LEN + 1];
++      struct value_pair *next;
++} VALUE_PAIR;
++
++/* don't change this, as it has to be the same as in the Merit radiusd code */
++#define MGMT_POLL_SECRET      "Hardlyasecret"
++
++/*    Define return codes from "SendServer" utility */
++
++#define BADRESP_RC    -2
++#define ERROR_RC      -1
++#define OK_RC         0
++#define TIMEOUT_RC    1
++#define REJECT_RC     2
++
++typedef struct send_data /* Used to pass information to sendserver() function */
++{
++      uint8_t        code;            /* RADIUS packet code */
++      uint8_t        seq_nbr;         /* Packet sequence number */
++      char           *server;         /* Name/addrress of RADIUS server */
++      int            svc_port;        /* RADIUS protocol destination port */
++      char           *secret;         /* Shared secret of RADIUS server */
++      int            timeout;         /* Session timeout in seconds */
++      int            retries;
++      VALUE_PAIR     *send_pairs;     /* More a/v pairs to send */
++      VALUE_PAIR     *receive_pairs;  /* Where to place received a/v pairs */
++} SEND_DATA;
++
++#ifndef MIN
++#define MIN(a, b)     ((a) < (b) ? (a) : (b))
++#endif
++#ifndef MAX
++#define MAX(a, b)     ((a) > (b) ? (a) : (b))
++#endif
++
++#ifndef PATH_MAX
++#define PATH_MAX      1024
++#endif
++
++typedef struct env
++{
++      int maxsize, size;
++      char **env;
++} ENV;
++
++#define ENV_SIZE      128
++
++__BEGIN_DECLS
++
++/*    Function prototypes     */
++
++/*    avpair.c                */
++
++VALUE_PAIR *rc_avpair_add(rc_handle const *, VALUE_PAIR **, int, void const *, int, int);
++int rc_avpair_assign(VALUE_PAIR *, void const *, int);
++VALUE_PAIR *rc_avpair_new(rc_handle const *, int, void const *, int, int);
++VALUE_PAIR *rc_avpair_gen(rc_handle const *, VALUE_PAIR *, unsigned char const *, int, int);
++VALUE_PAIR *rc_avpair_get(VALUE_PAIR *, int, int);
++void rc_avpair_insert(VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *);
++void rc_avpair_free(VALUE_PAIR *);
++int rc_avpair_parse(rc_handle const *, char const *, VALUE_PAIR **);
++int rc_avpair_tostr(rc_handle const *, VALUE_PAIR *, char *, int, char *, int);
++char *rc_avpair_log(rc_handle const *, VALUE_PAIR *, char *buf, size_t buf_len);
++VALUE_PAIR *rc_avpair_readin(rc_handle const *, FILE *);
++
++/*    buildreq.c              */
++
++void rc_buildreq(rc_handle const *, SEND_DATA *, int, char *, unsigned short, char *, int, int);
++unsigned char rc_get_id();
++int rc_auth(rc_handle *, uint32_t, VALUE_PAIR *, VALUE_PAIR **, char *);
++int rc_auth_proxy(rc_handle *, VALUE_PAIR *, VALUE_PAIR **, char *);
++int rc_acct(rc_handle *, uint32_t, VALUE_PAIR *);
++int rc_acct_proxy(rc_handle *, VALUE_PAIR *);
++int rc_check(rc_handle *, char *, char *, unsigned short, char *);
++
++int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
++    char *msg, int add_nas_port, int request_type);
++
++/*    clientid.c              */
++
++int rc_read_mapfile(rc_handle *, char const *);
++uint32_t rc_map2id(rc_handle const *, char const *);
++void rc_map2id_free(rc_handle *);
++
++/*    config.c                */
++
++rc_handle *rc_read_config(char const *);
++char *rc_conf_str(rc_handle const *, char const *);
++int rc_conf_int(rc_handle const *, char const *);
++SERVER *rc_conf_srv(rc_handle const *, char const *);
++int rc_find_server(rc_handle const *, char const *, uint32_t *, char *);
++void rc_config_free(rc_handle *);
++int rc_add_config(rc_handle *, char const *, char const *, char const *, int);
++rc_handle *rc_config_init(rc_handle *);
++int test_config(rc_handle const *, char const *);
++
++/*    dict.c                  */
++
++int rc_read_dictionary(rc_handle *, char const *);
++DICT_ATTR *rc_dict_getattr(rc_handle const *, int);
++DICT_ATTR *rc_dict_findattr(rc_handle const *, char const *);
++DICT_VALUE *rc_dict_findval(rc_handle const *, char const *);
++DICT_VENDOR *rc_dict_findvend(rc_handle const *, char const *);
++DICT_VENDOR *rc_dict_getvend(rc_handle const *, int);
++DICT_VALUE * rc_dict_getval(rc_handle const *, uint32_t, char const *);
++void rc_dict_free(rc_handle *);
++
++/*    ip_util.c               */
++
++struct hostent *rc_gethostbyname(char const *);
++struct hostent *rc_gethostbyaddr(char const *, size_t, int);
++uint32_t rc_get_ipaddr(char const *);
++int rc_good_ipaddr(char const *);
++char const *rc_ip_hostname(uint32_t);
++unsigned short rc_getport(int);
++int rc_own_hostname(char *, int);
++uint32_t rc_own_ipaddress(rc_handle *);
++uint32_t rc_own_bind_ipaddress(rc_handle *);
++struct sockaddr;
++int rc_get_srcaddr(struct sockaddr *, struct sockaddr *);
++
++
++/*    log.c                   */
++
++void rc_openlog(char const *);
++void rc_log(int, char const *, ...);
++
++/*    sendserver.c            */
++
++int rc_send_server(rc_handle *, SEND_DATA *, char *);
++
++/*    util.c                  */
++
++void rc_str2tm(char const *, struct tm *);
++char *rc_getifname(rc_handle *, char const *);
++char *rc_getstr(rc_handle *, char const *, int);
++void rc_mdelay(int);
++char *rc_mksid(rc_handle *);
++rc_handle *rc_new(void);
++void rc_destroy(rc_handle *);
++char *rc_fgetln(FILE *, size_t *);
++double rc_getctime(void);
++
++/*    env.c                   */
++
++struct env *rc_new_env(int);
++void rc_free_env(struct env *);
++int rc_add_env(struct env *, char const *, char const *);
++int rc_import_env(struct env *, char const **);
++
++/* md5.c                      */
++
++void rc_md5_calc(unsigned char *, unsigned char const *, unsigned int);
++
++__END_DECLS
++
++#endif /* FREERADIUS_CLIENT_H */
+diff --git a/src/plugins/vbng/include/includes.h b/src/plugins/vbng/include/includes.h
+new file mode 100644
+index 00000000..908f0e74
+--- /dev/null
++++ b/src/plugins/vbng/include/includes.h
+@@ -0,0 +1,182 @@
++/*
++ * $Id: includes.h,v 1.6 2007/06/21 18:07:22 cparker Exp $
++ *
++ * Copyright (C) 1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include "config.h"
++
++/* AIX requires this to be the first thing in the file.  */
++#ifndef __GNUC__
++# if HAVE_ALLOCA_H
++#  include <alloca.h>
++# else
++#  ifdef _AIX
++#   pragma alloca
++#  else
++#   ifndef alloca /* predefined by HP cc +Olibcalls */
++     char *alloca ();
++#   endif
++#  endif
++# endif
++#endif
++
++#include <sys/types.h>
++
++#include <ctype.h>
++#include <stdio.h>
++#include <errno.h>
++
++#ifdef HAVE_NETDB_H
++#include <netdb.h>
++#endif
++
++#ifdef HAVE_SYSLOG_H
++#include <syslog.h>
++#endif
++
++#ifdef STDC_HEADERS
++# include <stdlib.h>
++# include <string.h>
++# include <stdarg.h>
++#else
++# include <stdarg.h>
++# ifndef HAVE_STRCHR
++#  define strchr index
++#  define strrchr rindex
++# endif
++#endif
++
++/* I realize that this is ugly and unsafe.. :( */
++#ifndef HAVE_SNPRINTF
++# define snprintf(buf, len, format, ...) sprintf(buf, format, __VA_ARGS__)
++#endif
++#ifndef HAVE_VSNPRINTF
++# define vsnprintf(buf, len, format, ap) vsprintf(buf, format, ap)
++#endif
++
++#ifdef HAVE_UNISTD_H
++# include <unistd.h>
++#endif /* HAVE_UNISTD_H */
++
++#ifdef HAVE_FCNTL_H
++# include <fcntl.h>
++#endif
++
++#ifdef HAVE_SYS_FCNTL_H
++# include <sys/fcntl.h>
++#endif
++
++#ifdef HAVE_SYS_FILE_H
++# include <sys/file.h>
++#endif
++
++#ifdef HAVE_SYS_STAT_H
++# include <sys/stat.h>
++#endif
++
++#ifdef HAVE_SYS_UTSNAME_H
++# include <sys/utsname.h>
++#endif
++
++#ifdef HAVE_SYS_IOCTL_H
++# include <sys/ioctl.h>
++#endif
++
++#ifdef HAVE_CRYPT_H
++# include <crypt.h>
++#endif
++
++#ifdef HAVE_LIMITS_H
++# include <limits.h>
++#endif
++
++#ifdef HAVE_TERMIOS_H
++# include <termios.h>
++#endif
++
++#ifndef PATH_MAX
++#define PATH_MAX        1024
++#endif
++
++#ifndef UCHAR_MAX
++# ifdef  __STDC__
++#  define UCHAR_MAX       255U
++# else
++#  define UCHAR_MAX       255
++# endif
++#endif
++
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif
++
++#ifdef HAVE_SYS_SOCKET_H
++#include <sys/socket.h>
++#endif
++
++#ifdef HAVE_NETINET_IN_H
++#include <netinet/in.h>
++#endif
++
++#ifdef HAVE_ARPA_INET_H
++#include <arpa/inet.h>
++#endif
++
++#if defined(HAVE_SIGNAL_H)
++# include <signal.h>
++#endif
++#if defined(HAVE_SYS_SIGNAL_H)
++# include <sys/signal.h>
++#endif
++
++#ifdef NEED_SIG_PROTOTYPES
++int sigemptyset(sigset_t *);
++int sigaddset(sigset_t *, int);
++int sigprocmask (int, sigset_t *, sigset_t *);
++#endif
++
++#if HAVE_GETOPT_H
++# include <getopt.h>
++#endif
++
++#if defined(HAVE_SHADOW_H) && defined(HAVE_SHADOW_PASSWORDS)
++# include <shadow.h>
++#endif
++
++#if TIME_WITH_SYS_TIME
++# include <sys/time.h>
++# include <time.h>
++#else
++# if HAVE_SYS_TIME_H
++#  include <sys/time.h>
++# else
++#  include <time.h>
++# endif
++#endif
++
++/*
++ * prefer srandom/random over srand/rand as there generator has a
++ * better distribution of the numbers on certain systems.
++ * on Linux both generators are identical.
++ */
++#ifndef HAVE_RANDOM
++# ifdef HAVE_RAND
++# define srandom        srand
++# define random         rand
++# endif
++#endif
++
++/* rlib/lock.c */
++int do_lock_exclusive(FILE *);
++int do_unlock(FILE *);
+diff --git a/src/plugins/vbng/include/messages.h b/src/plugins/vbng/include/messages.h
+new file mode 100644
+index 00000000..9a5f0e81
+--- /dev/null
++++ b/src/plugins/vbng/include/messages.h
+@@ -0,0 +1,53 @@
++/*
++ * $Id: messages.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $
++ *
++ * Copyright (C) 1995,1996 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++/*
++ * Only messages that the user gets under normal use are in here.
++ * Error messages and such are still in the source code.
++ */
++
++#ifndef MESSAGES_H
++#define MESSAGES_H
++
++/* radlogin.c */
++
++#define SC_LOGIN       "login: "
++#define SC_PASSWORD    "Password: "
++
++#define SC_TIMEOUT     "\r\nlogin timed out after %d seconds. Bye.\r\n"
++#define SC_EXCEEDED    "Maximum login tries exceeded. Go away!\r\n"
++
++#define SC_RADIUS_OK   "RADIUS: Authentication OK\r\n"
++#define SC_RADIUS_FAILED "RADIUS: Authentication failure\r\n"
++
++#define SC_LOCAL_OK    "local: Authentication OK\r\n"
++#define SC_LOCAL_FAILED        "local: Authentication failure\r\n"
++#define SC_NOLOGIN     "\r\nSystem closed for maintenance. Try again later...\r\n"
++
++#define SC_SERVER_REPLY        "RADIUS: %s"
++
++#define SC_DEFAULT_ISSUE "(\\I)\r\n\r\n\\S \\R (\\N) (port \\L)\r\n\r\n"
++
++/* radacct.c */
++
++#define SC_ACCT_OK     "RADIUS accounting OK\r\n"
++#define SC_ACCT_FAILED         "RADIUS accounting failed (RC=%i)\r\n"
++
++/* radstatus.c */
++
++#define SC_STATUS_FAILED      "RADIUS: Status failure\r\n"
++
++#endif /* MESSAGES_H */
+diff --git a/src/plugins/vbng/include/pathnames.h b/src/plugins/vbng/include/pathnames.h
+new file mode 100644
+index 00000000..0256d473
+--- /dev/null
++++ b/src/plugins/vbng/include/pathnames.h
+@@ -0,0 +1,28 @@
++/*
++ * $Id: pathnames.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $
++ *
++ * Copyright (C) 1995,1996 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#ifndef PATHNAMES_H
++#define PATHNAMES_H
++
++#define _PATH_DEV_URANDOM     "/dev/urandom"          /* Linux only */
++#define _PATH_ETC_ISSUE               "/etc/issue"
++
++/* normally defined in the Makefile */
++#ifndef _PATH_ETC_RADIUSCLIENT_CONF
++#define _PATH_ETC_RADIUSCLIENT_CONF       "/etc/radiusclient.conf"
++#endif
++
++#endif /* PATHNAMES_H */
+diff --git a/src/plugins/vbng/lib/avpair.c b/src/plugins/vbng/lib/avpair.c
+new file mode 100644
+index 00000000..8ce2a8ec
+--- /dev/null
++++ b/src/plugins/vbng/lib/avpair.c
+@@ -0,0 +1,874 @@
++/*
++ * $Id: avpair.c,v 1.26 2010/06/15 09:22:52 aland Exp $
++ *
++ * Copyright (C) 1995 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++/*
++ * Function: rc_avpair_add
++ *
++ * Purpose: add an attribute-value pair to the given list.
++ *
++ * Returns: pointer to added a/v pair upon success, NULL pointer upon failure.
++ *
++ * Remarks: Always appends the new pair to the end of the list.
++ *
++ */
++
++VALUE_PAIR *rc_avpair_add (rc_handle const *rh, VALUE_PAIR **list, int attrid, void const *pval, int len, int vendorpec)
++{
++      VALUE_PAIR     *vp;
++
++      vp = rc_avpair_new (rh, attrid, pval, len, vendorpec);
++
++      if (vp != NULL)
++      {
++              rc_avpair_insert (list, NULL, vp);
++      }
++
++      return vp;
++
++}
++
++/*
++ * Function: rc_avpair_assign
++ *
++ * Purpose: assign the given value to an attribute-value pair.
++ *
++ * Returns:  0 on success,
++ *        -1 on failure.
++ *
++ */
++
++int rc_avpair_assign (VALUE_PAIR *vp, void const *pval, int len)
++{
++
++      switch (vp->type)
++      {
++              case PW_TYPE_STRING:
++                      if (len == -1)
++                              len = (uint32_t)strlen((char const *)pval);
++                      if (len > AUTH_STRING_LEN) {
++                              rc_log(LOG_ERR, "rc_avpair_assign: bad attribute length");
++                              return -1;
++                      }
++                      memcpy(vp->strvalue, (char const *)pval, len);
++                      vp->strvalue[len] = '\0';
++                      vp->lvalue = len;
++                      break;
++
++              case PW_TYPE_DATE:
++              case PW_TYPE_INTEGER:
++              case PW_TYPE_IPADDR:
++                      vp->lvalue = * (uint32_t *) pval;
++                      break;
++              case PW_TYPE_IPV6ADDR:
++                      if (len != 16) {
++                              rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 length");
++                              return -1;
++                      }
++                      memcpy(vp->strvalue, (char const *)pval, len);
++                      vp->lvalue = len;
++                      break;
++
++              case PW_TYPE_IPV6PREFIX:
++                      if (len < 2 || len > 18) {
++                              rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 prefix length");
++                              return -1;
++                      }
++                      memcpy(vp->strvalue, (char const *)pval, len);
++                      vp->lvalue = len;
++                      break;
++
++              default:
++                      rc_log(LOG_ERR, "rc_avpair_assign: unknown attribute %d", vp->type);
++                      return -1;
++      }
++      return 0;
++}
++
++/*
++ * Function: rc_avpair_new
++ *
++ * Purpose: make a new attribute-value pair with given parameters.
++ *
++ * Returns: pointer to generated a/v pair when successful, NULL when failure.
++ *
++ */
++
++VALUE_PAIR *rc_avpair_new (rc_handle const *rh, int attrid, void const *pval, int len, int vendorpec)
++{
++      VALUE_PAIR     *vp = NULL;
++      DICT_ATTR      *pda;
++
++      attrid = attrid | (vendorpec << 16);
++      if ((pda = rc_dict_getattr (rh, attrid)) == NULL)
++      {
++              rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid);
++              return NULL;
++      }
++      if (vendorpec != 0 && rc_dict_getvend(rh, vendorpec) == NULL)
++      {
++              rc_log(LOG_ERR,"rc_avpair_new: unknown Vendor-Id %d", vendorpec);
++              return NULL;
++      }
++      if ((vp = malloc (sizeof (VALUE_PAIR))) != NULL)
++      {
++              strncpy (vp->name, pda->name, sizeof (vp->name));
++              vp->attribute = attrid;
++              vp->next = NULL;
++              vp->type = pda->type;
++              if (rc_avpair_assign (vp, pval, len) == 0)
++              {
++                      /* XXX: Fix up Digest-Attributes */
++                      switch (vp->attribute) {
++                      case PW_DIGEST_REALM:
++                      case PW_DIGEST_NONCE:
++                      case PW_DIGEST_METHOD:
++                      case PW_DIGEST_URI:
++                      case PW_DIGEST_QOP:
++                      case PW_DIGEST_ALGORITHM:
++                      case PW_DIGEST_BODY_DIGEST:
++                      case PW_DIGEST_CNONCE:
++                      case PW_DIGEST_NONCE_COUNT:
++                      case PW_DIGEST_USER_NAME:
++                              /* overlapping! */
++                              if (vp->lvalue > AUTH_STRING_LEN - 2)
++                                      vp->lvalue = AUTH_STRING_LEN - 2;
++                              memmove(&vp->strvalue[2], &vp->strvalue[0], vp->lvalue);
++                              vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1;
++                              vp->lvalue += 2;
++                              vp->strvalue[1] = vp->lvalue;
++                              vp->strvalue[vp->lvalue] = '\0';
++                              vp->attribute = PW_DIGEST_ATTRIBUTES;
++                      default:
++                              break;
++                      }
++                      return vp;
++              }
++              free (vp);
++              vp = NULL;
++      }
++      else
++      {
++              rc_log(LOG_CRIT,"rc_avpair_new: out of memory");
++      }
++
++      return vp;
++}
++
++/*
++ *
++ * Function: rc_avpair_gen
++ *
++ * Purpose: takes attribute/value pairs from buffer and builds a
++ *        value_pair list using allocated memory. Uses recursion.
++ *
++ * Returns: value_pair list or NULL on failure
++ */
++
++VALUE_PAIR *
++rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr,
++    int length, int vendorpec)
++{
++      int attribute, attrlen, x_len;
++      unsigned char const *x_ptr;
++      uint32_t lvalue;
++      DICT_ATTR *attr;
++      VALUE_PAIR *rpair;
++      char buffer[(AUTH_STRING_LEN * 2) + 1];
++      /* For hex string conversion. */
++      char hex[3];
++
++      if (length < 2) {
++              rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
++                  "invalid length");
++              goto shithappens;
++      }
++      attrlen = ptr[1];
++      if (length < attrlen || attrlen < 2) {
++              rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
++                  "invalid length");
++              goto shithappens;
++      }
++
++      /* Advance to the next attribute and process recursively */
++      if (length != attrlen) {
++              pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen,
++                  vendorpec);
++              if (pair == NULL)
++                      return NULL;
++      }
++
++      /* Actual processing */
++      attribute = ptr[0] | (vendorpec << 16);
++      ptr += 2;
++      attrlen -= 2;
++
++      /* VSA */
++      if (attribute == PW_VENDOR_SPECIFIC) {
++              if (attrlen < 4) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received VSA "
++                          "attribute with invalid length");
++                      goto shithappens;
++              }
++              memcpy(&lvalue, ptr, 4);
++              vendorpec = ntohl(lvalue);
++              if (rc_dict_getvend(rh, vendorpec) == NULL) {
++                      /* Warn and skip over the unknown VSA */
++                      rc_log(LOG_WARNING, "rc_avpair_gen: received VSA "
++                          "attribute with unknown Vendor-Id %d", vendorpec);
++                      return pair;
++              }
++              /* Process recursively */
++              return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4,
++                  vendorpec);
++      }
++
++      /* Normal */
++      attr = rc_dict_getattr(rh, attribute);
++      if (attr == NULL) {
++              buffer[0] = '\0';       /* Initial length. */
++              x_ptr = ptr;
++              for (x_len = attrlen; x_len > 0; x_len--, x_ptr++) {
++                      snprintf(hex, sizeof(hex), "%2.2X", x_ptr[0]);
++                      strcat(buffer, hex);
++              }
++              if (vendorpec == 0) {
++                      rc_log(LOG_WARNING, "rc_avpair_gen: received "
++                          "unknown attribute %d of length %d: 0x%s",
++                          attribute, attrlen + 2, buffer);
++              } else {
++                      rc_log(LOG_WARNING, "rc_avpair_gen: received "
++                          "unknown VSA attribute %d, vendor %d of "
++                          "length %d: 0x%s", attribute & 0xffff,
++                          VENDOR(attribute), attrlen + 2, buffer);
++              }
++              goto shithappens;
++      }
++
++      rpair = malloc(sizeof(*rpair));
++      if (rpair == NULL) {
++              rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
++              goto shithappens;
++      }
++      memset(rpair, '\0', sizeof(*rpair));
++
++      /* Insert this new pair at the beginning of the list */
++      rpair->next = pair;
++      pair = rpair;
++      strcpy(pair->name, attr->name);
++      pair->attribute = attr->value;
++      pair->type = attr->type;
++
++      switch (attr->type) {
++      case PW_TYPE_STRING:
++              memcpy(pair->strvalue, (char *)ptr, (size_t)attrlen);
++              pair->strvalue[attrlen] = '\0';
++              pair->lvalue = attrlen;
++              break;
++
++      case PW_TYPE_INTEGER:
++              if (attrlen != 4) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received INT "
++                          "attribute with invalid length");
++                      goto shithappens;
++              }
++      case PW_TYPE_IPADDR:
++              if (attrlen != 4) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR"
++                          " attribute with invalid length");
++                      goto shithappens;
++              }
++              memcpy((char *)&lvalue, (char *)ptr, 4);
++              pair->lvalue = ntohl(lvalue);
++              break;
++      case PW_TYPE_IPV6ADDR:
++              if (attrlen != 16) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received IPV6ADDR"
++                          " attribute with invalid length");
++                      goto shithappens;
++              }
++              memcpy(pair->strvalue, (char *)ptr, 16);
++              pair->lvalue = attrlen;
++              break;
++      case PW_TYPE_IPV6PREFIX:
++              if (attrlen > 18 || attrlen < 2) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received IPV6PREFIX"
++                          " attribute with invalid length: %d", attrlen);
++                      goto shithappens;
++              }
++              memcpy(pair->strvalue, (char *)ptr, attrlen);
++              pair->lvalue = attrlen;
++              break;
++      case PW_TYPE_DATE:
++              if (attrlen != 4) {
++                      rc_log(LOG_ERR, "rc_avpair_gen: received DATE "
++                          "attribute with invalid length");
++                      goto shithappens;
++              }
++
++      default:
++              rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type",
++                  attr->name);
++              goto shithappens;
++      }
++      return pair;
++
++shithappens:
++      while (pair != NULL) {
++              rpair = pair->next;
++              free(pair);
++              pair = rpair;
++      }
++      return NULL;
++}
++
++/*
++ * Function: rc_avpair_get
++ *
++ * Purpose: Find the first attribute value-pair (which matches the given
++ *          attribute) from the specified value-pair list.
++ *
++ * Returns: found value_pair
++ *
++ */
++
++VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, int attrid, int vendorpec)
++{
++      for (; vp != NULL && !(ATTRID(vp->attribute) == ATTRID(attrid) &&
++          VENDOR(vp->attribute) == vendorpec); vp = vp->next)
++      {
++              continue;
++      }
++      return vp;
++}
++
++/*
++ * Function: rc_avpair_insert
++ *
++ * Purpose: Given the address of an existing list "a" and a pointer
++ *        to an entry "p" in that list, add the value pair "b" to
++ *        the "a" list after the "p" entry.  If "p" is NULL, add
++ *        the value pair "b" to the end of "a".
++ *
++ */
++
++void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b)
++{
++      VALUE_PAIR     *this_node = NULL;
++      VALUE_PAIR     *vp;
++
++      if (b->next != NULL)
++      {
++              rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next);
++              abort ();
++      }
++
++      if (*a == NULL)
++      {
++              *a = b;
++              return;
++      }
++
++      vp = *a;
++
++      if ( p == NULL) /* run to end of "a" list */
++      {
++              while (vp != NULL)
++              {
++                      this_node = vp;
++                      vp = vp->next;
++              }
++      }
++      else /* look for the "p" entry in the "a" list */
++      {
++              this_node = *a;
++              while (this_node != NULL)
++              {
++                      if (this_node == p)
++                      {
++                              break;
++                      }
++                      this_node = this_node->next;
++              }
++      }
++
++      b->next = this_node->next;
++      this_node->next = b;
++
++      return;
++}
++
++/*
++ * Function: rc_avpair_free
++ *
++ * Purpose: frees all value_pairs in the list
++ *
++ */
++
++void rc_avpair_free (VALUE_PAIR *pair)
++{
++      VALUE_PAIR     *next;
++
++      while (pair != NULL)
++      {
++              next = pair->next;
++              free (pair);
++              pair = next;
++      }
++}
++
++/*
++ * Function: rc_fieldcpy
++ *
++ * Purpose: Copy a data field from the buffer.  Advance the buffer
++ *          past the data field. Ensure that no more than len - 1
++ *          bytes are copied and that resulting string is terminated
++ *          with '\0'.
++ *
++ */
++
++static void
++rc_fieldcpy(char *string, char const **uptr, char const *stopat, size_t len)
++{
++      char const *ptr, *estring;
++
++      ptr = *uptr;
++      estring = string + len - 1;
++      if (*ptr == '"')
++      {
++              ptr++;
++              while (*ptr != '"' && *ptr != '\0' && *ptr != '\n')
++              {
++                      if (string < estring)
++                              *string++ = *ptr;
++                      ptr++;
++              }
++              if (*ptr == '"')
++              {
++                      ptr++;
++              }
++              *string = '\0';
++              *uptr = ptr;
++              return;
++      }
++
++      while (*ptr != '\0' && strchr(stopat, *ptr) == NULL)
++      {
++              if (string < estring)
++                      *string++ = *ptr;
++              ptr++;
++      }
++      *string = '\0';
++      *uptr = ptr;
++      return;
++}
++
++
++/*
++ * Function: rc_avpair_parse
++ *
++ * Purpose: parses the buffer to extract the attribute-value pairs.
++ *
++ * Returns: 0 = successful parse of attribute-value pair,
++ *       -1 = syntax (or other) error detected.
++ *
++ */
++
++#define PARSE_MODE_NAME               0
++#define PARSE_MODE_EQUAL      1
++#define PARSE_MODE_VALUE      2
++#define PARSE_MODE_INVALID    3
++
++int rc_avpair_parse (rc_handle const *rh, char const *buffer, VALUE_PAIR **first_pair)
++{
++      int             mode;
++      char            attrstr[AUTH_ID_LEN];
++      char            valstr[AUTH_STRING_LEN + 1], *p;
++      DICT_ATTR      *attr = NULL;
++      DICT_VALUE     *dval;
++      VALUE_PAIR     *pair;
++      VALUE_PAIR     *link;
++      struct tm      *tm;
++      time_t          timeval;
++
++      mode = PARSE_MODE_NAME;
++      while (*buffer != '\n' && *buffer != '\0')
++      {
++              if (*buffer == ' ' || *buffer == '\t')
++              {
++                      buffer++;
++                      continue;
++              }
++
++              switch (mode)
++              {
++                  case PARSE_MODE_NAME:               /* Attribute Name */
++                      rc_fieldcpy (attrstr, &buffer, " \t\n=,", sizeof(attrstr));
++                      if ((attr =
++                              rc_dict_findattr (rh, attrstr)) == NULL)
++                      {
++                              rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute");
++                              if (*first_pair) {
++                                      rc_avpair_free(*first_pair);
++                                      *first_pair = NULL;
++                              }
++                              return -1;
++                      }
++                      mode = PARSE_MODE_EQUAL;
++                      break;
++
++                  case PARSE_MODE_EQUAL:              /* Equal sign */
++                      if (*buffer == '=')
++                      {
++                              mode = PARSE_MODE_VALUE;
++                              buffer++;
++                      }
++                      else
++                      {
++                              rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign");
++                              if (*first_pair) {
++                                      rc_avpair_free(*first_pair);
++                                      *first_pair = NULL;
++                              }
++                              return -1;
++                      }
++                      break;
++
++                  case PARSE_MODE_VALUE:              /* Value */
++                      rc_fieldcpy (valstr, &buffer, " \t\n,", sizeof(valstr));
++
++                      if ((pair = malloc (sizeof (VALUE_PAIR))) == NULL)
++                      {
++                              rc_log(LOG_CRIT, "rc_avpair_parse: out of memory");
++                              if (*first_pair) {
++                                      rc_avpair_free(*first_pair);
++                                      *first_pair = NULL;
++                              }
++                              return -1;
++                      }
++                      strcpy (pair->name, attr->name);
++                      pair->attribute = attr->value;
++                      pair->type = attr->type;
++
++                      switch (pair->type)
++                      {
++
++                          case PW_TYPE_STRING:
++                              strcpy (pair->strvalue, valstr);
++                              pair->lvalue = (uint32_t)strlen(valstr);
++                              break;
++
++                          case PW_TYPE_INTEGER:
++                              if (isdigit (*valstr))
++                              {
++                                      pair->lvalue = atoi (valstr);
++                              }
++                              else
++                              {
++                                      if ((dval = rc_dict_findval (rh, valstr))
++                                                      == NULL)
++                                      {
++                                              rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr);
++                                              if (*first_pair) {
++                                                      rc_avpair_free(*first_pair);
++                                                      *first_pair = NULL;
++                                              }
++                                              free (pair);
++                                              return -1;
++                                      }
++                                      else
++                                      {
++                                              pair->lvalue = dval->value;
++                                      }
++                              }
++                              break;
++
++                          case PW_TYPE_IPADDR:
++                                pair->lvalue = rc_get_ipaddr(valstr);
++                              break;
++
++                          case PW_TYPE_IPV6ADDR:
++                              if (inet_pton(AF_INET6, valstr, pair->strvalue) == 0) {
++                                      rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 address %s", valstr);
++                                      free(pair);
++                                      return -1;
++                              }
++                              pair->lvalue = 16;
++                              break;
++
++                          case PW_TYPE_IPV6PREFIX:
++                              p = strchr(valstr, '/');
++                              if (p == NULL) {
++                                      rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr);
++                                      free(pair);
++                                      return -1;
++                              }
++                              *p = 0;
++                              p++;
++                              pair->strvalue[0] = 0;
++                              pair->strvalue[1] = atoi(p);
++
++                              if (inet_pton(AF_INET6, valstr, pair->strvalue+2) == 0) {
++                                      rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr);
++                                      free(pair);
++                                      return -1;
++                              }
++                              pair->lvalue = 2+16;
++                              break;
++
++                          case PW_TYPE_DATE:
++                              timeval = time (0);
++                              tm = localtime (&timeval);
++                              tm->tm_hour = 0;
++                              tm->tm_min = 0;
++                              tm->tm_sec = 0;
++                              rc_str2tm (valstr, tm);
++#ifdef TIMELOCAL
++                              pair->lvalue = (uint32_t) timelocal (tm);
++#else /* TIMELOCAL */
++                              pair->lvalue = (uint32_t) mktime (tm);
++#endif        /* TIMELOCAL */
++                              break;
++
++                          default:
++                              rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type);
++                              if (*first_pair) {
++                                      rc_avpair_free(*first_pair);
++                                      *first_pair = NULL;
++                              }
++                              free (pair);
++                              return -1;
++                      }
++
++                      /* XXX: Fix up Digest-Attributes */
++                      switch (pair->attribute) {
++                      case PW_DIGEST_REALM:
++                      case PW_DIGEST_NONCE:
++                      case PW_DIGEST_METHOD:
++                      case PW_DIGEST_URI:
++                      case PW_DIGEST_QOP:
++                      case PW_DIGEST_ALGORITHM:
++                      case PW_DIGEST_BODY_DIGEST:
++                      case PW_DIGEST_CNONCE:
++                      case PW_DIGEST_NONCE_COUNT:
++                      case PW_DIGEST_USER_NAME:
++                              /* overlapping! */
++                              if (pair->lvalue > AUTH_STRING_LEN - 2)
++                                      pair->lvalue = AUTH_STRING_LEN - 2;
++                              memmove(&pair->strvalue[2], &pair->strvalue[0], pair->lvalue);
++                              pair->strvalue[0] = pair->attribute - PW_DIGEST_REALM + 1;
++                              pair->lvalue += 2;
++                              pair->strvalue[1] = pair->lvalue;
++                              pair->strvalue[pair->lvalue] = '\0';
++                              pair->attribute = PW_DIGEST_ATTRIBUTES;
++                      }
++
++                      pair->next = NULL;
++
++                      if (*first_pair == NULL)
++                      {
++                              *first_pair = pair;
++                      }
++                      else
++                      {
++                              link = *first_pair;
++                              while (link->next != NULL)
++                              {
++                                      link = link->next;
++                              }
++                              link->next = pair;
++                      }
++
++                      mode = PARSE_MODE_NAME;
++                      break;
++
++                  default:
++                      mode = PARSE_MODE_NAME;
++                      break;
++              }
++      }
++      return 0;
++}
++
++/*
++ * Function: rc_avpair_tostr
++ *
++ * Purpose: Translate an av_pair into two strings
++ *
++ * Returns: 0 on success, -1 on failure
++ *
++ */
++
++int rc_avpair_tostr (rc_handle const *rh, VALUE_PAIR *pair, char *name, int ln, char *value, int lv)
++{
++      DICT_VALUE     *dval;
++      char            buffer[32];
++      struct in_addr  inad;
++      unsigned char         *ptr;
++
++      *name = *value = '\0';
++
++      if (!pair || pair->name[0] == '\0') {
++              rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty");
++              return -1;
++      }
++
++      strncpy(name, pair->name, (size_t) ln);
++
++      switch (pair->type)
++      {
++          case PW_TYPE_STRING:
++              lv--;
++              ptr = (unsigned char *) pair->strvalue;
++              if (pair->attribute == PW_DIGEST_ATTRIBUTES) {
++                      pair->strvalue[*(ptr + 1)] = '\0';
++                      ptr += 2;
++              }
++              while (*ptr != '\0')
++              {
++                      if (!(isprint (*ptr)))
++                      {
++                              snprintf (buffer, sizeof(buffer), "\\%03o", *ptr);
++                              strncat(value, buffer, (size_t) lv);
++                              lv -= 4;
++                              if (lv < 0) break;
++                      }
++                      else
++                      {
++                              strncat(value, (char *)ptr, 1);
++                              lv--;
++                              if (lv <= 0) break;
++                      }
++                      ptr++;
++              }
++              break;
++
++          case PW_TYPE_INTEGER:
++              dval = rc_dict_getval (rh, pair->lvalue, pair->name);
++              if (dval != NULL)
++              {
++                      strncpy(value, dval->name, (size_t) lv-1);
++              }
++              else
++              {
++                      snprintf(buffer, sizeof(buffer), "%ld", (long int)pair->lvalue);
++                      strncpy(value, buffer, (size_t) lv);
++              }
++              break;
++
++          case PW_TYPE_IPADDR:
++              inad.s_addr = htonl(pair->lvalue);
++              strncpy (value, inet_ntoa (inad), (size_t) lv-1);
++              break;
++
++          case PW_TYPE_IPV6ADDR:
++              if (inet_ntop(AF_INET6, pair->strvalue, value, lv-1) == NULL)
++                      return -1;
++              break;
++
++          case PW_TYPE_IPV6PREFIX: {
++              uint8_t ip[16];
++              uint8_t txt[48];
++              if (pair->lvalue < 2)
++                      return -1;
++
++              memset(ip, 0, sizeof(ip));
++              memcpy(ip, pair->strvalue+2, pair->lvalue-2);
++
++              if (inet_ntop(AF_INET6, ip, txt, sizeof(txt)) == NULL)
++                      return -1;
++              snprintf(value, lv-1, "%s/%u", txt, (unsigned)pair->strvalue[1]);
++
++              break;
++          }
++          case PW_TYPE_DATE:
++              strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S",
++                        gmtime ((time_t *) & pair->lvalue));
++              strncpy(value, buffer, lv-1);
++              break;
++
++          default:
++              rc_log(LOG_ERR, "rc_avpair_tostr: unknown attribute type %d", pair->type);
++              return -1;
++              break;
++      }
++
++      return 0;
++}
++
++/*
++ * Function: rc_avpair_log
++ *
++ * Purpose: format sequence of attribute value pairs into printable
++ * string. The caller should provide a storage buffer and the buffer length.
++ * Returns pointer to provided storage buffer.
++ *
++ */
++char *
++rc_avpair_log(rc_handle const *rh, VALUE_PAIR *pair, char *buf, size_t buf_len)
++{
++      size_t len, nlen;
++      VALUE_PAIR *vp;
++      char name[33], value[256];
++
++      len = 0;
++      for (vp = pair; vp != NULL; vp = vp->next) {
++              if (rc_avpair_tostr(rh, vp, name, sizeof(name), value,
++                  sizeof(value)) == -1)
++                      return NULL;
++              nlen = len + 32 + 3 + strlen(value) + 2 + 2;
++              if(nlen<buf_len-1) {
++                      sprintf(buf + len, "%-32s = '%s'\n", name, value);
++              } else return buf;
++              len = nlen - 1;
++      }
++      return buf;
++}
++
++/*
++ * Function: rc_avpair_readin
++ *
++ * Purpose: get a sequence of attribute value pairs from the file input
++ *        and make them into a list of value_pairs
++ *
++ */
++
++VALUE_PAIR *rc_avpair_readin(rc_handle const *rh, FILE *input)
++{
++      VALUE_PAIR *vp = NULL;
++      char buffer[1024], *q;
++
++      while (fgets(buffer, sizeof(buffer), input) != NULL)
++      {
++              q = buffer;
++
++              while(*q && isspace(*q)) q++;
++
++              if ((*q == '\n') || (*q == '#') || (*q == '\0'))
++                      continue;
++
++              if (rc_avpair_parse(rh, q, &vp) < 0) {
++                      rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer);
++                      rc_avpair_free(vp);
++                      return NULL;
++              }
++      }
++
++      return vp;
++}
+diff --git a/src/plugins/vbng/lib/buildreq.c b/src/plugins/vbng/lib/buildreq.c
+new file mode 100644
+index 00000000..a71b1f99
+--- /dev/null
++++ b/src/plugins/vbng/lib/buildreq.c
+@@ -0,0 +1,276 @@
++/*
++ * $Id: buildreq.c,v 1.17 2010/02/04 10:27:09 aland Exp $
++ *
++ * Copyright (C) 1995,1997 Lars Fenneberg
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++unsigned char rc_get_id();
++
++/*
++ * Function: rc_buildreq
++ *
++ * Purpose: builds a skeleton RADIUS request using information from the
++ *        config file.
++ *
++ */
++
++void rc_buildreq(rc_handle const *rh, SEND_DATA *data, int code, char *server, unsigned short port,
++               char *secret, int timeout, int retries)
++{
++      data->server = server;
++      data->secret = secret;
++      data->svc_port = port;
++      data->seq_nbr = rc_get_id();
++      data->timeout = timeout;
++      data->retries = retries;
++      data->code = code;
++}
++
++/*
++ * Function: rc_get_id
++ *
++ * Purpose: generate random id
++ *
++ */
++
++unsigned char rc_get_id()
++{
++      return (unsigned char)(random() & UCHAR_MAX);
++}
++
++/*
++ * Function: rc_aaa
++ *
++ * Purpose: Builds an authentication/accounting request for port id client_port
++ *        with the value_pairs send and submits it to a server
++ *
++ * Returns: received value_pairs in received, messages from the server in msg
++ *        and 0 on success, negative on failure as return value
++ *
++ */
++
++int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
++    char *msg, int add_nas_port, int request_type)
++{
++      SEND_DATA       data;
++      VALUE_PAIR      *adt_vp = NULL;
++      int             result;
++      int             i, skip_count;
++      SERVER          *aaaserver;
++      int             timeout = rc_conf_int(rh, "radius_timeout");
++      int             retries = rc_conf_int(rh, "radius_retries");
++      int             radius_deadtime = rc_conf_int(rh, "radius_deadtime");
++      double          start_time = 0;
++      double          now = 0;
++      time_t          dtime;
++
++      if (request_type != PW_ACCOUNTING_REQUEST) {
++              aaaserver = rc_conf_srv(rh, "authserver");
++      } else {
++              aaaserver = rc_conf_srv(rh, "acctserver");
++      }
++      if (aaaserver == NULL)
++              return ERROR_RC;
++
++      data.send_pairs = send;
++      data.receive_pairs = NULL;
++
++      if (add_nas_port != 0) {
++              /*
++               * Fill in NAS-Port
++               */
++              if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT,
++                  &client_port, 0, 0) == NULL)
++                      return ERROR_RC;
++      }
++
++      if (request_type == PW_ACCOUNTING_REQUEST) {
++              /*
++               * Fill in Acct-Delay-Time
++               */
++              dtime = 0;
++              now = rc_getctime();
++              adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0);
++              if (adt_vp == NULL) {
++                      adt_vp = rc_avpair_add(rh, &(data.send_pairs),
++                          PW_ACCT_DELAY_TIME, &dtime, 0, 0);
++                      if (adt_vp == NULL)
++                              return ERROR_RC;
++                      start_time = now;
++              } else {
++                      start_time = now - adt_vp->lvalue;
++              }
++      }
++
++      skip_count = 0;
++      result = ERROR_RC;
++      for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
++          ; i++, now = rc_getctime())
++      {
++              if (aaaserver->deadtime_ends[i] != -1 &&
++                  aaaserver->deadtime_ends[i] > start_time) {
++                      skip_count++;
++                      continue;
++              }
++              if (data.receive_pairs != NULL) {
++                      rc_avpair_free(data.receive_pairs);
++                      data.receive_pairs = NULL;
++              }
++              rc_buildreq(rh, &data, request_type, aaaserver->name[i],
++                  aaaserver->port[i], aaaserver->secret[i], timeout, retries);
++
++              if (request_type == PW_ACCOUNTING_REQUEST) {
++                      dtime = now - start_time;
++                      rc_avpair_assign(adt_vp, &dtime, 0);
++              }
++
++              result = rc_send_server (rh, &data, msg);
++              if (result == TIMEOUT_RC && radius_deadtime > 0)
++                      aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime;
++      }
++      if (result == OK_RC || result == BADRESP_RC || skip_count == 0)
++              goto exit;
++
++      result = ERROR_RC;
++      for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
++          ; i++)
++      {
++              if (aaaserver->deadtime_ends[i] == -1 ||
++                  aaaserver->deadtime_ends[i] <= start_time) {
++                      continue;
++              }
++              if (data.receive_pairs != NULL) {
++                      rc_avpair_free(data.receive_pairs);
++                      data.receive_pairs = NULL;
++              }
++              rc_buildreq(rh, &data, request_type, aaaserver->name[i],
++                  aaaserver->port[i], aaaserver->secret[i], timeout, retries);
++
++              if (request_type == PW_ACCOUNTING_REQUEST) {
++                      dtime = rc_getctime() - start_time;
++                      rc_avpair_assign(adt_vp, &dtime, 0);
++              }
++
++              result = rc_send_server (rh, &data, msg);
++              if (result != TIMEOUT_RC)
++                      aaaserver->deadtime_ends[i] = -1;
++      }
++
++exit:
++      if (request_type != PW_ACCOUNTING_REQUEST) {
++              *received = data.receive_pairs;
++      } else {
++              rc_avpair_free(data.receive_pairs);
++      }
++
++      return result;
++}
++
++/*
++ * Function: rc_auth
++ *
++ * Purpose: Builds an authentication request for port id client_port
++ *          with the value_pairs send and submits it to a server
++ *
++ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL),
++ *          and 0 on success, negative on failure as return value
++ *
++ */
++
++int rc_auth(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
++    char *msg)
++{
++
++      return rc_aaa(rh, client_port, send, received, msg, 1, PW_ACCESS_REQUEST);
++}
++
++/*
++ * Function: rc_auth_proxy
++ *
++ * Purpose: Builds an authentication request
++ *        with the value_pairs send and submits it to a server.
++ *        Works for a proxy; does not add IP address, and does
++ *        does not rely on config file.
++ *
++ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL)
++ *        and 0 on success, negative on failure as return value
++ *
++ */
++
++int rc_auth_proxy(rc_handle *rh, VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
++{
++
++      return rc_aaa(rh, 0, send, received, msg, 0, PW_ACCESS_REQUEST);
++}
++
++
++/*
++ * Function: rc_acct
++ *
++ * Purpose: Builds an accounting request for port id client_port
++ *        with the value_pairs send
++ *
++ * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
++ *        in by this function, the rest has to be supplied.
++ */
++
++int rc_acct(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send)
++{
++
++      return rc_aaa(rh, client_port, send, NULL, NULL, 1, PW_ACCOUNTING_REQUEST);
++}
++
++/*
++ * Function: rc_acct_proxy
++ *
++ * Purpose: Builds an accounting request with the value_pairs send
++ *
++ */
++
++int rc_acct_proxy(rc_handle *rh, VALUE_PAIR *send)
++{
++
++      return rc_aaa(rh, 0, send, NULL, NULL, 0, PW_ACCOUNTING_REQUEST);
++}
++
++/*
++ * Function: rc_check
++ *
++ * Purpose: ask the server hostname on the specified port for a
++ *        status message
++ *
++ */
++
++int rc_check(rc_handle *rh, char *host, char *secret, unsigned short port, char *msg)
++{
++      SEND_DATA       data;
++      int             result;
++      uint32_t                service_type;
++      int             timeout = rc_conf_int(rh, "radius_timeout");
++      int             retries = rc_conf_int(rh, "radius_retries");
++
++      data.send_pairs = data.receive_pairs = NULL;
++
++      /*
++       * Fill in Service-Type
++       */
++
++      service_type = PW_ADMINISTRATIVE;
++      rc_avpair_add(rh, &(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, 0);
++
++      rc_buildreq(rh, &data, PW_STATUS_SERVER, host, port, secret, timeout, retries);
++      result = rc_send_server (rh, &data, msg);
++
++      rc_avpair_free(data.receive_pairs);
++
++      return result;
++}
+diff --git a/src/plugins/vbng/lib/clientid.c b/src/plugins/vbng/lib/clientid.c
+new file mode 100644
+index 00000000..6901a04b
+--- /dev/null
++++ b/src/plugins/vbng/lib/clientid.c
+@@ -0,0 +1,146 @@
++/*
++ * $Id: clientid.c,v 1.7 2007/07/11 17:29:29 cparker Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++struct map2id_s {
++      char *name;
++      uint32_t id;
++
++      struct map2id_s *next;
++};
++
++/*
++ * Function: rc_read_mapfile
++ *
++ * Purpose: Read in the ttyname to port id map file
++ *
++ * Arguments: the file name of the map file
++ *
++ * Returns: zero on success, negative integer on failure
++ */
++
++int rc_read_mapfile(rc_handle *rh, char const *filename)
++{
++      char buffer[1024];
++      FILE *mapfd;
++      char *c, *name, *id, *q;
++      struct map2id_s *p;
++      int lnr = 0;
++
++        if ((mapfd = fopen(filename,"r")) == NULL)
++        {
++              rc_log(LOG_ERR,"rc_read_mapfile: can't read %s: %s", filename, strerror(errno));
++              return -1;
++      }
++
++#define SKIP(p) while(*p && isspace(*p)) p++;
++
++        while (fgets(buffer, sizeof(buffer), mapfd) != NULL)
++        {
++              lnr++;
++
++              q = buffer;
++
++                SKIP(q);
++
++                if ((*q == '\n') || (*q == '#') || (*q == '\0'))
++                      continue;
++
++              if (( c = strchr(q, ' ')) || (c = strchr(q,'\t'))) {
++
++                      *c = '\0'; c++;
++                      SKIP(c);
++
++                      name = q;
++                      id = c;
++
++                      if ((p = (struct map2id_s *)malloc(sizeof(*p))) == NULL) {
++                              rc_log(LOG_CRIT,"rc_read_mapfile: out of memory");
++                              fclose(mapfd);
++                              return -1;
++                      }
++
++                      p->name = strdup(name);
++                      p->id = atoi(id);
++                      p->next = rh->map2id_list;
++                      rh->map2id_list = p;
++
++              } else {
++
++                      rc_log(LOG_ERR, "rc_read_mapfile: malformed line in %s, line %d", filename, lnr);
++                      fclose(mapfd);
++                      return -1;
++
++              }
++      }
++
++#undef SKIP
++
++      fclose(mapfd);
++
++      return 0;
++}
++
++/*
++ * Function: rc_map2id
++ *
++ * Purpose: Map ttyname to port id
++ *
++ * Arguments: full pathname of the tty
++ *
++ * Returns: port id, zero if no entry found
++ */
++
++uint32_t rc_map2id(rc_handle const *rh, char const *name)
++{
++      struct map2id_s *p;
++      char ttyname[PATH_MAX];
++
++      *ttyname = '\0';
++      if (*name != '/')
++              strcpy(ttyname, "/dev/");
++
++      strncat(ttyname, name, sizeof(ttyname)-strlen(ttyname)-1);
++
++      for(p = rh->map2id_list; p; p = p->next)
++              if (!strcmp(ttyname, p->name)) return p->id;
++
++      rc_log(LOG_WARNING,"rc_map2id: can't find tty %s in map database", ttyname);
++
++      return 0;
++}
++
++/*
++ * Function: rc_map2id_free
++ *
++ * Purpose: Free allocated map2id list
++ *
++ * Arguments: Radius Client handle
++ */
++
++void
++rc_map2id_free(rc_handle *rh)
++{
++      struct map2id_s *p, *np;
++
++      if (rh->map2id_list == NULL)
++              return;
++
++      for(p = rh->map2id_list; p != NULL; p = np) {
++              np = p->next;
++              free(p->name);
++              free(p);
++      }
++      rh->map2id_list = NULL;
++}
+diff --git a/src/plugins/vbng/lib/config.c b/src/plugins/vbng/lib/config.c
+new file mode 100644
+index 00000000..1db78608
+--- /dev/null
++++ b/src/plugins/vbng/lib/config.c
+@@ -0,0 +1,925 @@
++/*
++ * $Id: config.c,v 1.23 2010/04/28 14:26:15 aland Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++#include <options.h>
++
++/*
++ * Function: find_option
++ *
++ * Purpose: find an option in the option list
++ *
++ * Returns: pointer to option on success, NULL otherwise
++ */
++
++static OPTION *find_option(rc_handle const *rh, char const *optname, unsigned int type)
++{
++      int     i;
++
++      /* there're so few options that a binary search seems not necessary */
++      for (i = 0; i < NUM_OPTIONS; i++) {
++              if (!strcmp(rh->config_options[i].name, optname) &&
++                  (rh->config_options[i].type & type))
++              {
++                      return &rh->config_options[i];
++              }
++      }
++
++      return NULL;
++}
++
++/*
++ * Function: set_option_...
++ *
++ * Purpose: set a specific option doing type conversions
++ *
++ * Returns: 0 on success, -1 on failure
++ */
++
++static int set_option_str(char const *filename, int line, OPTION *option, char const *p)
++{
++      if (p) {
++              option->val = (void *) strdup(p);
++              if (option->val == NULL) {
++                      rc_log(LOG_CRIT, "read_config: out of memory");
++                      return -1;
++              }
++      } else {
++              option->val = NULL;
++      }
++
++      return 0;
++}
++
++static int set_option_int(char const *filename, int line, OPTION *option, char const *p)
++{
++      int *iptr;
++
++      if (p == NULL) {
++              rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line);
++              return -1;
++      }
++
++      if ((iptr = malloc(sizeof(*iptr))) == NULL) {
++              rc_log(LOG_CRIT, "read_config: out of memory");
++              return -1;
++      }
++
++      *iptr = atoi(p);
++      option->val = (void *) iptr;
++
++      return 0;
++}
++
++static int set_option_srv(char const *filename, int line, OPTION *option, char const *p)
++{
++      SERVER *serv;
++      char *p_pointer;
++      char *p_dupe;
++      char *p_save;
++      char *q;
++      char *s;
++      struct servent *svp;
++
++      p_dupe = strdup(p);
++
++      if (p_dupe == NULL) {
++              rc_log(LOG_ERR, "%s: line %d: Invalid option or memory failure", filename, line);
++              return -1;
++      }
++
++      serv = (SERVER *) option->val;
++      if (serv == NULL) {
++              DEBUG(LOG_ERR, "option->val / server is NULL, allocating memory");
++              serv = malloc(sizeof(*serv));
++              if (serv == NULL) {
++                      rc_log(LOG_CRIT, "read_config: out of memory");
++                      free(p_dupe);
++                      return -1;
++              }
++              memset(serv, 0, sizeof(*serv));
++              serv->max = 0;
++      }
++
++      p_pointer = strtok_r(p_dupe, ", \t", &p_save);
++
++      /* Check to see if we have 'servername:port' syntax */
++      if ((q = strchr(p_pointer,':')) != NULL) {
++              *q = '\0';
++              q++;
++
++              /* Check to see if we have 'servername:port:secret' syntax */
++              if((s = strchr(q,':')) != NULL) {
++                      *s = '\0';
++                      s++;
++                      serv->secret[serv->max] = strdup(s);
++                      if (serv->secret[serv->max] == NULL) {
++                              rc_log(LOG_CRIT, "read_config: out of memory");
++                              if (option->val == NULL) {
++                                      free(p_dupe);
++                                      free(serv);
++                              }
++                              return -1;
++                      }
++              }
++      }
++      if(q && strlen(q) > 0) {
++              serv->port[serv->max] = atoi(q);
++      } else {
++              if (!strcmp(option->name,"authserver"))
++                      if ((svp = getservbyname ("radius", "udp")) == NULL)
++                              serv->port[serv->max] = PW_AUTH_UDP_PORT;
++                      else
++                              serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
++              else if (!strcmp(option->name, "acctserver"))
++                      if ((svp = getservbyname ("radacct", "udp")) == NULL)
++                              serv->port[serv->max] = PW_ACCT_UDP_PORT;
++                      else
++                              serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
++              else {
++                      rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name);
++                      if (option->val == NULL) {
++                              free(p_dupe);
++                              free(serv);
++                      }
++                      return -1;
++              }
++      }
++
++      serv->name[serv->max] = strdup(p_pointer);
++      if (serv->name[serv->max] == NULL) {
++              rc_log(LOG_CRIT, "read_config: out of memory");
++              if (option->val == NULL) {
++                      free(p_dupe);
++                      free(serv);
++              }
++              return -1;
++      }
++      free(p_dupe);
++
++      serv->deadtime_ends[serv->max] = -1;
++      serv->max++;
++
++      if (option->val == NULL)
++              option->val = (void *)serv;
++
++      return 0;
++}
++
++static int set_option_auo(char const *filename, int line, OPTION *option, char const *p)
++{
++      int *iptr;
++      char *p_dupe = NULL;
++      char *p_pointer = NULL;
++      char *p_save = NULL;
++
++      p_dupe = strdup(p);
++
++      if (p_dupe == NULL) {
++              rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line);
++              return -1;
++      }
++
++      if ((iptr = malloc(sizeof(iptr))) == NULL) {
++                      rc_log(LOG_CRIT, "read_config: out of memory");
++                      free(p_dupe);
++                      return -1;
++      }
++
++      *iptr = 0;
++      /*if(strstr(p_dupe,", \t") != NULL) {*/
++              p_pointer = strtok_r(p_dupe, ", \t", &p_save);
++      /*}*/
++
++      if (!strncmp(p_pointer, "local", 5))
++                      *iptr = AUTH_LOCAL_FST;
++      else if (!strncmp(p_pointer, "radius", 6))
++                      *iptr = AUTH_RADIUS_FST;
++      else {
++              rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p);
++              free(iptr);
++              free(p_dupe);
++              return -1;
++      }
++
++      p_pointer = strtok_r(NULL, ", \t", &p_save);
++
++      if (p_pointer && (*p_pointer != '\0')) {
++              if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p_pointer, "local"))
++                      *iptr = (*iptr) | AUTH_LOCAL_SND;
++              else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p_pointer, "radius"))
++                      *iptr = (*iptr) | AUTH_RADIUS_SND;
++              else {
++                      rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
++                      free(iptr);
++                      free(p_dupe);
++                      return -1;
++              }
++      }
++
++      option->val = (void *) iptr;
++
++      free(p_dupe);
++      return 0;
++}
++
++
++/* Function: rc_add_config
++ *
++ * Purpose: allow a config option to be added to rc_handle from inside a program
++ *
++ * Returns: 0 on success, -1 on failure
++ */
++
++int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
++{
++      OPTION *option;
++
++      if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
++      {
++              rc_log(LOG_ERR, "ERROR: unrecognized option: %s", option_name);
++              return -1;
++      }
++
++      if (option->status != ST_UNDEF)
++      {
++              rc_log(LOG_ERR, "ERROR: duplicate option: %s", option_name);
++              return -1;
++      }
++
++      switch (option->type) {
++              case OT_STR:
++                      if (set_option_str(source, line, option, option_val) < 0) {
++                              return -1;
++                      }
++                      break;
++              case OT_INT:
++                      if (set_option_int(source, line, option, option_val) < 0) {
++                              return -1;
++                      }
++                      break;
++              case OT_SRV:
++                      if (set_option_srv(source, line, option, option_val) < 0) {
++                              return -1;
++                      }
++                      break;
++              case OT_AUO:
++                      if (set_option_auo(source, line, option, option_val) < 0) {
++                              return -1;
++                      }
++                      break;
++              default:
++                      rc_log(LOG_CRIT, "rc_add_config: impossible case branch!");
++                      abort();
++      }
++      return 0;
++}
++
++/*
++ * Function: rc_config_init
++ *
++ * Purpose: initialize the configuration structure from an external program.  For use when not
++ * running a standalone client that reads from a config file.
++ *
++ * Returns: rc_handle on success, NULL on failure
++ */
++
++rc_handle *
++rc_config_init(rc_handle *rh)
++{
++      int i;
++      SERVER *authservers;
++      SERVER *acctservers;
++      OPTION *acct;
++      OPTION *auth;
++
++        rh->config_options = malloc(sizeof(config_options_default));
++        if (rh->config_options == NULL)
++      {
++                rc_log(LOG_CRIT, "rc_config_init: out of memory");
++              rc_destroy(rh);
++                return NULL;
++        }
++        memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
++
++      acct = find_option(rh, "acctserver", OT_ANY);
++      auth = find_option(rh, "authserver", OT_ANY);
++      authservers = malloc(sizeof(SERVER));
++      acctservers = malloc(sizeof(SERVER));
++
++      if(authservers == NULL || acctservers == NULL)
++      {
++                rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
++              rc_destroy(rh);
++              if(authservers) free(authservers);
++              if(acctservers) free(acctservers);
++                return NULL;
++      }
++
++
++      authservers->max = 0;
++      acctservers->max = 0;
++
++      for(i=0; i < SERVER_MAX; i++)
++      {
++              authservers->name[i] = NULL;
++              authservers->secret[i] = NULL;
++              acctservers->name[i] = NULL;
++              acctservers->secret[i] = NULL;
++      }
++      acct->val = acctservers;
++      auth->val = authservers;
++      return rh;
++}
++
++
++/*
++ * Function: rc_read_config
++ *
++ * Purpose: read the global config file
++ *
++ * Returns: new rc_handle on success, NULL when failure
++ */
++
++rc_handle *
++rc_read_config(char const *filename)
++{
++      FILE *configfd;
++      char buffer[512], *p;
++      OPTION *option;
++      int line;
++      size_t pos;
++      rc_handle *rh;
++
++      srandom((unsigned int)(time(NULL)+getpid()));
++
++      rh = rc_new();
++      if (rh == NULL)
++              return NULL;
++
++        rh->config_options = malloc(sizeof(config_options_default));
++        if (rh->config_options == NULL) {
++                rc_log(LOG_CRIT, "rc_read_config: out of memory");
++              rc_destroy(rh);
++                return NULL;
++        }
++        memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
++
++      if ((configfd = fopen(filename,"r")) == NULL)
++      {
++              rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
++              rc_destroy(rh);
++              return NULL;
++      }
++
++      line = 0;
++      while ((fgets(buffer, sizeof(buffer), configfd) != NULL))
++      {
++              line++;
++              p = buffer;
++
++              if ((*p == '\n') || (*p == '#') || (*p == '\0'))
++                      continue;
++
++              p[strlen(p)-1] = '\0';
++
++
++              if ((pos = strcspn(p, "\t ")) == 0) {
++                      rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
++                      fclose(configfd);
++                      rc_destroy(rh);
++                      return NULL;
++              }
++
++              p[pos] = '\0';
++
++              if ((option = find_option(rh, p, OT_ANY)) == NULL) {
++                      rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
++                      fclose(configfd);
++                      rc_destroy(rh);
++                      return NULL;
++              }
++
++              if (option->status != ST_UNDEF) {
++                      rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
++                      fclose(configfd);
++                      rc_destroy(rh);
++                      return NULL;
++              }
++
++              p += pos+1;
++              while (isspace(*p))
++                      p++;
++              pos = strlen(p) - 1;
++              while(pos != 0 && isspace(p[pos]))
++                      pos--;
++              p[pos + 1] = '\0';
++
++              switch (option->type) {
++                      case OT_STR:
++                              if (set_option_str(filename, line, option, p) < 0) {
++                                      fclose(configfd);
++                                      rc_destroy(rh);
++                                      return NULL;
++                              }
++                              break;
++                      case OT_INT:
++                              if (set_option_int(filename, line, option, p) < 0) {
++                                      fclose(configfd);
++                                      rc_destroy(rh);
++                                      return NULL;
++                              }
++                              break;
++                      case OT_SRV:
++                              if (set_option_srv(filename, line, option, p) < 0) {
++                                      fclose(configfd);
++                                      rc_destroy(rh);
++                                      return NULL;
++                              }
++                              break;
++                      case OT_AUO:
++                              if (set_option_auo(filename, line, option, p) < 0) {
++                                      fclose(configfd);
++                                      rc_destroy(rh);
++                                      return NULL;
++                              }
++                              break;
++                      default:
++                              rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
++                              abort();
++              }
++      }
++      fclose(configfd);
++
++      if (test_config(rh, filename) == -1) {
++              rc_destroy(rh);
++              return NULL;
++      }
++      return rh;
++}
++
++/*
++ * Function: rc_conf_str, rc_conf_int, rc_conf_src
++ *
++ * Purpose: get the value of a config option
++ *
++ * Returns: config option value
++ */
++
++char *rc_conf_str(rc_handle const *rh, char const *optname)
++{
++      OPTION *option;
++
++      option = find_option(rh, optname, OT_STR);
++
++      if (option != NULL) {
++              return (char *)option->val;
++      } else {
++              rc_log(LOG_CRIT, "rc_conf_str: unkown config option requested: %s", optname);
++              abort();
++              return NULL;
++      }
++}
++
++int rc_conf_int(rc_handle const *rh, char const *optname)
++{
++      OPTION *option;
++
++      option = find_option(rh, optname, OT_INT|OT_AUO);
++
++      if (option != NULL) {
++              if (option->val) {
++                      return *((int *)option->val);
++              } else {
++                      rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
++                      return 0;
++              }
++      } else {
++              rc_log(LOG_CRIT, "rc_conf_int: unkown config option requested: %s", optname);
++              abort();
++              return 0;
++      }
++}
++
++SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
++{
++      OPTION *option;
++
++      option = find_option(rh, optname, OT_SRV);
++
++      if (option != NULL) {
++              return (SERVER *)option->val;
++      } else {
++              rc_log(LOG_CRIT, "rc_conf_srv: unkown config option requested: %s", optname);
++              abort();
++              return NULL;
++      }
++}
++
++/*
++ * Function: test_config
++ *
++ * Purpose: test the configuration the user supplied
++ *
++ * Returns: 0 on success, -1 when failure
++ */
++
++int test_config(rc_handle const *rh, char const *filename)
++{
++#if 0
++      struct stat st;
++      char        *file;
++#endif
++
++      if (!(rc_conf_srv(rh, "authserver")->max))
++      {
++              rc_log(LOG_ERR,"%s: no authserver specified", filename);
++              return -1;
++      }
++      if (!(rc_conf_srv(rh, "acctserver")->max))
++      {
++              rc_log(LOG_ERR,"%s: no acctserver specified", filename);
++              return -1;
++      }
++      if (!rc_conf_str(rh, "servers"))
++      {
++              rc_log(LOG_ERR,"%s: no servers file specified", filename);
++              return -1;
++      }
++      if (!rc_conf_str(rh, "dictionary"))
++      {
++              rc_log(LOG_ERR,"%s: no dictionary specified", filename);
++              return -1;
++      }
++
++      if (rc_conf_int(rh, "radius_timeout") <= 0)
++      {
++              rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
++              return -1;
++      }
++      if (rc_conf_int(rh, "radius_retries") <= 0)
++      {
++              rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
++              return -1;
++      }
++      if (rc_conf_int(rh, "radius_deadtime") < 0)
++      {
++              rc_log(LOG_ERR,"%s: radius_deadtime is illegal", filename);
++              return -1;
++      }
++#if 0
++      file = rc_conf_str(rh, "login_local");
++      if (stat(file, &st) == 0)
++      {
++              if (!S_ISREG(st.st_mode)) {
++                      rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
++                      return -1;
++              }
++      } else {
++              rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
++              return -1;
++      }
++      file = rc_conf_str(rh, "login_radius");
++      if (stat(file, &st) == 0)
++      {
++              if (!S_ISREG(st.st_mode)) {
++                      rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
++                      return -1;
++              }
++      } else {
++              rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
++              return -1;
++      }
++#endif
++
++      if (rc_conf_int(rh, "login_tries") <= 0)
++      {
++              rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename);
++              return -1;
++      }
++      if (rc_conf_str(rh, "seqfile") == NULL)
++      {
++              rc_log(LOG_ERR,"%s: seqfile not specified", filename);
++              return -1;
++      }
++      if (rc_conf_int(rh, "login_timeout") <= 0)
++      {
++              rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename);
++              return -1;
++      }
++      if (rc_conf_str(rh, "mapfile") == NULL)
++      {
++              rc_log(LOG_ERR,"%s: mapfile not specified", filename);
++              return -1;
++      }
++      if (rc_conf_str(rh, "nologin") == NULL)
++      {
++              rc_log(LOG_ERR,"%s: nologin not specified", filename);
++              return -1;
++      }
++
++      return 0;
++}
++
++/*
++ * Function: rc_find_match
++ *
++ * Purpose: see if ip_addr is one of the ip addresses of hostname
++ *
++ * Returns: 0 on success, -1 when failure
++ *
++ */
++
++static int find_match (uint32_t *ip_addr, char const *hostname)
++{
++
++      uint32_t           addr;
++      char          **paddr;
++      struct hostent *hp;
++
++      if (rc_good_ipaddr (hostname) == 0)
++      {
++              if (*ip_addr == ntohl(inet_addr (hostname)))
++              {
++                      return 0;
++              }
++              return -1;
++      }
++
++      if ((hp = rc_gethostbyname(hostname)) == NULL)
++      {
++              return -1;
++      }
++
++      for (paddr = hp->h_addr_list; *paddr; paddr++)
++      {
++              addr = ** (uint32_t **) paddr;
++              if (ntohl(addr) == *ip_addr)
++              {
++                      return 0;
++              }
++      }
++      return -1;
++}
++
++/*
++ * Function: rc_ipaddr_local
++ *
++ * Purpose: checks if provided address is local address
++ *
++ * Returns: 0 if local, 1 if not local, -1 on failure
++ *
++ */
++
++static int
++rc_ipaddr_local(uint32_t ip_addr)
++{
++      int temp_sock, res, serrno;
++      struct sockaddr_in sin;
++
++      temp_sock = socket(AF_INET, SOCK_DGRAM, 0);
++      if (temp_sock == -1)
++              return -1;
++      memset(&sin, '\0', sizeof(sin));
++      sin.sin_family = AF_INET;
++      sin.sin_addr.s_addr = htonl(ip_addr);
++      sin.sin_port = htons(0);
++      res = bind(temp_sock, (struct sockaddr *)&sin, sizeof(sin));
++      serrno = errno;
++      close(temp_sock);
++      if (res == 0)
++              return 0;
++      if (serrno == EADDRNOTAVAIL)
++              return 1;
++      return -1;
++}
++
++/*
++ * Function: rc_is_myname
++ *
++ * Purpose: check if provided name refers to ourselves
++ *
++ * Returns: 0 if yes, 1 if no and -1 on failure
++ *
++ */
++
++static int
++rc_is_myname(char const *hostname)
++{
++      uint32_t        addr;
++      char    **paddr;
++      struct  hostent *hp;
++      int     res;
++
++      if (rc_good_ipaddr(hostname) == 0)
++              return rc_ipaddr_local(ntohl(inet_addr(hostname)));
++
++      if ((hp = rc_gethostbyname(hostname)) == NULL)
++              return -1;
++      for (paddr = hp->h_addr_list; *paddr; paddr++) {
++              addr = **(uint32_t **)paddr;
++              res = rc_ipaddr_local(ntohl(addr));
++              if (res == 0 || res == -1)
++                      return res;
++      }
++      return 1;
++}
++
++/*
++ * Function: rc_find_server
++ *
++ * Purpose: locate a server in the rh config or if not found, check for a servers file
++ *
++ * Returns: 0 on success, -1 on failure
++ *
++ */
++
++int rc_find_server (rc_handle const *rh, char const *server_name, uint32_t *ip_addr, char *secret)
++{
++      int             i;
++      size_t          len;
++      int             result = 0;
++      FILE           *clientfd;
++      char           *h;
++      char           *s;
++      char            buffer[128];
++      char            hostnm[AUTH_ID_LEN + 1];
++      char           *buffer_save;
++      char           *hostnm_save;
++      SERVER         *authservers;
++      SERVER         *acctservers;
++
++      /* Lookup the IP address of the radius server */
++      if ((*ip_addr = rc_get_ipaddr (server_name)) == (uint32_t) 0)
++              return -1;
++
++      /* Check to see if the server secret is defined in the rh config */
++      if( (authservers = rc_conf_srv(rh, "authserver")) != NULL )
++      {
++              for( i = 0; i < authservers->max; i++ )
++              {
++                      if( (strncmp(server_name, authservers->name[i], strlen(server_name)) == 0) &&
++                          (authservers->secret[i] != NULL) )
++                      {
++                              memset (secret, '\0', MAX_SECRET_LENGTH);
++                              len = strlen (authservers->secret[i]);
++                              if (len > MAX_SECRET_LENGTH)
++                              {
++                                      len = MAX_SECRET_LENGTH;
++                              }
++                              strncpy (secret, authservers->secret[i], (size_t) len);
++                              secret[MAX_SECRET_LENGTH] = '\0';
++                              return 0;
++                      }
++              }
++      }
++
++      if( (acctservers = rc_conf_srv(rh, "acctserver")) != NULL )
++      {
++              for( i = 0; i < acctservers->max; i++ )
++              {
++                      if( (strncmp(server_name, acctservers->name[i], strlen(server_name)) == 0) &&
++                          (acctservers->secret[i] != NULL) )
++                      {
++                              memset (secret, '\0', MAX_SECRET_LENGTH);
++                              len = strlen (acctservers->secret[i]);
++                              if (len > MAX_SECRET_LENGTH)
++                              {
++                                      len = MAX_SECRET_LENGTH;
++                              }
++                              strncpy (secret, acctservers->secret[i], (size_t) len);
++                              secret[MAX_SECRET_LENGTH] = '\0';
++                              return 0;
++                      }
++              }
++      }
++
++      /* We didn't find it in the rh_config or the servername is too long so look for a
++       * servers file to define the secret(s)
++       */
++
++      if ((clientfd = fopen (rc_conf_str(rh, "servers"), "r")) == NULL)
++      {
++              rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
++              return -1;
++      }
++
++      while (fgets (buffer, sizeof (buffer), clientfd) != NULL)
++      {
++              if (*buffer == '#')
++                      continue;
++
++              if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
++                      continue;
++
++              memset (hostnm, '\0', AUTH_ID_LEN);
++              len = strlen (h);
++              if (len > AUTH_ID_LEN)
++              {
++                      len = AUTH_ID_LEN;
++              }
++              strncpy (hostnm, h, (size_t) len);
++              hostnm[AUTH_ID_LEN] = '\0';
++
++              if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
++                      continue;
++
++              memset (secret, '\0', MAX_SECRET_LENGTH);
++              len = strlen (s);
++              if (len > MAX_SECRET_LENGTH)
++              {
++                      len = MAX_SECRET_LENGTH;
++              }
++              strncpy (secret, s, (size_t) len);
++              secret[MAX_SECRET_LENGTH] = '\0';
++
++              if (!strchr (hostnm, '/')) /* If single name form */
++              {
++                      if (find_match (ip_addr, hostnm) == 0)
++                      {
++                              result++;
++                              break;
++                      }
++              }
++              else /* <name1>/<name2> "paired" form */
++              {
++                      strtok_r(hostnm, "/", &hostnm_save);
++                      if (rc_is_myname(hostnm) == 0)
++                      {            /* If we're the 1st name, target is 2nd */
++                              if (find_match (ip_addr, hostnm_save) == 0)
++                              {
++                                      result++;
++                                      break;
++                              }
++                      }
++                      else    /* If we were 2nd name, target is 1st name */
++                      {
++                              if (find_match (ip_addr, hostnm) == 0)
++                              {
++                                      result++;
++                                      break;
++                              }
++                      }
++              }
++      }
++      fclose (clientfd);
++      if (result == 0)
++      {
++              memset (buffer, '\0', sizeof (buffer));
++              memset (secret, '\0', MAX_SECRET_LENGTH);
++              rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
++                       server_name, rc_conf_str(rh, "servers"));
++              return -1;
++      }
++      return 0;
++}
++
++/*
++ * Function: rc_config_free
++ *
++ * Purpose: Free allocated config values
++ *
++ * Arguments: Radius Client handle
++ */
++
++void
++rc_config_free(rc_handle *rh)
++{
++      int i, j;
++      SERVER *serv;
++
++      if (rh->config_options == NULL)
++              return;
++
++      for (i = 0; i < NUM_OPTIONS; i++) {
++              if (rh->config_options[i].val == NULL)
++                      continue;
++              if (rh->config_options[i].type == OT_SRV) {
++                      serv = (SERVER *)rh->config_options[i].val;
++                      for (j = 0; j < serv->max; j++){
++                              free(serv->name[j]);
++                              if(serv->secret[j]) free(serv->secret[j]);
++                      }
++                      free(serv);
++              } else {
++                      free(rh->config_options[i].val);
++              }
++      }
++      free(rh->config_options);
++      rh->config_options = NULL;
++}
+diff --git a/src/plugins/vbng/lib/dict.c b/src/plugins/vbng/lib/dict.c
+new file mode 100644
+index 00000000..84dbba0e
+--- /dev/null
++++ b/src/plugins/vbng/lib/dict.c
+@@ -0,0 +1,519 @@
++/*
++ * $Id: dict.c,v 1.10 2007/07/11 17:29:29 cparker Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++/*
++ * Function: rc_read_dictionary
++ *
++ * Purpose: Initialize the dictionary.  Read all ATTRIBUTES into
++ *        the dictionary_attributes list.  Read all VALUES into
++ *        the dictionary_values list.
++ *
++ */
++
++int rc_read_dictionary (rc_handle *rh, char const *filename)
++{
++      FILE           *dictfd;
++      char            dummystr[AUTH_ID_LEN];
++      char            namestr[AUTH_ID_LEN];
++      char            valstr[AUTH_ID_LEN];
++      char            attrstr[AUTH_ID_LEN];
++      char            typestr[AUTH_ID_LEN];
++      char            optstr[AUTH_ID_LEN];
++      char            *cp, *ifilename;
++      int             line_no;
++      DICT_ATTR      *attr;
++      DICT_VALUE     *dval;
++      DICT_VENDOR    *dvend;
++      char            buffer[256];
++      int             value;
++      int             type;
++      unsigned attr_vendorspec = 0;
++
++      if ((dictfd = fopen (filename, "r")) == NULL)
++      {
++              rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s",
++                              filename, strerror(errno));
++              return -1;
++      }
++
++      line_no = 0;
++      while (fgets (buffer, sizeof (buffer), dictfd) != NULL)
++      {
++              line_no++;
++
++              /* Skip empty space */
++              if (*buffer == '#' || *buffer == '\0' || *buffer == '\n' || \
++                  *buffer == '\r')
++              {
++                      continue;
++              }
++
++              /* Strip out comments */
++              cp = strchr(buffer, '#');
++              if (cp != NULL)
++              {
++                      *cp = '\0';
++              }
++
++              if (strncmp (buffer, "ATTRIBUTE", 9) == 0)
++              {
++                      optstr[0] = '\0';
++                      /* Read the ATTRIBUTE line */
++                      if (sscanf (buffer, "%63s%63s%63s%63s%63s", dummystr, namestr,
++                                  valstr, typestr, optstr) < 4)
++                      {
++                              rc_log(LOG_ERR, "rc_read_dictionary: invalid attribute on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      /*
++                       * Validate all entries
++                       */
++                      if (strlen (namestr) > NAME_LENGTH)
++                      {
++                              rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      if (!isdigit (*valstr))
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid value on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      value = atoi (valstr);
++
++                      if (strcmp (typestr, "string") == 0)
++                      {
++                              type = PW_TYPE_STRING;
++                      }
++                      else if (strcmp (typestr, "integer") == 0)
++                      {
++                              type = PW_TYPE_INTEGER;
++                      }
++                      else if (strcmp (typestr, "ipaddr") == 0)
++                      {
++                              type = PW_TYPE_IPADDR;
++                      }
++                      else if (strcmp (typestr, "ipv6addr") == 0)
++                      {
++                              type = PW_TYPE_IPV6ADDR;
++                      }
++                      else if (strcmp (typestr, "ipv6prefix") == 0)
++                      {
++                              type = PW_TYPE_IPV6PREFIX;
++                      }
++                      else if (strcmp (typestr, "date") == 0)
++                      {
++                              type = PW_TYPE_DATE;
++                      }
++                      else
++                      {
++                              rc_log(LOG_ERR,
++                                "rc_read_dictionary: invalid type on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      dvend = NULL;
++                      if (optstr[0] != '\0') {
++                              char *cp1;
++                              for (cp1 = optstr; cp1 != NULL; cp1 = cp) {
++                                      cp = strchr(cp1, ',');
++                                      if (cp != NULL) {
++                                              *cp = '\0';
++                                              cp++;
++                                      }
++                                      if (strncmp(cp1, "vendor=", 7) == 0)
++                                              cp1 += 7;
++                                      dvend = rc_dict_findvend(rh, cp1);
++                                      if (dvend == NULL) {
++                                              rc_log(LOG_ERR,
++                                               "rc_read_dictionary: unknown Vendor-Id %s on line %d of dictionary %s",
++                                                       cp1, line_no, filename);
++                                              fclose(dictfd);
++                                              return -1;
++                                      }
++                              }
++                      }
++
++                      /* Create a new attribute for the list */
++                      if ((attr = malloc (sizeof (DICT_ATTR))) == NULL)
++                      {
++                              rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      strcpy (attr->name, namestr);
++                      attr->value = value | (attr_vendorspec << 16);
++                      attr->type = type;
++
++                      if (dvend != NULL) {
++                              attr->value = value | (dvend->vendorpec << 16);
++                      } else {
++                              attr->value = value | (attr_vendorspec << 16);
++                      }
++
++                      /* Insert it into the list */
++                      attr->next = rh->dictionary_attributes;
++                      rh->dictionary_attributes = attr;
++              }
++              else if (strncmp (buffer, "VALUE", 5) == 0)
++              {
++                      /* Read the VALUE line */
++                      if (sscanf (buffer, "%63s%63s%63s%63s", dummystr, attrstr,
++                                  namestr, valstr) != 4)
++                      {
++                              rc_log(LOG_ERR,
++                         "rc_read_dictionary: invalid value entry on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      /*
++                       * Validate all entries
++                       */
++                      if (strlen (attrstr) > NAME_LENGTH)
++                      {
++                              rc_log(LOG_ERR,
++                    "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      if (strlen (namestr) > NAME_LENGTH)
++                      {
++                              rc_log(LOG_ERR,
++                         "rc_read_dictionary: invalid name length on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      if (!isdigit (*valstr))
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid value on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      value = atoi (valstr);
++
++                      /* Create a new VALUE entry for the list */
++                      if ((dval = malloc (sizeof (DICT_VALUE))) == NULL)
++                      {
++                              rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      strcpy (dval->attrname, attrstr);
++                      strcpy (dval->name, namestr);
++                      dval->value = value;
++
++                      /* Insert it into the list */
++                      dval->next = rh->dictionary_values;
++                      rh->dictionary_values = dval;
++              }
++                else if (strncmp (buffer, "$INCLUDE", 8) == 0)
++                {
++                      /* Read the $INCLUDE line */
++                      if (sscanf (buffer, "%63s%63s", dummystr, namestr) != 2)
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid include entry on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      ifilename = namestr;
++                      /* Append directory if necessary */
++                      if (namestr[0] != '/') {
++                              cp = strrchr(filename, '/');
++                              if (cp != NULL) {
++                                      ifilename = alloca(AUTH_ID_LEN);
++                                      *cp = '\0';
++                                      snprintf(ifilename, AUTH_ID_LEN, "%s/%s", filename, namestr);
++                                      *cp = '/';
++                              }
++                      }
++                      if (rc_read_dictionary(rh, ifilename) < 0)
++                      {
++                              fclose(dictfd);
++                              return -1;
++                      }
++              }
++              else if (strncmp (buffer, "END-VENDOR", 10) == 0)
++              {
++                      attr_vendorspec = 0;
++              }
++              else if (strncmp (buffer, "BEGIN-VENDOR", 12) == 0)
++              {
++                      DICT_VENDOR *v;
++                      /* Read the vendor name */
++                      if (sscanf (buffer+12, "%63s", dummystr) != 1)
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      v = rc_dict_findvend(rh, dummystr);
++                      if (v == NULL) {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: unknown Vendor %s on line %d of dictionary %s",
++                                       dummystr, line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      attr_vendorspec = v->vendorpec;
++              }
++              else if (strncmp (buffer, "VENDOR", 6) == 0)
++              {
++                      /* Read the VALUE line */
++                      if (sscanf (buffer, "%63s%63s%63s", dummystr, attrstr, valstr) != 3)
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      /* Validate all entries */
++                      if (strlen (attrstr) > NAME_LENGTH)
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++
++                      if (!isdigit (*valstr))
++                      {
++                              rc_log(LOG_ERR,
++                               "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
++                                       line_no, filename);
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      value = atoi (valstr);
++
++                      /* Create a new VENDOR entry for the list */
++                      dvend = malloc(sizeof(DICT_VENDOR));
++                      if (dvend == NULL)
++                      {
++                              rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
++                              fclose(dictfd);
++                              return -1;
++                      }
++                      strcpy (dvend->vendorname, attrstr);
++                      dvend->vendorpec = value;
++
++                      /* Insert it into the list */
++                      dvend->next = rh->dictionary_vendors;
++                      rh->dictionary_vendors = dvend;
++                }
++      }
++      fclose (dictfd);
++      return 0;
++}
++
++/*
++ * Function: rc_dict_getattr
++ *
++ * Purpose: Return the full attribute structure based on the
++ *        attribute id number.
++ *
++ */
++
++DICT_ATTR *rc_dict_getattr (rc_handle const *rh, int attribute)
++{
++      DICT_ATTR      *attr;
++
++      attr = rh->dictionary_attributes;
++      while (attr != NULL)
++      {
++              if (attr->value == attribute)
++              {
++                      return attr;
++              }
++              attr = attr->next;
++      }
++      return NULL;
++}
++
++/*
++ * Function: rc_dict_findattr
++ *
++ * Purpose: Return the full attribute structure based on the
++ *        attribute name.
++ *
++ */
++
++DICT_ATTR *rc_dict_findattr (rc_handle const *rh, char const *attrname)
++{
++      DICT_ATTR      *attr;
++
++      attr = rh->dictionary_attributes;
++      while (attr != NULL)
++      {
++              if (strcasecmp (attr->name, attrname) == 0)
++              {
++                      return attr;
++              }
++              attr = attr->next;
++      }
++      return NULL;
++}
++
++
++/*
++ * Function: rc_dict_findval
++ *
++ * Purpose: Return the full value structure based on the
++ *         value name.
++ *
++ */
++
++DICT_VALUE *rc_dict_findval (rc_handle const *rh, char const *valname)
++{
++      DICT_VALUE     *val;
++
++      val = rh->dictionary_values;
++      while (val != NULL)
++      {
++              if (strcasecmp (val->name, valname) == 0)
++              {
++                      return val;
++              }
++              val = val->next;
++      }
++      return NULL;
++}
++
++/*
++ * Function: rc_dict_findvend
++ *
++ * Purpose: Return the full vendor structure based on the
++ *          vendor name.
++ *
++ */
++
++DICT_VENDOR *
++rc_dict_findvend(rc_handle const *rh, char const *vendorname)
++{
++      DICT_VENDOR     *vend;
++
++      for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
++              if (strcasecmp(vend->vendorname, vendorname) == 0)
++                      return vend;
++      return NULL;
++}
++
++/*
++ * Function: rc_dict_getvend
++ *
++ * Purpose: Return the full vendor structure based on the
++ *          vendor id number.
++ *
++ */
++
++DICT_VENDOR *
++rc_dict_getvend (rc_handle const *rh, int vendorpec)
++{
++        DICT_VENDOR      *vend;
++
++      for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
++              if (vend->vendorpec == vendorpec)
++                      return vend;
++      return NULL;
++}
++
++/*
++ * Function: dict_getval
++ *
++ * Purpose: Return the full value structure based on the
++ *          actual value and the associated attribute name.
++ *
++ */
++
++DICT_VALUE *
++rc_dict_getval (rc_handle const *rh, uint32_t value, char const *attrname)
++{
++      DICT_VALUE     *val;
++
++      val = rh->dictionary_values;
++      while (val != NULL)
++      {
++              if (strcmp (val->attrname, attrname) == 0 &&
++                              val->value == value)
++              {
++                      return val;
++              }
++              val = val->next;
++      }
++      return NULL;
++}
++
++/*
++ * Function: rc_dict_free
++ *
++ * Purpose: Free allocated av lists
++ *
++ * Arguments: Radius Client handle
++ */
++
++void
++rc_dict_free(rc_handle *rh)
++{
++      DICT_ATTR       *attr, *nattr;
++      DICT_VALUE      *val, *nval;
++      DICT_VENDOR     *vend, *nvend;
++
++      for (attr = rh->dictionary_attributes; attr != NULL; attr = nattr) {
++              nattr = attr->next;
++              free(attr);
++      }
++      for (val = rh->dictionary_values; val != NULL; val = nval) {
++              nval = val->next;
++              free(val);
++      }
++      for (vend = rh->dictionary_vendors; vend != NULL; vend = nvend) {
++              nvend = vend->next;
++              free(vend);
++      }
++      rh->dictionary_attributes = NULL;
++      rh->dictionary_values = NULL;
++      rh->dictionary_vendors = NULL;
++}
+diff --git a/src/plugins/vbng/lib/env.c b/src/plugins/vbng/lib/env.c
+new file mode 100644
+index 00000000..03dccf91
+--- /dev/null
++++ b/src/plugins/vbng/lib/env.c
+@@ -0,0 +1,147 @@
++/*
++ * $Id: env.c,v 1.6 2007/06/21 18:07:23 cparker Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++/*
++ * Function: rc_new_env
++ *
++ * Purpose: allocate space for a new environment
++ *
++ */
++
++ENV *rc_new_env(int size)
++{
++      ENV *p;
++
++      if (size < 1)
++              return NULL;
++
++      if ((p = malloc(sizeof(*p))) == NULL)
++              return NULL;
++
++      if ((p->env = malloc(size * sizeof(char *))) == NULL)
++      {
++              rc_log(LOG_CRIT, "rc_new_env: out of memory");
++              free(p);
++              return NULL;
++      }
++
++      p->env[0] = NULL;
++
++      p->size = 0;
++      p->maxsize = size;
++
++      return p;
++}
++
++/*
++ * Function: rc_free_env
++ *
++ * Purpose: free the space used by an env structure
++ *
++ */
++
++void rc_free_env(ENV *env)
++{
++      free(env->env);
++      free(env);
++}
++
++/*
++ * Function: rc_add_env
++ *
++ * Purpose: add an environment entry
++ *
++ */
++
++int rc_add_env(ENV *env, char const *name, char const *value)
++{
++      int i;
++      size_t len;
++      char *new_env;
++
++      for (i = 0; env->env[i] != NULL; i++)
++      {
++              if (strncmp(env->env[i], name, MAX(strchr(env->env[i], '=') - env->env[i], (int)strlen(name))) == 0)
++                      break;
++      }
++
++      if (env->env[i])
++      {
++              len = strlen(name)+strlen(value)+2;
++              if ((new_env = realloc(env->env[i], len)) == NULL)
++                      return -1;
++
++              env->env[i] = new_env;
++
++              snprintf(env->env[i], len, "%s=%s", name, value);
++      } else {
++              if (env->size == (env->maxsize-1)) {
++                      rc_log(LOG_CRIT, "rc_add_env: not enough space for environment (increase ENV_SIZE)");
++                      return -1;
++              }
++
++              len = strlen(name)+strlen(value)+2;
++              if ((env->env[env->size] = malloc(len)) == NULL) {
++                      rc_log(LOG_CRIT, "rc_add_env: out of memory");
++                      return -1;
++              }
++
++              snprintf(env->env[env->size], len, "%s=%s", name, value);
++
++              env->size++;
++
++              env->env[env->size] = NULL;
++      }
++
++      return 0;
++}
++
++/*
++ * Function: rc_import_env
++ *
++ * Purpose: imports an array of null-terminated strings
++ *
++ */
++
++int rc_import_env(ENV *env, char const **import)
++{
++      char *es;
++
++      while (*import)
++      {
++              es = strchr(*import, '=');
++
++              if (!es)
++              {
++                      import++;
++                      continue;
++              }
++
++              /* ok, i grant thats not very clean... */
++              *es = '\0';
++
++              if (rc_add_env(env, *import, es+1) < 0)
++              {
++                      *es = '=';
++                      return -1;
++              }
++
++              *es = '=';
++
++              import++;
++      }
++
++      return 0;
++}
+diff --git a/src/plugins/vbng/lib/ip_util.c b/src/plugins/vbng/lib/ip_util.c
+new file mode 100644
+index 00000000..d686a59e
+--- /dev/null
++++ b/src/plugins/vbng/lib/ip_util.c
+@@ -0,0 +1,390 @@
++/*
++ * $Id: ip_util.c,v 1.14 2010/03/17 18:57:01 aland Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++#define HOSTBUF_SIZE 1024
++
++#if !defined(SA_LEN)
++#define SA_LEN(sa) \
++  (((sa)->sa_family == AF_INET) ? \
++    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
++#endif
++
++
++static __thread size_t        hostbuflen=HOSTBUF_SIZE;
++static __thread       char    *tmphostbuf=NULL;
++
++/*
++ * Function: rc_gethostbyname
++ *
++ * Purpose: threadsafe replacement for gethostbyname.
++ *
++ * Returns: NULL on failure, hostent pointer on success
++ */
++
++struct hostent *rc_gethostbyname(char const *hostname)
++{
++      struct  hostent *hp;
++#ifdef GETHOSTBYNAME_R
++#if defined (GETHOSTBYNAMERSTYLE_SYSV) || defined (GETHOSTBYNAMERSTYLE_GNU)
++      struct  hostent hostbuf;
++      int     res;
++      int     herr;
++      
++      if(!tmphostbuf) tmphostbuf = malloc(hostbuflen);
++#endif
++#endif
++
++#ifdef GETHOSTBYNAME_R
++#if defined (GETHOSTBYNAMERSTYLE_GNU)
++      while ((res = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &hp, &herr)) == ERANGE)
++      {
++              /* Enlarge the buffer */
++              hostbuflen *= 2;
++              tmphostbuf = realloc(tmphostbuf, hostbuflen);
++      }
++      if(res) return NULL;
++#elif defined (GETHOSTBYNAMERSTYLE_SYSV)
++      hp = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &herr);
++#else
++      hp = gethostbyname(hostname);
++#endif
++#else
++      hp = gethostbyname(hostname);
++#endif
++
++      if (hp == NULL) {
++              return NULL;
++      }
++      return hp;
++} 
++
++/*
++ * Function: rc_gethostbyname
++ *
++ * Purpose: threadsafe replacement for gethostbyname.
++ *
++ * Returns: NULL on failure, hostent pointer on success
++ */
++
++struct hostent *rc_gethostbyaddr(char const *addr, size_t length, int format)
++{
++      struct  hostent *hp;
++#ifdef GETHOSTBYADDR_R
++#if defined (GETHOSTBYADDRRSTYLE_SYSV) || defined (GETHOSTBYADDRRSTYLE_GNU)
++      struct  hostent hostbuf;
++      int     res;
++      int     herr;
++      
++      if(!tmphostbuf) tmphostbuf = malloc(hostbuflen);
++#endif
++#endif
++
++#ifdef GETHOSTBYADDR_R
++#if defined (GETHOSTBYADDRRSTYLE_GNU)
++      while ((res = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, 
++                                      &hp, &herr)) == ERANGE)
++      {
++              /* Enlarge the buffer */
++              hostbuflen *= 2;
++              tmphostbuf = realloc(tmphostbuf, hostbuflen);
++      }
++      if(res) return NULL;
++#elif GETHOSTBYADDRSTYLE_SYSV
++      hp = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, &herr);
++#else
++      hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
++#endif
++#else
++      hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
++#endif
++
++      if (hp == NULL) {
++              return NULL;
++      }
++      return hp;
++} 
++
++/*
++ * Function: rc_get_ipaddr
++ *
++ * Purpose: return an IP address in host long notation from a host
++ *          name or address in dot notation.
++ *
++ * Returns: 0 on failure
++ */
++
++uint32_t rc_get_ipaddr (char const *host)
++{
++      struct  hostent *hp;
++
++      if (rc_good_ipaddr (host) == 0)
++      {
++              return ntohl(inet_addr (host));
++      }
++      else if ((hp = rc_gethostbyname(host)) == NULL)
++      {
++              rc_log(LOG_ERR,"rc_get_ipaddr: couldn't resolve hostname: %s", host);
++              return (uint32_t)0;
++      }
++      return ntohl((*(uint32_t *) hp->h_addr));
++}
++
++/*
++ * Function: rc_good_ipaddr
++ *
++ * Purpose: check for valid IP address in standard dot notation.
++ *
++ * Returns: 0 on success, -1 when failure
++ *
++ */
++
++int rc_good_ipaddr (char const *addr)
++{
++      int             dot_count;
++      int             digit_count;
++
++      if (addr == NULL)
++              return -1;
++
++      dot_count = 0;
++      digit_count = 0;
++      while (*addr != '\0' && *addr != ' ')
++      {
++              if (*addr == '.')
++              {
++                      dot_count++;
++                      digit_count = 0;
++              }
++              else if (!isdigit (*addr))
++              {
++                      dot_count = 5;
++              }
++              else
++              {
++                      digit_count++;
++                      if (digit_count > 3)
++                      {
++                              dot_count = 5;
++                      }
++              }
++              addr++;
++      }
++      if (dot_count != 3)
++      {
++              return -1;
++      }
++      else
++      {
++              return 0;
++      }
++}
++
++/*
++ * Function: rc_ip_hostname
++ *
++ * Purpose: Return a printable host name (or IP address in dot notation)
++ *        for the supplied IP address.
++ *
++ */
++
++char const *rc_ip_hostname (uint32_t h_ipaddr)
++{
++      struct hostent  *hp;
++      uint32_t           n_ipaddr = htonl (h_ipaddr);
++
++      if ((hp = rc_gethostbyaddr ((char *) &n_ipaddr, sizeof (struct in_addr),
++                          AF_INET)) == NULL) {
++              rc_log(LOG_ERR,"rc_ip_hostname: couldn't look up host by addr: %08lX", h_ipaddr);
++      }
++
++      return (hp == NULL) ? "unknown" : hp->h_name;
++}
++
++/*
++ * Function: rc_getport
++ *
++ * Purpose: get the port number for the supplied request type
++ *
++ */
++
++unsigned short rc_getport(int type)
++{
++      struct servent *svp;
++
++      if ((svp = getservbyname ((type==AUTH)?"radius":"radacct", "udp")) == NULL)
++      {
++              return (type==AUTH) ? PW_AUTH_UDP_PORT : PW_ACCT_UDP_PORT;
++      } else {
++              return ntohs ((unsigned short) svp->s_port);
++      }
++}
++
++/*
++ * Function: rc_own_hostname
++ *
++ * Purpose: get the hostname of this machine
++ *
++ * Returns  -1 on failure, 0 on success
++ *
++ */
++
++int
++rc_own_hostname(char *hostname, int len)
++{
++#ifdef HAVE_UNAME
++      struct  utsname uts;
++#endif
++
++#if defined(HAVE_UNAME)
++      if (uname(&uts) < 0)
++      {
++              rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
++              return -1;
++      }
++      strncpy(hostname, uts.nodename, len);
++#elif defined(HAVE_GETHOSTNAME)
++      if (gethostname(hostname, len) < 0)
++      {
++              rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
++              return -1;
++      }
++#elif defined(HAVE_SYSINFO)
++      if (sysinfo(SI_HOSTNAME, hostname, len) < 0)
++      {
++              rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
++              return -1;
++      }
++#else
++      return -1;
++#endif
++
++      return 0;
++}
++
++/*
++ * Function: rc_own_ipaddress
++ *
++ * Purpose: get the IP address of this host in host order
++ *
++ * Returns: IP address on success, 0 on failure
++ *
++ */
++
++uint32_t rc_own_ipaddress(rc_handle *rh)
++{
++      char hostname[256];
++
++      if (!rh->this_host_ipaddr) {
++              if (rc_conf_str(rh, "bindaddr") == NULL ||
++                  strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) {
++                      if (rc_own_hostname(hostname, sizeof(hostname)) < 0)
++                              return 0;
++              } else {
++                      strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname));
++                      hostname[sizeof(hostname) - 1] = '\0';
++              }
++              if ((rh->this_host_ipaddr = rc_get_ipaddr (hostname)) == 0) {
++                      rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get own IP address");
++                      return 0;
++              }
++      }
++
++      return rh->this_host_ipaddr;
++}
++
++/*
++ * Function: rc_own_bind_ipaddress
++ *
++ * Purpose: get the IP address to be used as a source address
++ *          for sending requests in host order
++ *
++ * Returns: IP address
++ *
++ */
++
++uint32_t rc_own_bind_ipaddress(rc_handle *rh)
++{
++      char hostname[256];
++      uint32_t rval;
++
++      if (rh->this_host_bind_ipaddr != NULL)
++              return *rh->this_host_bind_ipaddr;
++
++      rh->this_host_bind_ipaddr = malloc(sizeof(*rh->this_host_bind_ipaddr));
++      if (rh->this_host_bind_ipaddr == NULL)
++              rc_log(LOG_CRIT, "rc_own_bind_ipaddress: out of memory");
++      if (rc_conf_str(rh, "bindaddr") == NULL ||
++          strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) {
++              rval = INADDR_ANY;
++      } else {
++              strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname));
++              hostname[sizeof(hostname) - 1] = '\0';
++              if ((rval = rc_get_ipaddr (hostname)) == 0) {
++                      rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get IP address from bindaddr");
++                      rval = INADDR_ANY;
++              }
++      }
++      if (rh->this_host_bind_ipaddr != NULL)
++              *rh->this_host_bind_ipaddr = rval;
++
++      return rval;
++}
++
++/*
++ * Function: rc_get_srcaddr
++ *
++ * Purpose: given remote address find local address which the
++ *          system will use as a source address for sending
++ *          datagrams to that remote address
++ *
++ * Returns: 0 in success, -1 on failure, address is filled into
++ *          the first argument.
++ *
++ */
++int
++rc_get_srcaddr(struct sockaddr *lia, struct sockaddr *ria)
++{
++      int temp_sock;
++      socklen_t namelen;
++
++      temp_sock = socket(ria->sa_family, SOCK_DGRAM, 0);
++      if (temp_sock == -1) {
++              rc_log(LOG_ERR, "rc_get_srcaddr: socket: %s", strerror(errno));
++              return -1;
++      }
++
++      if (connect(temp_sock, ria, SA_LEN(ria)) != 0) {
++              rc_log(LOG_ERR, "rc_get_srcaddr: connect: %s",
++                  strerror(errno));
++              close(temp_sock);
++              return -1;
++      }
++
++      namelen = SA_LEN(ria);
++      if (getsockname(temp_sock, lia, &namelen) != 0) {
++              rc_log(LOG_ERR, "rc_get_srcaddr: getsockname: %s",
++                  strerror(errno));
++              close(temp_sock);
++              return -1;
++      }
++
++      close(temp_sock);
++      return 0;
++}
+diff --git a/src/plugins/vbng/lib/libfreeradiusclient.a b/src/plugins/vbng/lib/libfreeradiusclient.a
+new file mode 100644
+index 0000000000000000000000000000000000000000..56c91fd880e9d435b62149ded2a0a9067cf8cbd6
+GIT binary patch
+literal 367122
+zcmeFa3w%`7)i-?3Ob7#kOt^><Q3f0^AcO<~5y568!3hNAE+`m6E+i6?m`nnAK`@Cj
+z##m{skG52>SG3yN)+$;rK@jw@7qwN<)@rS`@Ss((D)q+qUwf~0X3x%~(&v4C@ArO}
+z{Y&Po_1|l+z4qGs>~rSK*=vuOUe;J%eQw_gq2!cju$neML!tbMXHL~3EBiW*Gs|&$
+z4gJ^u4d*(J{68?zam@e2k2&sLM~?g7x8qjl%l`d8eZ~1#|7jCnbdKwP=krb){r_h4
+zm;U!EKH~H$y~+G<EH7QvTvJ=oSb4bvdUa*2w5Ecnva&LDXpU9Ov9zJFe*Ff;m6yll
+zm_W;`E6djq+*nywQM$IQp{k~~l6a64wN_1)Ry9_tjJnEorImFpBtwwUWfc`d)~s!)
+zZ;T1oR9RP1+Em%tQrW1gZ)qs2X)G;kYN}aXX8=%ZaH}iLJhafrtEq!F6F}8Qw%A#w
+zD{3ffY*KbJAFFSQnTFKXuQm#k7ix6XXis^4T~&?B)>LUtU5%=k*izP`=$bkMZ)|a5
+zl}$0DxN>enTUAYxOIW!Wu7oRU%40S4b!CmJ?}(#*E{kc~6;E2a0WD><)ErNs1>W}n
+zXz0e9^4!A^tA>|WZKx|-t6b*+@U-&X>iYVM(wYX3r4i_HH4UXy+$c=LfsCkMSC^DU
+zye?PS)Fc9{$T>+UsxNJ7ESK8q8!GF#*Z6>*m>6423LsijWz@`lw6>zMwoG|)?V2V%
+zs(HLsprab=RaO-W*Q&k;0q^U!udSF|T3%LL?$p+-YQ!lrw{UVXje-QbsIjcBsj9wl
+zt${6WK-W|nz^s}&cv?=|+<HAX_B10-nKVgFgcHv?bBdl4SN6T8sAQJUbulsO<T~d%
+z2~JSQ*;$dG3lv%4oa78~7B4IcKG+qFe-M8m+WK}N8owY=62Bn3Fg`2mAc<|6>2?%`
+zLj_yTh|dgx%8AbmM_cy>E?KcBIK0qtsE`sQa8K3Ek&7ZrB8wx7isPRzUKowPP#AwE
+zy7}#0&=ik_mlt;2AAS$?W28D7F9{cv#Gx}9zbYK6h<2on%29Y*cqfkeT}rW%Es4Ji
+z!AUldr+`T77ip3B{$ShVepU@}l~WwwJGcGKVB77;X#Ybreoy!|s$hRxcn6M@g6#{C
+zM;d}{U7)Ih@4gw`Ul^WBnMZ;HD#BUnGdt3e7H;nf-gIi3;}mzcDMgT5N^<#7T^ODh
+zjXzo3Ss0EI6D^KEx$78GaQG$?iI)HFNF<om_Iom*Dwx}gz$?;&ZLOLw3}?4o*$RCw
+z3ioT><LZ{3JuHms3&UA(eZSyMm!NAq=lP<oPX>xxpY*l9@p<zPwC!*DP)Elts$J0z
+zI5rv|5bd~8IkF;pW<TZGVEd2I#OUU|yHM#RD<aDyD<YRhO3{-j`-m>vek?XX)opqy
+z5`3@-B8$7C9i0tmR5X4|cnfq;7p{-Dg*Sm#g|-xiFNdj<$f&|Cv2X)2Z$>7tJdn45
+zjG?0!q0c+e=h04xsDiCW-C(;5)kW>cf;S!g;@C0tL>K%3uZ`V*B)Aj~f+vb}H4)D*
+z8)u0#cELB!p<7TgIJ^K|mj$m;B~z)A>ip-A1ecSJXmA{cdtta*ReOk9L-MLLTnm>5
+z+wOuA_;6|a)4{fHgN}3z4y(>=e?EBAjR2w@wc&Xs_=x_JYK^~Kh>9jf<A+P)Z_SOr
+z9f|+?@YE`Ge!z~&kf5P-Ce>4T_F5-+QxrO+vguSo>yvJ@bq_jquP@TM_*k?Y=4Q3M
+zkTh6)u_pj74`*Ze9B6vrOM5IW9PL<$9{YK6kHu2<Sf1*!_#>*fr01x+f^9Ur^w?#?
+z;J?Ci(54%wf;v?HIk}VO1>L<R;pNfJ`_;)(l>c;5e%He^@RjSMIGfsAKRb3zdG^qS
+zs-!NbPI)DS6Zp_H$iSIx<VNJ{aY|>2lAsgg&_EQ{{-$%cngn$nkR~7IKmXVm9Q3KA
+zbK2D?m>Rnz3JvJ2ce~)+t8k(fjKdfi3vT&Q$X^xCKIFmxRY(t^q(Nm3r{AM9b$cpN
+z$a6xq<peS&$&6szM<}T+;95IA<yvueR^@u_Z+$x}@(>NW%k&h1c{h7ca(;3ADLDHw
+zHyVE~8b6Z%k*-O}-HiE~%cC<cOUr*ckty?e779`MG)Uw>Z5D?mG`|<eU!o~~ZhS9I
+z@gGLxpX&L%_3diR2mOqR9P=5^;?ekPN+=TFr)rGEpNwLz97ZQ+R1Xb^MB}?3PDk6Q
+z7w6%qh$s;NhEa|-H(ndg2|idG?pJ~<$5e3oLO{wwP*W0r0~67RLR@kR3Xxm550@}K
+zT&PRt#rJ46bdGzIWAgyGvO0dim=~24F7GwXO{H|@uW!Z;i)I@uV~sVHxINKq1?~{l
+zy+Il7viY{Q47b)yQVS@(_xPW(90ykrqyTlI(~myPG_rSs^SJ?Hd_INw()1yq4=%X_
+zdFo2yPwPcDo4$bJR0Y1)OOdb1HX?nxphh|f=@m#1e1medE|ue-bFCChJ8)j27^_xw
+zAL#Y|3|w!NalMXQ1R<tB{wk3gKT33#rvFKFwx&NJI;81OiO$jVXGG^|`g5YEYWfSJ
+z3;N*0>E*b@L^b0oW}aqzidm|eG`AV%t<+4qdnK4^%>-Pswm~!f6cf`-rdx@e^_m&z
+zP6D$@GlSe>FxP5ku)7)BS~ZjHZUwVNGb7vvh~2E2F>WWA+cYy)F*`JKhGKSVW}IT~
+z(@d`WLzLO2nF-3aF3se-|ABh;I`sY5>2<5>gX~`0sFB)7-zJjjJE*zb2j8LAW;yAB
+zLSX5EE^ryt;beBdD?t!SU8&F?3OYy+oAkW#5KyBcJ)az+$urLZsR|sB0{xwgpMgFo
+zd~ZkD80dXgf81~=8+)If7$?1_5uJv*sYHL0(c>yGw+wXV+OqXd;DUsF;6j3Rn*#Hw
+z)~M1Mm{0gpO)t0{^leTCjSwPL`+7SWn?ch*^S*#;h586A%tl5K1)QgRflE&UsCBKR
+zyF8}L9z}gz_o^^(J*ETY6F}=R9jI6bI;6{1J`OrZ(^a2<&dXfYT;&8-WBBrz4pct{
+zox8M5O&0Kd=q04|0NIcppeh*{3t#}{O$}V+QZ;Hw1eUqu=v3Ft#cHsGHFJq#ax}AC
+z70H9j$)aaopwuN3wLqDvXO&_`=$vw;r%*E$sz?-it`<Fcfz>WGPYcwTdM-2VS)-(K
+zQ1nSit8qguR^4%p=0|`ZNW<}%tH)TN_Uq^vB|BYYL(U-O1~*XWeiNXsx52FUa<kq>
+z(+^E9xpbT^6I12$29vr#vwJs`<+-{xqLpQz!(OWT1SQns63yMv>V5@NuU6IW(n-V2
+zb&7Fy&h=_S3TS4FvL#D1ag~#;nHyA2NHZO#{Wq#=xF0(eL;ZN4XVgvZBcO+nf$n%Z
+zQ{594J=EO|`?4FW9d{^ECu#Io36jn%M(J!}lFo2Vo}55WPRJ?}7VL+jq10vRfg+G6
+zufT^Sni?p%+m_*s9#+Fy!<vNHC`4R{TZGuo#3^@!@NIQY`Gq<LPMyygq!`tz<c5Yb
+z<<zP(<z!PTQ>3<C3p0`>LzL&vP_qk*Eo80kw$pGu9zmX)K@_Et^x@8+;X{d88UY47
+zhJ{D0ZCdTP=aTypx#vn%rxE5V7R?JQu7F(V-@56VQHqU-V$Gf>MMu{-?o45Hp2ZeU
+zU>kI9QL^x?WcK`IHcIm&rO|cu>m0XOSZ(6$ZOHL&J-YF95^;CZC#4*-;|Xv#&BHhz
+zM%_kf81<tfq-TeDeeLzWHy*qZB4g(Gy1ly*-+JMHyAfk_J8}Dfq4)`^AL}mmU5(F0
+zeb})OND>;3OZk@y6@Hme8>*}6LC72QH$%u{wt?{s*$L(zT|8~;eH+tZFO9^p?)<c^
+zyU;OSDN^B;x*yDIQtBx#b#x<2xp|2q-6}dEL$x?%MV{_1=q|AZcalZ!<gxAo|JJur
+z&r&yUth)@AdBw;NP07U!$9v5nn>;3|O}|3U-AchCUto;Ylq5-N{i{-y-FnX;YR3sU
+zAJN5$2CH@`^=Jq=%xj2e)B%*kw5lgpnhMebTQGt`G``$N<)kG}P5XpydkOWZDeKYX
+zDeKYXDeF<0S@aC{X!4Zxm`qt`ka9{ial(B62kv4T7azEb;1(R_Q$Kv*E`a$sETx{v
+z7Ym;=Ej(50frZum*}~_NEqpH7r00@NdhSb1qESEw!7efgc9B7_i-rcf><!bPlRbkD
+zia~EA8}vr9%ia+Cj>{=z5BI3&kax}cPx0!%2-hdoW$z}}|L&JmXg1lX&TH=HW_3rr
+z>Xu+ssp>vYu1<Z+A}Kv2Y?kf^DCvuum#Z%d$K<*-jznBX-MJ7+HzJPfs{1Yf*3UNT
+ze4m%EdB4Z!cDssXy8jXU-+dYJ&Rm+oA3^mrIXB_6#~J+3UnWFzz!3a<n*3Y!Og2T$
+zWS^N6fLA?D$>$^&QWLW8Dr4$On#a_XF@c=kXD5C0)8t)5<`GJ%Z-h<>odUly=wBPO
+z>r2S|#K1o^=(`R2E`z?8<^WFa0C!a8pbUTJ$(aM(fxWX%#LZmT$;dbt5bh(G#CM;x
+zA&x(DTE;mU#kjHW6@&=pJ30{GdywnT%*dc@7i^%vCp#5leVFZ4Jc!u7q6yy_T(@`-
+zmFPFZDIPQdnf=cKfiIOP6413#k)YDwOY~<Ag8u2a`yJrb+l#aeR9bpD&LB@-;e!nW
+zkb43f0DI8sxz1Nkl9q)~*NM5V0H>c6Qtip^<ynK9ZZMuBhK^R|o}BCE4<i2+WdFx`
+zCy^<`dO7)neDLNeipX}HQ%_-;r5Vdm&G7iOt}_4-W<RsW;$%IzxQHW2+sH)a#GYob
+zs3JVcGtCEfl)*xHG+6d2l|8*L3lG4ftsF9LfxGxbGLGyY1M@I8@>TDQy#coRvbUZG
+zrDsS6zM!#w_>mNjH&_Vf8Y)#UOh}mXm6NFV^2qhmPpZpQ{zS**Cjc3rILh_bbruUL
+zUtH20T=2FVvPq;!yUrpZ&t?JFStz8bYteD&nlHMhdAgPeY3iDP9J&^WF0<f*<0!Z^
+zRl%jlQE*wRg3G!UoX2gu(`(~mA(vygP;#9WLN3Ik0!n@dH>Se;kU_`^`JbkoFgfUW
+zN{|y$zTs(ooPS3`PRQ>vq~x@g#HTdjN`^2Bgj|)d<L!;YY+%smG&({X6}-JMp;}W?
+zfjGu><_meD=c6S;id$&N&fhMac*b>>2q}Kig2IVwASk4Gi8Xd}(-PZFTJX!8u|S$(
+zH2>M-X#Ua^<#ruMxn)xBe9vtQg%n4T?aNZQZDA_6E!*DRZ3|Pm4H~<-ZDA_6bw5MC
+z&3+uiHv62s?Lz;NF^tQnHul1`oszUffx@(UgD!7-C)3g*(kQgFM->)E9<Pv~(1X3R
+zWS)>K5@*R%8->}JkQ4HHQ%)FhhU>_1*R8>)w6@G^ZJ%S?g}K%1%6URQ;mK{?wow>y
+z74(avPGW}v+QQ^d6OfR<XUON|Z%^az?eu7x5@Dm5zL<}G2i6I59fPRiYfL_qfX?BL
+zDC8rggp_`x8l-Q!5@JG1523rZZImG<u2+_5Lld92GpSF-m*Oj2w8TeudJb7Aq&UX!
+zG+nb@81Vv%3MoFI8ia1}oOJay+l9Ho^T-MzZ#CtFNqBC)km4@C1AW4X?@~_mkhA@y
+zhIPV2iaH)Q!RZH6oplE{+Eaj%Jf3R*%x0t~MzxTM&RH&<v)FUoav{ah0cY!hjp>2t
+zFwgY~uPhN#u09xdLdx9WI?KOfO%srk;U?{al#tRoTsMSFoYKoJ?>awb;Aeb<ZXu0p
+z!QO6j`r|CWCs9sFqg+?Fa?h~*tBG<#Cj43|el79*S}Lwe_@z|HI})d(kaDKFPHA^n
+zm3H?_DVyUR#7-H0eVseh&p{+0n9O7tR6A1*zn$Igj7%+JqS&Xj2y+_G%w_?>q@!J@
+zTFAsi151RFUN?1k?PKD2nz=JEi|^PdOro>Ogf!f-!*fR$Pg`i+j*Y^|Ozt{mLdt}$
+z<b;uP2y#NoFi>*B$Tih$sSFNrvzaHDcv~qG<^vv0W&y!I_C{Knkm6;f!*=f!ZvD!H
+z7rLJkDTKP8Zz6PocNv)9Q)LN}ZWr+GS{C%AMND>`OTSDc&B0UYZeJ**E>Q#r-Pdh8
+zILIgXP<AYYx;w}g!bxqLBqI9fN&0Hh%{|>ky1A#j$fBMq5`$B?N3@7YYWLVuDcwUq
+zCQ|D1?%fs(xsM^bP451MxO>4xsS0-g_S?PS{8R<If7R_?a6zhq-M{K~FSs;S!R}vm
+zpJfjmOgKl#zyC|;NWnL~f{TO{1sFd<n!39COLV>A>6$O3C~%zxLYlg|yHIq!=IL4>
+zq$qHmr9zszx_k9K*3pZ9<HMsAAu||CJ#xAiT$HL{cTaRLI6qav?#<3(drnW7D&+Wo
+zX{r=F%`3P_NKt@(6w=hy-TFM%vD(wMSjdk(XrYku5?E>%imo|c!9_wo?m<h0q~HB1
+zVFK84jWA{f$7Ae#F?JY!7NUeXQpi&nB4g)o7fxzOF`0_}q7wsHNGV0Sx(~YU1(!;}
+zA)Z~!g%nFj*U}Vrb-Py;?|<q!ah{NaJoO8O6!o~H6;iCncO&hk#Hakcy)L0!$f2I@
+zOS>!Tc5%Ft6>Lf<5;EIUw4%GB6$x83B|p<2_7ok5NH=r3Yw33Fv_&uwyFdC8AsMy!
+zb|IvU*`xt1R#WG8AHbqbq<qfwZubu&^E|g-Uq*$Kl6c1V<&Nvt+w>!szLD~7>XjB5
+zAht@mm$``VzAoWoBOh&fxw!Y?+nWA-9KlChUfTL=ZtDR)N-J&oTT!pi8G;*g*ZmZ~
+zoZ$C7x=AN~LUU8&gqphY+UAPN3G1g$DV;KDd~Ho#^ZN0t>zXI5s);o@rif;+EM~&$
+z^78KTlSNfhq3&``8=9QlTu(T$WTu=<k8NnEY|6!3J0S6zE-2XF6sxGHtOAW&K-6DT
+z@4<LeR?{pDr_m}a{VMPH^4gk8C4eg&bQtBJMVG@5P+rIQPj>Uq-#TZGKWn!C@})CM
+zrp;*a_kDQIGJh}@xVg)J#ZuqM>}8wh;BQ4yWc5e4p3(Y<zfYCF<_`b**|$~t$5r{h
+za)RSabJGJ4r?=g>c}^u5U-}*C{>ewSAN7~`#<@=~d-Njz9oO8m`C@-o40X)$zv0aG
+z@3?06l4k#(oqNs<%m|F|ubJ&XVY+|Kk&EV3`m+MD)en8(uYb{>y_8f3)~5%c@Pxpd
+z5McFzb-L1f(jQa$TNC<A{GUO8>ov36E&>%>6PV$zz1cq}Fx|h-cZU0<|5YdOX5a+>
+zFRpoW>$1PBUUts1$^LxbX!qWSw)+>};cvdfH*)Z_i>v*6oxnhUFc2zv+Mo62>~mpb
+zW~>CCeeVD>$e(d-VELlifr4e5XZZVE>)#N#BQUzvzjfo%i!WM6zI+`&=WpG3&zxn;
+z{BOHUFJ6*&iElK<VQFc7RaI%sDJ{NGFHUU0+PBj3>N2d)D{ZRAk}`VPvZ>~ZN(ia-
+zZdm))T<OHBYns$5vr=Ov8HQ0+J}nTVC6WmVS+rJJURl#pSxPGto75O{78YGlSXvla
+z6mj(1-nCkJX?+7N%X9c`@4CwMSP52Nw>qRg=*4VW)>v5)f}LumTy<Gp1r}7Ef5GC=
+z%>4Y&<lITQd7+7U`BU<y<eeQFzc$ufS2+W#9V;7a%E8jY*%>(3#!s0P8oxR;{=$i&
+z@l{Q+vhp?Kv5+%XSstrz98W9O>Q)=|HrH{jWI!pc;H;}xjnzvav79a8MP3i+ty=U9
+z=VhKvP*7X88VC3tUc)lZ3b?(w5z85Co7dJkyjoE^qRDASo%vI!3+kI!p{1quwH4HJ
+zO;jl#S#@nqQ_PuAUB9++f@;!)3onSwo6s_IUeSbZXXON(g6b5%qP`Am5UqFb)q+CZ
+zBh;sO6Q5VKlF@MD8mu*?GrG=6at+DiRehFiYAG*Oij)hI1l5{Vtl+~~;l%)?cwJ*n
+z41)y2a7m<OaZ%~KNbv$kEjC1tc-ENfT}zv2j4DNXaUw0$U0AeWNznpxV&gU_mp7GR
+zAg(HFs&p_^d6?<4-jYOWgVDWe-DqiTJ=XCyt-<2U^7>{q45$|;I;CstD=Ntuw4_0w
+zCg{<6@=qBS>8hm+&`-SzHzQ{)26s6YJvg%P0qZVH>&lw6ujqWENm!}U3sg&0)0<F?
+zMvCVr;m9yPjb{~?6eSf@mf(zolOaN_ttkgZ`e~tReWNVp<i)!%#ep3doVt^nbc@s~
+zSo)}0)r?h_x@bdXxr3z|r7aDKL7>h`HFt#QRH1gO_0Od(u`&!^8LzP`O4s5-hef>W
+zusqbMT#xmhrC9Ha(+~yLlvb71)H<>dgieqqM_)^{kH`{bxT=oU!m66onqjOBE>*LJ
+zn%<^NV$Y~GzpB^Cfocqp|Fo$|L$guORTZWmy{79<;CZYR$BKLyjswO49nRE;N%}Au
+zU3_^ntyESXFI9tq3~H`xZmL8X)v-z&&U%a@URn$HR5ZoZ$f2`;Dz{-3+|%5k$8J;Q
+z<)wA2%yrg@1>dp=))*^Z%W1+<Ok-tJb8Sq`E@w_e1<v_1XHE;{EMA4N-K?k4@l%==
+zm%lN8N^ahy+(~1s=~dtB4Auw7y<&mmuFrB$?$<kTGwvV4z=v_3`UyRfnRT5nl9}D=
+zpPLz~$;<{H$qYDDzL4eA+s1{NS;fFhfXNpN^%(fP%&f2a&dbcc$$wsEs59-n%$ys0
+z6=vpLmmbNS+S+?==6kOHX18zV)JSGtBr^vxkVTpEG6RKpr^CT(56(SYk9y~?Ff%)v
+z8KSCG-cy`+Djjv+e93#0^G@cxIhmn3l1KMSlun@!U2Y!bk^RFsPrX5wu)ipU{TF8L
+zaDBUB{>*OXN67ph6IGGsynif}fM1NWGW~Qbmm>M)shpMPclaSiH=J*OyW#u=svDks
+z7cbd<y&y+e@91|@H{IWTwU;X6chm^-$_wGwOH+jPj()uo!Q+MS>lG5hdPlz+tsbk0
+ze(JNQ_6|%I1~&lz1C4%B=LRquKUw&<6P-sSU%(mC!d%AX*{J+fLW^Wm>524!&+P$U
+z)&pMM1HP^Yd`l1btv%r1>jD1-aPq@_JQU@<-A5UJmT`6d0;3;HNM4?HsdE?D?-<YG
+zp{veYV1H&@9*wAT7MOV>ky|ozDqU;5DVDG3`UWC7N{Dv{$X9=aSWrPd%-{!n*_Fr?
+z=B*7%$wk=?<v~~JM7Fy7v@f2N{clGpp~fcWZ2DeCb2C=os#HXoNH$LWP6;ovJLYU~
+zheEYH-azy8e3x;N$J?JO{e+LC-;}?fagmq)?dn1Pc}t$o6H2e>gR-Bl1=6k!JV#T#
+zbZ!d%O#{aZaUMQ|1d-@~@Hrkn$G}a$wHY{#LD5gk{3y}E)c>i0)Adv2D|pJLY}3vk
+z^ngEQ;HI6Q8@OrbS!qy=MEXrTTMV4e6|v`5#-(56oxN`v@}{33HE`3OR}9?r!#@n1
+z`dsQA!{@o}x7h}6`t3>sH|^hU;KL35j~Y15F;eeaJ>Whb^kk1IAMOD^pK<XUim6m#
+z$eZK8){>X=CDw!dPYv8`@6!fu_WRogZua|812_BYRKC<vdriNwxS9w0aGU6$uaA0u
+zpljE!IgiFLCGrE|uaiO~wN4O6!C&I@kj4fjVp&x2^2RsGV>N=8@|Y4mb9g+RW#MVu
+zujg9$EUu);!Y^Z-?(Zmx{s%SdJ+Kyh8P{9J`GT+Jc2!w8v(Duf{u=AqXyNjzPpgGr
+z&h5I*!uPPAZ(I0bo)>mn_-N+o`b$adAHnuNqG1oei}~Fa{#({B{V#fC{(ae!mpjF`
+zEc^nl_k9aL#O?ar!sSQ4K3q=fy-CKKg+IV{O8Z3qefH;gOMVmcXIuCOtbdk;-^+Ry
+zTDZKXu+qX$;dZUHa5+z|u<)tOUvJ@G;db3(;SVx@r-k3h{EscXmhDmTTHtH(56!uh
+zp0ea~x!xBnd=K+)Sa^i}^R9(Q8UM_}FJxREB#S*u7?<m{;PTSVY1}`8pU-yYS@;#K
+z=UfZl%ko7QKAHLX7XC8(ZH0yJWxmG3vsr$pg@2#z`MHJvkp1$Qh09O7hb-LB{D&5P
+zCD-e6`@}!AQk>FB7B2HhzJ;sh+>oDP;lsGTVhg{5d3h~Q>fOQiv{~}^aeLzy{xa*o
+z#lqJxf2W1t#(M6x@QYPz9p@nnpUU`?7XA$DdCtN^?6+4fd^_`pEc^iTF1K6!Z~@mV
+zzfcMOb=EI0u?YSRmOsPN)4+C4vGCE%&$Mvq$9Wb$g8jV0!Z&cems$At7~g2&;~DR;
+z@Q0bd&BDc=?_0Ro^D_(o9_!y{;fvVMzq9aTjK6N-)0lt9!oSD*vHV9R@&6viXIOYE
+z^K&d*+O^ce^SHiB3l~2(TKG*|?==>F5BJxN7B2Sx)WWy1yxb2<yRKsVKP~y2n19K_
+zrM$ejBYI@skn5`8Wvu@TOOMPC8GNHD^4GC^wuQ^m`%xA?h4oIf@HOnWSr#t$TMI1w
+zw_NX~7XBjZm-}<E^FLYs8cSaMc7uhBf4*ViGJo!{aPiNNEL{BafQ5^HUSgc41vXK6
+z;)o$nZIC1{au7!UXLE**siZN&+ZpfA-xoywImYGX62bfOyfoaBpUL=C#>Gx~o-@b7
+zL#+Q&3ol^2*}{t%Z)Ke9q3<K|Dnh3vFVEZVHRP$xRcz<a44m}*n9tuw44mY@!p`1p
+z;3WT3o`0S(aFXA_^3NJL$)CvM?G*zj`PHoFkcG>2=kEqidgMBK)WAv4ORVQ}11I?k
+zt~Y~k)Jc|b8RtVST$UPy4V=ozi{N7nob<@~f2M(x{0^?Sz{20*@mgfyq-PS_f1!bs
+zp25s7GH{ZY`<_b;oa8&0FE?<Km-B0_fs=d_e+h0haFUnv?kWQ(`5&?TW&<bre%$X;
+zKgrVnUs(QTOMWG{_nQVz@*VVnbeDxU@+0;i8#vXwMM*o(qZWPxkLNv%%lRlTmp^Oa
+z@<z@9LytTYpep`m;AG-+ocW%Gf5iAdE&OEu((hw`kPiAkm+=e>FJpYLg|{(&iiQ7>
+z@zECkYsM!qE`FHJ{dJy&U&#1k3zs*LRv7xJsq*}y*1)M<N4VZ*3qO%M4QZo=Ph<Rg
+z3tz#wj<c4Sw>L3<yCwf!#=m3X`xuw;EB=3*@%vd`{PP))&;1rI_q#7z_;+-(oc9f!
+zPj!{^sezM=f6nql$Pgr|m*nNSS;)XielPwhonzo6PtP1F6&X0m|4E^av(msxK9}*!
+z44mZeAOn!rS@=-OL~65eSyy+jg+IXZ4_o*##$UJaU$LLxv2a;IH-yi7>6a_`yq;^}
+z+Zn&iz^T1*-H#bKnX;SZH(U6h7{AHFk23xv3m?z({4NW>fbl<BxZLj!;dw&ZC5xP<
+zFi!5Ep?R47R$$4??@KEUc`7r22T-MflODOg*Bdy=&u00Ufs?#k-!~dK$+xn6tAUfe
+zT;Dqloa8CC2BmEl{vqRcGA@4D&3-#z$dmrl*$;16^74C{kLMezlm2u0$Hm?TZnkTH
+zfs_1dmLFo^X1hWLPVzrz`3V+&jPXf~OS=wnyJ`%1rJu)tlO->|2Y%g<r+Vk`1L@lg
+zob*Wle#gK`zK!MO`aqcJho4&VkFxv&jEnv0bTT0wGUQ3mLhhFjEP46eau5k2QN8s4
+z5$n%3aMPZV22S!5_^0X985etU*q)_^Jdx#mp02Xw<@eHS4SCXkCF{T5z=?c{^=vh8
+zlHbqrw;DK+^1Wt<fs=gBAbcQw-@u8K??*o|aFV~C<sY-~F2?s5IFWK6`@DtAed((P
+zPWp$_k19xS7&wtfcpM(FaJg^%+`viCm8{3d=P_X<BKM8`4V?1!viuOnr61)@<x>rL
+zI>lGwpHi-Ylb-(kK=~{S&tts6!WS}LY~d}8FR<`$F@A}KA7Z@1!u#_N{A(?I7UM09
+zOM9Q<aT~XAc~ko~3$JGRpBp$s%0G`9IGu{?IrD&l6U40ZhJlm3`2R$nx5Uo(SkH6|
+z|BUfs3zs+DFJfHALjlhZt1NsjkGHiJ-o*IjJ>VNGoFe2?y1ECv-NJv(=XJaXe5-|L
+zusz@C0sppz4`=y1d%*9q@L#Zh?(G5pg@r%K*O7;Mz;|1CUvBS{J>b8#@B;Sdb3NcM
+zTliO5|EoRVJY3Y=&tHjDf3di_?`0P#{4}m##-Rf75n_U5P5G#W7cjrl!sju6pM}eP
+z)UPaD?kf&jxLlXh*iNxWu6H2|m+Ov`+q7XVUN6Nl)~JuwLN#JrlH3@*M4qc&63$(P
+zeNYsT+gw*$v!=3kgOl4>PkB^2KR4fF%bQ|T!H|NA%2my)u{TXsJ=7?=Y}Km9$`;}9
+z25ypM8Quz7jfmzfES#YW%RDM28}&N5<@IaVVy%ReTZfm>bMZDiUP8y~o~*XA8e0L;
+zUNQd@DFh|tN*O<*vw#ViZv>a|Bs@KLqoG+K03QPpO-$u+OYbmHJu)`wT@Xs6@lQCP
+z&IGBnik~kDFGrF!(>O4s^S@g@A7x3W-TvdPzkth6#L-MrzR(0gi~VxEkTJg9@uYWh
+z`^8_9A-o*R44ooF$NRYa8&-!&y&}6DM5_KPDAE!Qr|2W~AJr-KO8>0|X6vL9Ut@u9
+znUhEg*(+0ERDL`^(5>O?J7JXUx;j!|BzG%yEK;66c%OFp>yVSG{r9cXMWj5npYE6J
+z_J0$Yt&>Xb<N9wV#z?m8y~wjM5?{gt>YHEUznzdxW&i7Jzw{H?Pq!qt{SN`7`lX#9
+zReEodK4w}chS(~{y%0-P{)=h4{A7LbKBb%-f6e7R0VY&1d>c$5`vzl{o1CfV=)%=f
+z5$lrnGwZwxB9;G+vj4hRko-rt)>2;lN?)_=xrd7EDyL7!d0QX6Ps<$TJKJ^=-Z5Pl
+zS<lL;KKg26*H4eTQq`YbfDEMn(g*L;u3xXDsHr&KJ+ku8nwmc)MCthV$jbhTSG`l9
+z$O618c_Qz5@&)aA5{-Y1Jx?~jorAuJVtbLmV<cznc+wW8Hy~uw6KrwQ_BAvGn?V)j
+zzv=Da(usX$O5*?Z81?8uQb2p*w4DIK-~-FUS&`PgZrdMX2Xt0vErdI!9zG$l2M%@%
+z3O=yHfz18U;A49t9~GYOhMEs<`m}HCyPG~eEq2FaAyUelU_p7Tc^~-Br7pw^+_tXf
+z?8B#;d&cac41Zf!EWo<new;c|Y%8YCwZ3ntR8RAY<Gu4g!fq={DiS|GP~0&qdv1JV
+zc5(dttV1W__1nj&*9|j*?ae@GFQGtT{LjjDkJF%Fcge0@Y6G3agS_?%p5H|~T9JPf
+zo3>2EZdTM8#;z?|FAdg|dVi_xRUaKwbqmQLY(1k2=65NRRE9R>2HNH3Q*^qn+1RCw
+zwvx#2+H~%OeQ9AQHelBT)VV(`JfWhpr3xDqrA6a!MdNRD^o_PYk=D8S*cV@X@$qvb
+zo*K0YDRwBn8=l#HDC@3Go6zrtyQ7`6ebHdybMf5{at=O3gCpAdia$E$*=Xm@$KWS6
+z_LA&q`yZO;B>E42p}~Yi`#NYb^3^S2G7!ERJSqox^Emj5+TiWo)^SM|RK*^TcAP1_
+z)ZW#6uw!Q6@NQL^-cu>E2p;GtrD|h2#qrOg9p^+l*697=)TTX$wPo$^G{0Glje69a
+zLmjfGk&L3ZzST-5Ecl~Uh|@ylWp$^=LWG4zHBH0666-F9#c84Xs?gfXwe{HXuzUX6
+zvRc|<4+|^l))b4kplY0^M^z|!y~a>#q`eVCvDgNPkuWktbQ7(X7S-UvEO`%8mzsO%
+zBAS$@8PnJQ(#AZ!5*zdMGB@U--FR+5mF8|d>8ZBhNuz5<zX`ozXF!>#w+V85noH9M
+zy=4jSR>GT;I0ZUyllt|+RiFA7s5C_f5OBOd)b=Gils9_kodRAxv_24cpRV%CF#)~n
+zkETCvgLFXCM~TkT^goHt*7PSthcx{u(K(v_jOaW~e@^sNO@BdjfqIA-a9m=dnsF5~
+zPcuHnEY(b!`#j8BshM<_wuzz0<1meP{m~5X`lA`%^+z+j>yKu5*B{LccK-xzt(wVp
+z{|;u0W=7~;e>5}3y%yE!N3nsiirJxa&QQ!w&5TpbeVWO2x1!80&G4>2n#p(nfqM3;
+z$7oLAR@DdDfo;@C?W1oK$@Cr6T<(MKTm+bQ{kaoZdVo4GNF7RMXVHx;q12TMrC?YJ
+z<z0XJs9PG9MGr4j7WVg{Qh~l_6#`PV_tpFPXxiJ)he`|}8Qx|`eO-9UmvQMIrCi3!
+zKZDddGRmlOZFR<~zk${xC!?HRAJro#qoNXYNY#^3c`s-^ax$t8g3cR6OKCG!{~fd*
+zIT_VK=-H*^YrX)!PcMH;50DM%0jg5_(#@i3l%zYLjT$%z3vu0n38UP>Btfox2c^^_
+zzo{7)xnz;*ql{(lP<jBP8Qz9RGrSFtW|pfWw0+BID5~_#%P4iJHCmv|)U!%4BXkaL
+z!=srBRfM+TStEM#GFH3f2`x}#>fvp8bj}(jMceTF9MY<L$vLWfuhD!EO&LPtL$=|`
+zs9l0)E7`HgQ?eno%*F8!Q4!qz^nR<F?*Y(+q<4_<sZ-fcFQE>_5?ROhIg@oDX>^{9
+ze~|4EaFpxQ0|QZd0R0?x66K}Uw&BxHuXicgv|7@@q<ZOV09B`DZ&$JuxJV1!o{+sg
+zq2YEq(e&a@cLW*XC7cSB+-<+a^mqzw|1yFoN~h9?J3=)L6fGTa+|za=*T40?bs@!u
+z<wv{`<&HawY@rmQj|4k{hL)E(;&PK|aNN-}&?t?lt!s4L)5X4#@&YmC$(L_8pB~4a
+zR)+>tI;~s?c?&PBGw|9(Uj*&OE)KAD6n1gw>!gix=VNOUJkX#XHIqAM0=|o%b`Hay
+zid|ZTuL+74xp^q>;ycsnQgjcpm!KeON!z+}T{?vNV9;>N5#qNH^UAyeX0tBiYazA1
+zKq!%W2)VcETsNA4KLkuq3s4aXC2&&qYY!(I&rW2zIMa`@t}~NNLp#{s1r%KWbTPC)
+zN}P!9rE1`(Bz!^&oN8F8ad%=;4asHKB+BMUUD+t>F(XW792l<$s0x_lrfvYuX>{hQ
+z)AV`NqEBHzkMtUv%_M!ogu4x~+Vx1UA&Qb7=`}LaM_^E{kwK}4eXSn$&#oJJgE4mK
+zn<XW;;bPoFoF*@NpY~0W8U27zTF`MDe?pRfWcak_gpinXUdzwZE%&XXK|*_djKW?Y
+z7{tbQG>}l~U8o#Ol-o?_xj}l`=Cd}8o<!e}b5DW`$ib76`j5_(bw&qKZ^75&A>5Z7
+zeg;^_ZKqF4{2&3d$k!pEW|4N8MaY@gi!(>mnVi@EE1^D#amJC_-aF~auF1QI98V}E
+z-v{)WOCOZ{57O5Um3n8n9^CIjuYkG`=nW!B%>TUWmB{=e&7(8kPn7Qcj`zUD(-@rS
+ziDupA<|DKWec_pqFih9eW3_+5ZXy3OdqkwUv{{7g;Sk8d_5;`@!Rez2xU;X`OCiJC
+z(?M-S&@Xu}iT=h`4k(kE*h?ZPdr4%;UJ?WJUJ?Vn%^;M*LCIT743@nlPVnkgyA=$P
+zy(AL*LG(KPq~bv#Z$}8)1VU{gaZ>XB4WW!lY72;=iLD!OsY~qCfU8<^fuxNiPDzxa
+zO%+Z}lp}U{Vh;t{;UQ$O$Q=RJ*x_NMx#I+F>VTNBdQ*yUViSi^#@-I2jV&8gGfx*e
+zDxCv{cdQtbfiW?#H=$z_Cg3D98<y0paS1WK`NR0cUJo=R>hSY(ZZd?|2a*7c6=TN;
+ze3zesJt_1lq&}fRB?LDV@*cX!K|)+kA%DUUg(6$LT{!twDn$TKtpUzu0x`yfoa#Y~
+zg%m{yf3_3TQF1z)*(e_oj84cKJWE%IO}|Y*zi0A*2hB^?jE4yfJd@BZq^ufqvFQaX
+zC`u@jwPWQ8sJjIV?dtx)fG9)+xbCHve0iyb-Ai?=E5>TB<s)Lh-M4PLaO*s~kH-S}
+z<&QQ!p@c3FGSQS$F-q2-K}yKqdId|hhQud7+;*f-DS)}qiT+(K$`hKFOaIE~Nfr8B
+zG_B$a5k@^xwWe&5H2iRzw!J5*#hjttDO?$&IE#do8nvLUZYVn>>^Y`e2THRp@#(_Q
+zE#y`YS}5cv4Cyn}u1<8_=oMTfq*<_gltEGdoL6w+@0gT=I6>^{a#-YSKBhZIY!SuV
+za;|fcEw_<XZ02JhrvVFahn;q;_jZBgz05vNvt$V*jZ6{CcnK>^h<GmP<gC<z7p0&`
+zr7&842FT+3Qgoe=lRap;kn+?mb=OJ3kzT=tLXP&J#iuhVIx(}@o;>l(Md%hxw>^+l
+zS}aTg!O-_vN+<Hs9@RQG@wt>8E91D4`78J+oh`0Sl+@HR$oZUAsO|sIn2p{~IOSxp
+z3avO1@f2Y&XfL)RUM#4oTYaX^FakS5#tY}D%IZ*zC}%`yMBFJ2Qy3~x_@dA)h8$pA
+z_sdDOmYq&<QDWn3>dw`6QT=RKWn*I<#f?-p60S=m#eW>(2C7Q^8<t{+WuN~~Zs49Y
+z*MIlMK<L&*7a+u<KRs{{4!(!eAGtFyvRNauHFAC6(lo#SH}174@w1If6+IpF&o|yN
+zXHM}P2)X|HrHI?OG|<}m&$bEvYTqa~FsRi(B<8<hsc+OE|GBY;181HyCoOF}qC5^s
+zOY@Hnyof?erYo|F$ZLt54QlC|f&9R^6R2wc6~2*p>_|~3-%MZO?|08!(Ei8i;~e^+
+zs{PC8<E|B3eb{x~2)np&bz@mWwS!0R^a2S-UPPyruWgX9iz<@Y@x@*&Ene8vP*z^q
+zJ^CUCA5(o(Q-??~h=GVmk1B{w3;;!5Ypg3Ti&5+~FD#*Yl+PJGhC<|Mji|e<wxPOA
+z4H0NqSW&YYA>ID(3f!m~RMFhvg=(ajZ|Zjwiuu+(AR}5CtFQIqGL|+?EJcJzYDZaZ
+zUGv(16`fInGJ4J=@1p<AD2;foT7`It$!`8{g=vIE4b64sF&#Kgbyd&77*&0hWovbV
+zlVaQ@f(TNuMKT!!LPgXwBT4GuiYY?mc_H-F7(qRa<&G87k90O{aCFo}9q>{@B~~F|
+z5#s1|515D_w{(=mazr0&n24u*UNA&7ytaNFIguk?su-N~MiiYK$zc+`&Q|eEODibC
+zAYsQ5ClO7_*Ii#)N2QGziB<ItG$eYAjaXk}ghlk6tpXIHF;zNnBSqg!gdL;^iKSef
+za!P4gZA}?sFD3^|MB7)@mes9sRCGt`)ub?q)=z?oh<?UJA~|4UX{nmBOIMLgXq1=N
+z#TqgEix;lf=WS`Jnyo3jOhsd@DzB|?Lg>-s53Fc(ixE8WI3gw{h9)`6i<HQb5n*F<
+zLj%Tv5h9UFn4uBztE5D=tgT;7qZ_S3JkEq>J#4)Yw@})EE0PK#$>U!I<ofT2MASc%
+z;2LPhL@WU&aWd2`(7%oecz)*V0e@%en1&HNVNp-HYUx^wq@GA7Vl2+iyf5I}+gHLY
+z&dSJv%xy}NpRl3s8-0k!c%46z8EQ>yRHBHM$TF!8bOZMPy;y_#DV*((o?{AT*`kW~
+zdp|lPXQzrOND_W85|S-HC>a3P5C0VF&P#l!OJgmSH6we#X^f<jpV9+9qX)dO2YhZ1
+z_@W;0OM1Xp^?*0^fVcI4cLG;_V}Hq0{r~7e{`)=P_lO?;@*_{MALv1z!`b2`taAHZ
+z3`bvS^i?u>s^$x|+%VE@8{OsLK({Zr5YT)lbG3b)=r*Z)6C(=p^;X?7cz1$S9d2d3
+zY`lY9S&0TAouUuw-E({e@X}<a$elDwC3f1S20qxp@hXZ+Bu~HPiu^A%tft5z1}^<W
+z@_44|$!GG=C!8KTik^^x(+`}2pJ(8v{-uoLX9x9ua1=*M6^8s!@S>;I!0885!P|Pk
+zC1#E2r}K@{BZj=Gf3Ja?`kys$I>)76iLpd}pgt1(kA^(`Iwkla#>F0Fsq~>CZ`u<l
+z#Yl7r;a~LpfN{~Y9(k1RGvrM@2Mv4#<V4R$25z=1o6jrCKFyFntp{9QVI_O;YnGR2
+zo}@%LJ%<i*JLQ)*!E5k!mlBOhN`m)h`_zx+z^OPxB<74!pIY9$YUCL>)%zyfeU^ob
+zzts0<<Vn5DxsoDFUY=}}SolAgmq%uzCym=xX31}6KU7&bv)y9R?Pfh2E%|ZWE}B;<
+zNxfII{MR(>;iH+C=b$403&ww7$scC^K?|1{JC9koJg0in!hg^FuPpox=6`45x3m4P
+zSol)r|7_u3<4N(Lg$I~_*TVBz|A!WSGvl9H_;el*F87=G?QZ4=S-8Y5I@Q8Aaes}q
+zaEX07#lp*2Ugl4!H^y=jn@{j(*#3(xJsa3RRTeI>QX4INILmLe@Ez<Id4ezX9%Vak
+zwdD7(-@a?%^I5++Kht?CG20%s<ey;u|7qcL?V<FNh0Ar~O$+~k?RnqA|H}Lq7XEYQ
+zGq{|zcO?5c+rqbSyGB{~JIqhC@N>Cc5}QW!f5!StEO|fcrzfVAM7}TMRTe&g@g@t;
+zW_*){f6BZ(sTKVa8{k`(d^6ks9SfJ(yg#<^Uvj%1w(z@|-)G^Evi@Ft6nj>(o{)u~
+z$>n8U6#17JpK8g^Vm~af@ZWI1Uu5A!nXj<$$5~#s3zmAzbT>IyS@LurPic#V-@$g;
+zvGo4R?cHI?U&#DD7A~=c_FA}HpPsdFiP2@p%#->0@0Prr|DRa+?QH)5wpaWxUN_eX
+zTe$3zEc3C*i=J~W`6AXo$HE&~|56K=dL@RY=%2{)8!Y)4^VeCp*z<J@7khSCxYT>U
+zg=ezA<a#dlNdNuDl7EHe|6t*wKa0n&=;_7d@C*xof%Qzc@b5ETY~e2B^%gEMGdnE&
+zuiP)+vhX_A^8*W)-yI*c@O!ym_FK5<dEUZB&#M-m$^Md972+R>srUiQle^e-Rr4Ue
+zktKQhmt@Dfo5k%KY01ma;HMinUDu9qzf7@l)>B~MRPWtf@mvc}XFYaoJQ<(ME%|1a
+zzs$ma#JFtaC++<+<87Awcy`j)EnL2zY-5~?ljuCQ|3ORsZ>*=w!uzrxBxbhQlgIdP
+zEd8rk|A!VXzg&K9=$G#xRHPqXsH7zNuVMWI7#I7)?1wxHKU)`f<{CH;C6#lLfm2hj
+zX88&Wf1L4aE&L0{Z?|x1*H0~6-dFjJh0B_}g9c76k?+^C$W7WSF-o)fhFS0};s*=w
+zVtlrNll~mGUt+w8o~Ky8){rOv$h#gJEc|7bzs|y6XZ-6H{!hjw)*7)q1e8U;V|nU#
+zIv?ey_E#-EG8ues$Wxi`@Ho*cP7?QBa^CghFTFCZ<a&9Mg`dvz(y0bc_LT7;%4eMH
+zC;!Ns6eWf{)v<#0NNh8yx1I4)OOO0QzuM44=Y@PvZZUAuwUhN+W8p5_xy8b#G2Y3z
+z*e~~y_gVO#sc}e88hXeN+t|;~TKJvZzkjgwyv=&vv+(;F?@NtAlJOwVNroCYiONea
+zXEII)vPZ6GXIt`kSgg`AL!QVL?1w4~zl-shg&$#j1LNYiVXXf;3zzpnZZY(bo$~U^
+zb_?&#dhWJxxxW9{!UuD|-*4d}|B!`$o%`j{9`L;u{vg})R1f&G7Je<;^ZOp~KUnzJ
+zxZhv1@O8SooVP4o<p0aU<@wa#d%!=kaCu+wlOAv%{dj~#+0<V(-0$f<;F%UK_mKm8
+zz)!O9udv@v=>Z>U;ooKX(LLbfExdv4&+h@BY2h+IpKsw?$SFt?15f-T@(V2a;ac2T
+zV&U=}cDaR%e3^y6%6ck$z#G^fWDi{mrm~z|Qv_!<-fuW^{t8~t=ZB4lSb&Br4_SpY
+z*f?iyvvEF;{{2`ise`ZJr-%GpgkPc1EoP*ae;tj*46suF|D=#CP6+;_K9T-p_c{ek
+z*l)&Vi2xtzw*eX=1<cDKFj`YPxZmjc6xGAG6MDTFcoHLAx)G#GSJ(jKBx|N|U`VGe
+ze!S)LQI>Sd_h67JNqIJ3U?oe8*ipc=U49cA^nDUGlC)pSUx+-SZU2wr^Uf%$NGT_H
+zIS3o0JSo4H&sUMRWiLfWs{Y%Vqf0zXKbj#?|B>xtzdUcO2WIO8<a{kipN_NLa-c1H
+zEo5wr%H<EFPy7yIImVWy?-i-+U(XMg#7;VrD{T9}2F%t8$eG0j<-U+GO15k#uvGQm
+z%=JroQr92<cKvsz&<V(C;reABB#e?>|NSX2lKU%{mpwlSqhy!=39wZ5cct(jo%^=^
+zU93~u309?<G%+CE&DTfGCF&PDo<RoDcKLTgy2NCC@IIxS9O?HIp*<lGBS)BAg0^K3
+zA&W3;m^wLJzAI5wQPO^a-vp7$e+SrqQ5K}`px^YQJa>=UPtBgYs7UBs`gEKR^uhbI
+z?N4Pp2_IzpSF&>Y-H=WxyMFq*kgERZC}bf0QXjleyZ*|$776DPqLimT^@pbQ=afm4
+z6qtYJl&Kmy{+KTB<$BdS1&Y)$UD}UrELprT{`uoHFr%$+2M$tZv>l-|_QV!M%Ri6q
+z{+mC6%?!js(fz9Ye!bO5G=3m{MznQrKt<C)7?3@W(>PGS<>_)98AZp?$nQG*eAUf~
+zm>nvlNXIo?ZTz)MXfQd6{K!R-B@}RmVvl?P`*NZk^@ve&6$L6894_g&+L_yaEZFuI
+z3Lz#<QT|7&&XV$jQ3M{znj3%n@QK0Ug@`=Ux-W1+$5oTHIKA2N7>%xy_%U5z%+YB4
+zPvA<<K3E*QU~e@3gu)R9<jH8q^e~hS)2-<!p_nztqMfy_FB<>52HU#|5j$mAuq_*X
+z8-)nsx-1H3kv}0*9Dg~o3zZ>feqeSyZDO<|5_p(KL3ICa+MRKB$Mn2ov2cLnv@E-n
+zw4wCgoWl6CMnsq3aHuE@2TICUrgb>fz}ACq<m|n{wjYr)b~M?GKs(B^xt+DWd=fVX
+zy*fKy_?8p9q@)A2k#)+7gnina5}4dED*&rrH>`?u%t|ZnSQ048e_qwx<woMO(xSIT
+z_oqEUjaz#0q1hDchG;belmU^4sey;`@WJG$Bq44x=k-BeaCm{)|BDc4WpT8#F0k<M
+znP|W2HE}wP(V_duugyoJo%7t1_}^4kd)GeyjP-+~txpD`9akTXwjXQWe@T89MPj)`
+z#j;T`S<3N7<T||3*)lDZ9AITs(+q@S!J9L*w|9zsYN45nsDB~sDc`)hI;39W4j~u|
+zfR-9;L{D)6Lpe2d*fSjam4}KhSW>#M_~N25&d>2MjV3)zCu%-0A1o?Zo+1$QzZ7T1
+zpNO;K|FSqMX$Q`u>H_LXpD&;;Jn4b^fc3rs9|8P32YS6vzdWjkB)xR}6HV**Cz{sr
+zPc;3{Hk8WNw2ptGX&wJW(>nf%rd7~{shZaDPv{#GRx7xqD5@Ebf1(+Vf1;T*_cEBb
+zQZwmp1DI;faQqX^aQqX^aQqX^aQqX^aQqX^40c<ftyMGG?sZ_cXolmTXolmTXolmT
+zXolmTXolmTXolmTXolmTXeQsK<wtvUu#R50sy@i>wT&97ee`W2nZARX8_>8H|Kx07
+z=>d8zqu&kqAhY{l34&1SN`-C{bP!N-w5lkOe%5|uD23@d)QP6OP$%?jZ6?WZsFNT@
+zzLVAaTQ2=PrCQMY+bTvz5|friV!iKhsoH=u04Ijid%OEGICa<Rn{g3L@KZS4L3pvv
+z@y%cokuzq{!gh5}?VCZrwVvQ)lD(OC<AdG@bKDc<RT<)9^nv7VBlJW?o=Dm$Wn&Hc
+zNg^#T208OF{(l6`L$MgXKnK?#VS?#LM!<broIofX2#r27oXB5+{CBz7#Gy$6Aox}e
+z4{IQU@(3eA-X|Z?t5S}87JX7uEx^&;whZQ;LT+-;5(`gNBKROR@;pLxA~3*W@j#(8
+zkP65TM(#EWYphikic0N}LUJA@i_NZa+*zV4n-*5M=ac&>h3LbLlJ6;v7>dT2$z6ID
+zCXkT@43Cuec}9+9#B&Pm>H~ivp2bjv)yN;}F7Wj^Hq>33h@dglU8Y>ty^_jp|7Imu
+ze`zJ&IB0`i_d`8*n1|mCoPIqd{2F{BaL0_qFxZY<iiexXMQ3|uNoOB)19JWA@SWAm
+zxEmStQ(vN3i&g9^oNKFFno1oF)&?$cwV{Xx=`9*}dm5x912gP=KD%0EJWyv}%suXI
+zn~XwwY_%khtrp6ml#Q^u?s^$7Uc<?oLsgB+kKU-D@lVdU3ZL_RO}I>^2WXg{M!Et!
+zX{OWUT||ZnrPSwn*Q0yCpP>8v#T}(3IPg)TNZ%XmtkELb_p6?=KCl0eMQqRk83JBl
+z1QipYPjWzpzR3X@G7<q9`bj{B{t}QOQwL-SLSY~ygTg0J1c59L$beW1^vrPpG*A!&
+z6<T4S8Bl<NFX+$;gAzd!FvliBBw&`MuUkWsOC<#&z*ZN2irj!u6ckV)J2_;+NoK%<
+zp+;zglO@B7-jJl*j@^(5m@r%y|HgSI<)g)R*akc70=D_naT-puqb7vyhzO&S02M}I
+zbTTAE1V?%-K?#d^g)Gqspd~`iWk@gL6>gy?xL8Q<lGS~MuDV*F#2ByCJR#?J(8BJD
+z1YsG+*~HWquhe28WrD}5Z6UvrkP`A%hEgv{-od%QNfZ=PekY+w4%cwDci6$y3w%US
+z2qERYKbR%tz3SeX?xYbEXS;Ax0R%n0OzhyJ=)|ILA<I~o&spaPEw3QL)E(Cd^DRSA
+zXsMbEneQ2b0AebUN}=gyjFM6*%zOrQap9yLRNPKG82AexQw27d!PSeA7>e=^;~K6I
+zu?~c!TU$ygmW4}Diw&$0Q5%GmmpXglHRFxW$nMJKX|0J*d5uJ@>YI3YvOOWCDO)y$
+zZ6eanwxv6bfpl0Rd?(|*5EKBgu<~Og&RDzBkGRBGcF4an(3VXRJ3>Tc%i?~{RnD1V
+z4E^-e0_h{|%H?7Iy<TrD7V=#WS}x>!4C!-FxPK-Dg_LiTTJXy&T_lyh!@B%V%lhq7
+z!N(?OE9>IS-+NZf6Y_NrS}3aCPe8V!aR79#`YPgOOItjEi51*$YxyWcR0f(Y|0&Cz
+z$R?c3N9lK4{sqYUoDul^Z$}ouGW`jw%gZOMpE{*<%B1lK*V?>({OY>q36m$_89{Ax
+zMWr*Lxv4QF)4fpB25eK1>j^vfu7D*;NGdP@uiZ}-I{*!pfB}AdLHe>F0TO2bvLJPc
+z0!4Eu0MN<718@_@zQjCtqI<&m^ZZvVo%c*&e#^RP`Tn{)`~!3S&7rqm@((%^nz41p
+zaDT>|ffI|q5%??C+WWQzM*7BN2S%K;EN}_d=wEgR7VQr?(gw1c*6)wUntlJ;!0f<x
+z1FeBkKrdMebQIzZfFyy_-z=GX){p(`0|VdkH{SE}z##w0fop$q@s4TdPChp<a+<%X
+z%74<$!zcLHE%o<V>PtgsCLZP_E&b-lL$vn0POUMm^48clm9<o=#lVSmscLC(%@viU
+zF$oHgSOCrIo)f}qb#qm1*=j5p_Ew*#sE5`Zs|Bz4O|?#i7O1Xoj3H<*79Z=y<4wGr
+z9BrT#Ui7?5b?6oK*rWnr&DsW(P%t*82+hpT4^7UUl$#ftn3q2#Z%W?Tq48^D&2^PC
+zR#(<lHrAAbEyIfP85p7Cr%VcsUmY5M;l$ARDz$KVd_yC4xG0a+H)4kiJl(>AHCk2n
+z?<|K;4lAJ6bte|}CwxK6*C@_Gd2=JymDe_}t#fosk`@osf^O*>y#!t_dnZS$1=nzZ
+z^kVX|Znc<s60N?YYMN?R*Hu=8)PnDXfnEu6cM?PTdF_5_VkI&yZ=W&={h#P()py=H
+zXu?$_1J(UtWJ$TI7`CXu1-wqXp{ybwg98Vwy{E&O_A-5iPIjPC#h^&F*1xoBEk|-l
+zvfm4Q0E@|9)L&Dl7VInA%>~(X?$=>Nucy(>Q5Im(+Imb?UVC&i?UnBrma5Z4XR0;-
+z^)w=BougM$oi#d|0Aak$pC_{OXU?1!%2~Xsxh~eMNA372&5Fz4m_H>qZ&L20G1h37
+zIa@s*0%Nb?rfZ7aLaV#%qRg!8XdQK{e@<p-16EP*$;^uE%M6^4Rn`9MR2Ve5eOFIr
+zutvMpH&3mzUI|^*_@|^Eu_V@mpO+cxOgk?#=f+-<%)IN;BbifMd!L`V(sy5Gb!}!t
+zG_yLAxw5!#=G4N>yhvsaq|eLDMro|yF3j*<m|0zs*-)*7CPDYFR1N%9Tdn&pq;=m#
+zwC?*FtP!873Pv)}idl+e`BVqG<o*9^z_n-oPg(;`Pe{x);PMTS9){9Sb9SPKC#mpI
+z4>&#fApM(gq$E!n^Fb57gFqyCR5%@UD*ZEiz-RY>FX#cM$4062*8o@c@cn~4UgCQj
+zV?O7F)I6c6>kw$~8VH(yzM)B;CRUm2`ARC&rghatIpdNETXZ6G2H{`Uy2|q*8(+rq
+zeR0GiKrda&6v@-vBzme0`~(A!_kcfd;PgO7^!WK+mh{uu5d35VA8O#^4BXTcF>rbi
+zCwgiamv)gZN;ezwG_Q)hgy184O#Oc_<W2mbft!Ao`$)Uq(WDrO4raXz7#H~v2_eZE
+zT*@~6zs`{7r<6**m2q4C0RuPvENe$78xOxcKYUGT({`HuiwCeOk)3^*rb9ob38!~E
+z|Hk|P3*U-+Zc3z+lE@dZAIUaK#InhXmuE#JFHfo{BTwZf^t{D-&a&`*tn6G14>Mk5
+z;jb|+*HE$3Wn3Q62u?p_Q!3L3uU(ti9ywn`{wV9Y+>)Qg_(luAi1|(nmpFmaU!uR5
+z<>bkP;Qd+u4=g>hR`dZ2e~#^c!opjamuF+5znb;GV#zmhzyH<3Wi8?n3!le&zOZn)
+zZ|Tc+NxkQ=+z<=DmGO}l-pu-QEqpQCd5(qmV?1i%xvYP&h5v$aiswg3?38Cl@=mPa
+z<*ffIOJ06*id#4yi>q|2h07XhdC(~OWv!OI)>zhb+iQ)lV7>NQ<CR>mz1H~a>`!@4
+zC-r`l@%Jq|@09+v@DG^J;C#{ZAoKQG<B9Ayd#!OP%gb6=(Q_TkPqXyrGcV_#$agYs
+z&d)TzJ;QchYU$a<_;)S*S@zpcEPN;PzqD|9F8hLo%VQ^5Lne00S{~YRgp%O0_Tgl1
+zx8Ty>5et8r%P+O?SGZlP7$=rRRec*Qd8xP6z^QIYH(PikXMDrbFZX-*Som0$|CNQW
+zV*IZLZr;zlXW(T2Wh|eOrU~)SUdCk&ue5g);}Z>eD)URm&thEUWxg)7aG94bHuTWA
+zl2l>I@8Aqs+eCHJ|4{Ci8!SEh7{A59Nqzz2w;MRs`xyQy$r=dJ|5KK~&yc6QE4cI3
+zj#c1AUe<2!HRMS@-CIyH*Y;8w8OJZNJXJ@k<(cSfh90@cK(_OD11CL`xL-fE@Rf|q
+zO|94|<FXeI4ypGRZtv*^PNdv7%GzO(muInsEKmB$PPs2xXyBCh0^76P!d<qz(!#@x
+zU&gr9E6;jwG;kut&Tkty`SV5mQ~HI4%XSgJv+&{UhxaW!kMX{IBPjOBFD<f<yWqcL
+z`2tJ+HO7}&_}h$MZs99=ymc5jnHHi(A$`NZN%VS_|B->4_sI`1PJKe-^JV-~>N4a>
+z#SYf<XG5OKEZ~0mtAUfAAF%zj!3!mlrT_gb|AmF)r)rh_Y#bG*Dj(*0PquKm9!zIk
+z?3cB2=Ucd}?OkBu^K`Xp>lY$LkKmVD@@sh9%6_vVFZgAayxc$4^?<inxV#f|g@xk{
+z5S2DrxX8C#_;u{Jcn|ni3;%@s>l+p>_gmkxaFO3(;ooIDzt;o)BMX0w?fgj(`1$N_
+zGLMFcoYx0?z<F4yel&k|%3`}@Trum&eXos&Sb)r96BQ!kLhwy2SIbAicQF5~jf=8>
+zd*5tpt(Ltw%h*Qy%XiNHfA3nYPsG3Mcj<R#)y7&h1r-Ru$CamOLe@spvke*(GKPq!
+zG#dYe^Y9}`rD-<6ILVr692nARiyv=!dfrDmC*t2sQhu5Vf|mN_SiqQ^Cn6rR4dM(b
+zCvq2ZdAt7gTs|U#d=&qQo^md4i8&8(`3HF(kbEg8{G}jL_1`X@2=z{h`k58gE%i(P
+z)dRD2lI{lnA{n&Ck1cy`59P1nhcU9|n{-mL%hNob%Kp%JCGOoXk-cP+ZU5JR**dA@
+z9|zKB;(kkW-DT-MJXQVkQq)gPvg^MSSgQK_(L+C^mFhF`Vawi+EE^-~S}y;xm1(g~
+zPiwU{vHjA|bfk0Nw!aG)>CD5wnTq&9+<)*mlsu_lj?W+?Rrx=1#gnBVAElfef6wJD
+zF=v20@Ut?coWO^;yfsXnY$<OQkoHUYH$kN8|J&GqD_M}5LoSi>;#Yc(X}L(1ILhTe
+zP+a1}GDrE&ww<K2`NIAzXHs)$NZa+(v({AgALJhe*CF3bcKuEG!Lq5cv8A$6FWJ)T
+zutF+nT7Sw~tw~d-oH<eD9{*acT@NHIC{Sbp;(-oT`)~7FsLgM$hh^AryPw+9I2yk(
+zTn!-qX{>co`*BCH{wOEd_6Xb&?Ywv}7SYIt#KzhxtR)KPKOKK!_kU%zKObx_gYXuA
+zr1h$B*cWW4XfVa)i^Ah}(O8dmUg;~2f6@9$UNm^&vz_M!TVH>V7Dcso`J(MlZ<*=F
+ze0UWc8+zyEcRfTGhvLpyIPZh#j}-P0sW?bYiFVY6109R8)a=Q$&TG|H(9e%}cGM=M
+z*g<8<U7I!`v}fTH(ayy_><t|({4ZxWR#Xk6l}|a*)>r+}GoYgV>5|UswBSuI!phEN
+zSdLW~URe^a2#2ubYi|6*-G|dkI;ZD!7GV_?Huc{9moykVxWxT{Ru@Ip>L=K`@?jcJ
+zh4Bvy$GoGgE5^DjY~P(0j>3BA`?xrMQ2-eH*INs8wqW(wdwMNfwETr=YnQ8bAzw5&
+zFK^zl=-K<44@J-Z)7<z!f^A39+~W90hi@j2=JYD*oaqLypNa}2)RJT2CzU_ipN{!A
+zxdV%V<x%xhVeo)fY#u!@8lU-IG`{etxBvItj_-x(d*j^pH-qh8`GR&3*WK=I0}dtG
+z!S+9rpEvKN5n?PJLpSZ4>84X{>14q;RFqB?r3asi&;0E0oe^}+I7q=zUuTg|`n3F2
+z)s-dj{n7X<x)0qwR8ePPjt^eVK2(8KTPUZ>$9{{Vho36xKv$3u^;~CRKntD&!F~Rr
+zWJa`ejvEO+SQs9iYzA2tKGgF0v129i4-P*ngZ9t>6fKGGIdl}wRz_eg7@Z5n@eda-
+zq`kP~FGb_%4qm{BE#4y?MNaF{W3fS<gR?h(LX&yRkjVZb2a1mA^@@?@krjJrO<noX
+z_$yeaSK|Insiu;hh5loacoD`at!z}1HydjaH@_W-sPiw4&%d_t(E^-*T~REYqveTt
+zbOKJriaT0|h!gQiOgd@=Z<^`^+bD8Lv}0pV{`1lJhmX<eq8*DJ>if2?AD13%i{Z-(
+zmbGO^JKMtdQGY^BDBAu}tpCI6bd2xUCE(u>jpv+b=b~^yv;#G(jP|ZzyBmN-&#P}p
+zi3NG>UGY7^E!X2VNeQdmDBQdfm0&$$VYr%zsyN2KQk0K#3v}?QDzs|V!*HV$e+|Y|
+zNHtr20bLzMVXU;vd5C6TR7qC|(zPB(=qd>}pu{kAZ2`twVK^3iuqdl)_frAd9llX1
+zf~SIQ1#nC7fg=1bcBiLpX$!v>!i;oF_<bCLZPz0=|0C>6PfEG=NPPeLWhI^Wgf{_;
+zJVMq*9-~h>&r9M*u#~Zomw2{!tv@wd{%mB--eUKKBAh}u?S-{-%l~osrQmQXu61@`
+z(4@uowjRxhJ+3N=w}mNJ=r)7iV$e5&j&^8S+H#)qN;>aXO(54qq30hV$ao!kOZYSJ
+zFftn7r@Hsx$)6lMR@hlRxG;WDd#5dY1R_Q8cZ%}gEXv2y$W0DX2`0OS{HG%iQA11O
+z|5XzIh?jomKd+vf$Croak!u%KVGu4+mRAMeee+0g0G5n`dgn-RY-I>+ML19u%zbNJ
+z<Zw0410~oowK%@N^;lZ4{dH(p(2?MBlsgj4!n#(J{sZ`@Q0y5f01~{8?#Ymg5lhXx
+zDm?Eo%sfDr6@~*xg5#c5O6XL)1KkyAJ>~}6c0(Z2y4Q`MDaX#n*a&`gG|o#5-<Y;y
+zZ5HT);`m<0&W*p06}j<4>gnp^7za4hR7OO_-u4#0-l)z(Z#pcDzaDI-=zN$B>3lV2
+zLmD5Ej;|;sN+I+s?W~wij*z;L<#*vKwy!rvJ=aJR$l<TUUmq2Qm!K_^z?XEEgrllo
+zqSWVP;L{H~Av#xZ8bqn1RB4Rzn{r@K>(N0QPYOPGWB3Sis&+peC=5RM=fbmJ4|eW{
+z?>gpYMR6&}F`FBCgz8mF*pfs208l$*gde&J(<V-`3anZ_na<h<>W!6Bar-pLQ?@$s
+zqn*u|GfKjR!KaGypDxPpdYDdH44OhE-{Wc6z5ze+%OExfxH*s)d<>V+C4feAbiW??
+zQ12A)pG8k~VRF(4k8}(U7q{;1c1Q5H_!GtDpX2sKZVHMq%i*q|Bv|-{vzzAAP;u)Y
+z{Uz?l#bdB$dtXWX4Q2hz&PAgz6dwt1LR~mL6lkBF-WeI!XX2q-sAcH)oanA-Sz|@*
+zhO(x}t{60s<b61zA-iy>#A4p6LST=8Vei6m1;O^4Z~`BC1-+owoChDc+Eq4o<l#Oc
+zt@BoOyYu3RBb(pg`<)ke|2^yDC-e=^i_y*oA8vQ{#a}FNUW}mo-j22&z}*fSx%rE?
+zgD|7~+2HlR!K4*&_eM5<M#C%kRa$;oFzu1>`>-Y0POtAoJMItv16;J@k??19?8HP$
+zxeq=ajo%;Mp|b7|Z=z%Tk?>B%KcXfq%GX6>xU3*km!Hnd^Lc2KV{b;OLiRQddEyD*
+zfup)euwNqay}|Z3U{&xzOlHWWi7ohGS7-F?_NRk4-9^RV^1Nv0E#WkXVIcAv{%E`?
+z&pWYkGV*;TW^R2x2HX2lf8pM0suLSaex8a`tpp0O(>;`4orinj*Z^FO=zD-30XQ+v
+z4?dvXF+I>SWV%1rJiSls^2j5&tvGh*m!DG4IS*67#%S=nPXw>M3&`P@dESlgFUlkJ
+zhbkc)?O2ZMd*?h@9t)Sy{Eh4WYX_?_@)>#UVG=&Lgb-MVrRclp?oE}B(2cosXg1VS
+z%kKlj?bGKuZfA5WmE9dv)j>@Mn5WDM@KA54Fy{#+$?e&q?h&ntL<t<4jAHTEj7h~Z
+zBc%aqQi{fRcdPHvW(@ppC|lu!6+Pws73WG%dH;z#ZoXls%#FqIu5JZoV*KErT#`EA
+z-%of2jK1dKgTCiY3pLl3t*WgI#p**<HFXssfe|A>CtJR*KGay*P`e>i)mXnav>;Mg
+zym%p(3XN)-HmZ3X4k&7uYpg79p(4|iR0SPW1z#$sYpZF3iS;4%8nBcrudXa#gLjT$
+z%`_NQURl$E_nebWYOHK(sINnCf^{{qYP?$Bf{m;yLU?0tb*wt29wXj?-W`p@9>78H
+zS54K19x71E@PYQEwyUnb4sV~w%B!)%U<fwU)cs3MJ?fD*Xun`vEbJndqBFX6KvRAB
+zn#!2+yY2H;=y}yI)G2D8@8-s`x{CU>-IO%c*VZZ(^wUlv6@0be7kI`<7g;=&z&wz6
+z*NbSCCiWK!KN<v-s6VY2y?w6eKzJ7NIXHv5+X@6uzZy__RfQ86Gl>eT$De_*gr;fw
+z3?<?Cuzw*^>PQkUeFcGLC8Fx;)4BtQCfkVQY6IG=KKBsTC-4&G=+avD(XRnfWZ$)z
+zhBcXSz%ZO^>4U|u__>S}s9F#7d;c4l6P3;VjwIUB@8jnnq61R&J4$qxmiZ^q*_!@@
+z=#ZvAB|1mbpAoIY?)Lkf=&2h2g6IPE$hM#35);*otC)G3@hN7hX42eW!@QN6Nq2t-
+zrdl%rm#ozffcy1ROibrwx<5qDdd&=UJHTwx%pmu6FxP5kunK$7s+nx}5L9o`%n0{q
+z5W873W8A%9Zqv+I#q7|`8H(AdnQ@A_PcykLUCwuDW`eS<OEdW{ts&d1UpVY{tLlU7
+ze%q*#+DG3elIc6Bx!eceq1I-h@3#T#6Uas{_NQJXvojwBK`3>lLXQbLNDqbnd2J9-
+z1Eha`hew|24V%mne*%iT9Y_&)a&`;u_p^w1)u&H=`qgKe`s}4X)759+0VD}y`OV#c
+zt}8f<>Qar&%Dnvt(5M=j`7Kh;^frQh+Uy5Fs>bx!<+Dyb0f;_5vWC9`T9wZlL4w?#
+ztaTK4x<9q}LlCNXkn7BPmtJ(yW!_KJnRSFz`858)ZqWLq&H9MM15ST()_EY6vfgm)
+zX2|pjP#5$GEJ6m>Ya;~)oOJ~lrDwp|l*{xqqSGL|7}<kKM#&EuxcJv1Kky>5*h$BZ
+zjRThw=_)k?mr-l9X#+2Q%QJ1@B~)^-Zs)5Ym1(Ya)4=8QUJX6>b)NDKytEFLX=N*$
+zs9sH%kt_9J8n}w~64590!16ZG`h*@>@hi|FEnhhpvy(od2UcAOIxiiU9cSR`#h~>G
+zJ+PYkZkLv?sRX`Hzv12|KsNLVP?hQxs6K&f0Gvn`P91oWOVz0JVc;@%Gm0^Du{u-2
+zI_DC_<Y;EODv}44H;A5j14~^pQ45rrdR8fBgw82fdI~jDp^8MIhvG;md-4XZcBy$<
+zpvKg5nQ6}&C6$AsLm{osGHS8vhif$70zRA0MJzf-hu~3o?Li!s>{gKt>Ch8X-GO!P
+zy8v~)4Q9QUoAoxDerR&ZrQ>v&m@1#A9>EW6c8@_B?sWC}FSUIRd#UP^l{qag(cBHK
+z?k(s!t*YHsqfs;0DaO^z^=dW_Xl9GDB}+4Lm6NTR8&pn6GaaV=H>zs5A3GI8{n!h2
+zYol&*2Y?<%2KpxM#i#!O_)|1*kgq1te^BONk{x^j9IVS;pvn#oNLj^eH5btN$fPQ(
+zOVrXO$bXJkqShb_fI5RoU~qrTwWoq`{NrhA^p{Bi&FkvZ)Qx~YE_rEVsF<o#XAReK
+zy++b+LH=KgT(6OyZM{ZP3sjL_BMmdJRA#;-C45&V%)FA!)D62bQ6fD|I{m}(tBcA@
+z4;$n;Qiqm8SIh;X9MZc$*|uKF^)B#i>s>%S5h^XMb9xt0O-ivT5J?n^v_gY3m}byE
+zfe;4l;Hv?Q0Oq*6-Cv1%cQ-XmDROs{XG65G(A^zHxe)D->+U8Wj#S}q_K<)MJmUUd
+zjW4$Xw|Zeh0hlxyEjTF<`Z7bFhWjX0_C=*k(=QqH0k;|Q8h=^Qqfaj_MO2_asXGeL
+z>xHIf(wy8U(10R++n`rnLfXOc^(aTxHJVJ5)E|zagaAo+^=eEDLL!Z(Gm_F+`fx{+
+ze<(3ajihu2eYiQIY#f3GC71^I&EqUd&FWiLPtREDPD(oW44Pq5u<DmWcO2R3-@55)
+z&5j?e*!!*?N7n{7H%u>)A!$`TvAJ(>Gqo_<vhc|a$C(hoV5T(TbIzY|L<DnxAe0ty
+z+(jqhk=BG?iR5k}9$+Gm1)a$_ck>bT2S(>3WYAT4`G|8AK=wqMD<ts`nT~tO8qzyK
+zObIjLsr$dE`||jziYxwm-%G+{OAt^&Q3HleAq$(Vnn<EAvY0@EL4g<`Kq>@CUJwNW
+z8c?1w3f8Kv)M(wSwzjn{xB(*2x}mk!y0qH5McgWixB$O%X3qECdGp=_+u!e>-~D`&
+zd*(Z5&N*}D%yO4Ew-DkUWN|4QUtgJ)=avRLI238|R?hfELMw+VD~FhsI!Y{YZ+<yp
+zksMUa$u2VN=2GqhUviOhz%g>AH68ai1L->FFb;EKim7EC%f5YC!eXiho>QhOr)cNW
+zo<USD-pElmvY^C9QjR*@(Jv;{=2sp;@5~^T`-qvEHqc1_%YqxZMM_gQzPFNI8y+qa
+zodv|FyCcV{>W(=&&B3bDhp6XrryYS$B5+xL<%AD+(_6%sb3G4fbmaUR#2<w?ZHo{i
+zTbbyR*o`mjWGO!)T;a-PRHxEVy~DSg4^eb_zFw*Wkaq2IoKb9&dv?GbMN4-*&Yd0L
+zdg*biIKb}ePvgTmnxZRKw?vVnRmnwxe*M*;TVa%%t{5DLX9~ytyXSFA{a&i-Zu*kO
+z?SXX*D4!`l^dR;3{gNEGsD3`>VhGbC!kZ8_m`k{CeNEAsvhmh~jXM3dPCt0CQM3Oe
+zcEt0Nn){zTQl)HMgVK^-i_-5vw`PBrXQGsi>yiC0*rIj)J2v?ql4F&BR5E4b)hPTv
+zvUTAPzT*1Op;di&keraR@e5e?5l<y48@C|cmQHP$vhl$~Qtyu?{q$-rZV#jn;#uJn
+z%nD=qo9OPRlSog>#tks#Go_O-UDiux^BTiE+(Tg+WOCjWIOjDG&k5m$*eV@jsT<!p
+z(8!~k8ZO6~qjpyj>>lf`VWEc^y2qKr6<_o4;r4Xz;&R?_5F=fpjAlUh72+Do(ueY-
+zFjP$lF%oG(s}6U7yFW(a>5@Sgbo$69qt8%N_&_y<GfHWi#{IOD&%NC|+{y0dZe(ej
+z;02s{+Sigg%~jXTbh+4(i1EkJzkFUFnuj|r@HnZ?St)qVQXxElU#<P^@4H9CnM=8a
+zET)9CpLUX{Iqg&-#_>uM2TXP=1KDirZ=vZ95I?t7-mF#9K6*SUuHwOlhEc~KH-AkG
+zo`HY#xT${Tti=|%O9N|JYx2R(m%5b%c|-Hz6OMB_>L*jW^98BVEjZO`K|k$`<CQXw
+z-a@$5?yT-)V>bz{9KBg5A^1#?SJxMGT~!a`cE}^w9J_JXfyRBI!Cwv5vgx+siQf$S
+zhJ?q&t=B6Sx;L=4!}N;$z6f$yc)5E5UBc%qgoRZgrh%9MA|J$XAw1*Xl7_11W>q5$
+zSx<|TOj`7~wDPGS>|kS_J6#QghKp$dp^m9!gLd&o%f)`$iRpk|mmc9>!WBr|rO6%Y
+zaL;n@Brdy4$2Ikvo*jjj9ez4ND2ClJbi?5=q3C%^&$HznSILf|v`H1Y%pdYrlDRP}
+z#6hURH#MvxZiVRN^OcQxxIcIE=ncG_HZ)gfS-|JGAihS{+d}B!rKjYd)>nw4JR(vy
+z?mpO9G)__P9Bhp5h~K)Iba5YF`-F=%UDZVWdB0nhP)w3l*h*riRhY8Qh&tLp(!o6D
+z9H6+o9eiZF;-lJ7bh`OITZrz}@6>GWP~!1N#8{p^KY}NNTu)}%a=ZXwT?z6N^ojW-
+zN%x7HtyuKaPQE!kaum3CxHog_A8rtcE7R3|=?G<F1{~s5hkK&ij^4dIoGz~^x>LPR
+zCT4Q4JA(b6>-#p7@+wqbdFsY5)Z|ZH;v>BZP)jWuM<j4OfrF^fCAyG1gr(BI7^$Zb
+z!}X?AU*UMldQ4~0WrK=}TjQdFE&i)wDszWfviTZ&pU(69Zle)-ld13^T0ir3g3>_K
+z9LZ2qUhI%afjC_J=}f0mUV^7WFA<YdZL%$)gy$5Fu3u`kRs{0pCok?RVmb)Vuz&Q-
+z^wq7jg?^AwsIQm>9rOjo7<4M#af=Um@`i5XSRwo!4DB=@Ur*LlYg{ecRfExl;&WWj
+z_0}9-1O=82;8vrio077TmgiJ=o{OfNk;m=$lqzS8!Dc)1_1=e2y+w^6x+POr(awH-
+zd<$+R3j%aMi)^>6bw6e0AWOoVEh$aexc!he%a_BBJX<sK6|Lt;j>b6(FLTf2dKvxa
+z6k3U0<CRg~p-Tp0YR3zRw398?#}ly{W1bguF%cLS65nbuR-E}3b1e3wE0Q1G^rvfP
+zuJ(^KVcikL|41><A3==Q2;4aDC9qOm?Y9r{o%r^lU(mWy-45r=D|MxxtJ5b@THmNY
+z$vKO=e7Ae}QJW_3W%6tc1l<*3CBw)q2GO-sARavWD%UFLB~vJp4K1lOf;rAP{Ev@g
+zhIoRHo$GpZj{;v_8g+3)K)a!woY3W#bi6~wuS-RIkw+JJV!Hmv7uodzgMQKVEa<t^
+zXKyp$6+Xx9K8G9d;Nyn-@cX{(qi^!*u6qpnUW5L(LEryBZ~7d&yK|as#!TBIkL*a#
+z!eTdj4rMqU32o1(V!F8Kpm&Jw7`q2_Cw~v<&e#Jw9eY4$(B6mXT$=Y_c1cE;0kk1=
+zFOqtcA}A8ODk7D_tRFQ}cfD!!(aO$Llscvxl^RQ7aI9y)+Dy8K(nDo?di)AM&M=X3
+zj~5fwCeyuQw~NLm(<k^lMbiU~Y%-gb_wUKuP_yAD@oFN|+=;rk&!k!U_`6HfB0_Rg
+zeGyrrLYdK5HhWfyejVxlXn!fLkO98%;%+h9P7m~L;4Q6B@$Kg1ss0|)oE+qv#L2-%
+zF4ZU7-ikU0TT$ow8(`-d`(h8_0&Go1$LY!|L%9GA|6pfN4fi*~9+55l`8{qtvnOYs
+zHcU3V9?2zpQR9sA9i`nkn)bG3=TqL8*tUxC!&swgRF`pvX(|Rz@8~i=D?LM4$+PT*
+ze52ZmwV<P0PWYK@8{MbqpiYGha_J&vGO0Mr_ud&jIU3K7-Fv&1=C`m9(VL}yLf7Y<
+z7=U`ggb|L~&X30@KGYyfXW9W6<Nyi{K3r!8NcBQBL9|`-7b}tY#^(#kRp(K1rlO|{
+zd7lq~d{7`I?O93e_4z=OI(6{w#6pHVXok*<|Bq_Wp4lKFkQBbY5($VTK9G0@r1;_`
+zYXm}R(`=9sN#*t@kYAcW{{EG={EG#6M$RN3-*Seh15SSHT=5gXc)|y527QN+@Na_s
+zp}R_370Q`6%Eqo3S9$F?4dmSdrO{^5tDIh~NTcb~oQT4q5iJV*GqDJcNwhC_ljwj<
+zvf37xpd#1nT01w&nKt1D2|?5fpR9x^gqH$svlJ+Typy_bPboAm+Yb73v6%{fv=Xg?
+zpjRNm9zTIrV5PX@MmZ}G3BMsrKyESlkU&kS#vuP`^1UYs_*^ML0uiVh!s<(k(W|}?
+zousA+7-|aJdkI?Se6ax)CR=U6?+OdQDa8k|fP{j8Qy<qm&?;keDXP!X?yX4770`92
+zf<&AIoqD$wiMu?$a*&94*O>(p!A_QeL}<}i0rF!n6i5LQ2npAz0Ey@z+YlR5rRro`
+zpcM&xUoq$`cUzJ0{WulmMSfwo6^VM!nH9}KB9=%mNc0Ki6C}`escHx-{Ct#(f_%f*
+z8fZlV5l8Y?wjzN>q{1K(gydt8h)30oUP1y>*%!2;lw2yU=bbR9ohnU1+s=c;;6f7-
+z$Uk^ovp}LPi7Vb6Gvdvk>8Tb1;{u|NyBFvOgvWKJKo4SqAjAT;mLbS)CW7o1Vfknh
+zm`7}Ipg%iKu`Rt#fIrGP=!9}xkHn-#3yTSY(1B7MdXnFY6vQX^pa8NkzqO}tCFrk5
+z#o1xAQf#8scF+Em@%E$KW?|B{Aq5d+8%Rjgj8;v(ZKJBZ$SDJfo%m?%d_8Wg!o&(@
+zQV0^|Na2I4;_8jui$x*N_qI_s55=y{@|F}wxFr%}^8}p){sa?-H`Otbfb;|%^Bfs1
+zFdYP(mAGB+*@`?2bpdBsTwQIRH0MjNyh+%6Y78|Qm|iYMt(P+mP{~+Ud7~XU1qr{W
+zmVtz*gw8`h#e~<+S($ZxN`BwCT7m&1Xd+M8Jjpy^^QocPu4b2@MoyA5#V1Jqk{llt
+zRUpd+(jU!0YNgKza&-)&mgE12QtUxVeHvt$Cu=51s9~jLtw=Tcj37;=WpS>JS6T|C
+zC7!HlAfbkpmU>Dr^%+5$N=xIEW=nx{y@FFA85<iWh&`~(lv3>-ylm16Xuc<~6y$<<
+zZr|maf?%*FShj%$`-XOMmdMadw{ly7LT7@peT|s$if3UtNc^0GMm)O3Ya54xZ+QjF
+zKz^2{nR(?Y<ivIw(oumFcI_fYkS#HcNDc1nNd)Oz$8na-x>r5xN<sPsH|~$GR&k0J
+z6_GP7B|+-<xw(f;jjzB|m^!yTOr3h4khygA&Ic8|M93B&dQHf8Jg5ZZaCw+a1xtiP
+z^%KP5`(pBAbT@>LRGO)tUfqhMZ~iQp-zd(e<sHn&t9%53>?^MUh`fc8{6#E`q+kD8
+zs6T2*GWlIYKKz=^YK^PeEY0Kpe@^U#MQq8T##YEbql0D@7|GQFQxk&JUpv*VApuC<
+z=y8^Tgv}z;wp(D>zE|oXuy47hHcJ$~<3(c$NFy5Q>7ZTk4iu1X#LK!Hgx)0Qpws?P
+zD_V4_cuIkA7yQJfQ7=@8F*F8hlW6hSCPAftEXA=r^AQOEzs2KL+0TeMcn_7D0>(V%
+z^^=m9#QmRo%`hdtpG<*|zY$-PEZbdMqz7#GJ1@vL1qwLJvOuFp&;a+=fkwCxBaueY
+zFHlL1q7v|?M&VQVQ={-Idag!o)A_}6KA<PT;t;h%6L2$u{#t^8ilH8U=bnK|yyNxv
+z8Hf$&V`1<xc2-Yd!@ClYKOiuj5=f}`8x#XxzBi<m7YKQl2bEw9yxWIB?huH4MUVTC
+zdd_1k*Us|)pC$F5>G`1wq|wT|{Z@u|NCTm85WJ$%1g%WG30j%Z1g%V{Z=k05CqI0^
+zHrJ^JiEgc{j1)S#>&yme)Q5b7)<(xCMvz7oi7`PH2~AK%LK9Sx&;(T^R9DFVpC%ox
+zo17C~u7atn*HO!S37U#$DFHV`ldI^xO1t2>BJ(0SC%T4;=ZU{0wRvc4r#C9%RvHbW
+zrqQcP(qU<bu#nwr=uy9Qydt?6of3?1f3{d?FzaGTae^{X)AJ{FklFN*zZJ<r7{{HN
+zAXmk5A{q7J?IZxnpZV}Ef|0z<ho2`H9m!Zbuobqk%cRt0a;7?8E@X=jT_fbredrfL
+zLTv(Pp?YDj)Qky2F7+Xhs5Os+piyPMtOJeu2Aq*`bq_dW<0_tD3`GkaBUU7uZf%~!
+zeZvtIMOA2Ow%woLvyP{W_PL%fN>J(~nb;5GRFrN{uZ$$Q6$G=un!tv5mda!if;Qo{
+zK!~7C7(<Ns?K7;^4w6Kd=ZHYa$K|=L1GudRxUCELk?JGe(^f|?cRE`e!QAO=Wdw7l
+zvvu)Dy!qJgH?ao%|7~$BaceltJCDlT)kDq63Etst1;-QKBwPye$s-o_ZPFCfqGZ6y
+zi>n}b?iK0ehYjQhB%z!xdqF~)aN0^2$^r>fCrw`QT5YC8{nzG6JXJj<>b807vgshP
+zawbFRhZb=)k1tt~pd`Iemb4@kB(fgT!IMJ!NoOXN1jTe;2qX%U^?adbyBYGqP7MSS
+zB@<lVz9n92^Sm_$%NJbV(H(WHT?TrW2~!>y@;M*+n~)#+5XjFwDDL*`Zp#8{)!!fT
+z)=)4)qqZFywN25eZH-24uZ3k;u8=cv-H~7!A-Qk(gE+{6vO;I^Pp`JczbFM>@e6{)
+z5<kHZj_a0Fyw!i4*K8J2pJ3T$b9JG|)Ou#w==AAOlG!URieS~xM0K(u*XE<3{31ce
+zcu2%NDOaI7=+TV+H63>aEQN8!l(>UH;%VM>Z8=E93a#K=s5sdRymF8TVrE0=JnOT8
+zL|`);V(DF<4J0C*+3ePbt*AXYi5G0J4b>OeuD`%X5~^F?mZ?!&Wa21+nP-SgNih#F
+zNW!hOasi2ZJi>`2?(@)~1=6TG%e2iD0k)k2+f}EZil_sYkwqY38NDU~9eusVDglY6
+zCoZ)7PM-@TTAsMj@c;I?K%(J^%eE5^?c~Mi43Iej1)WIuRwQ72JEzX+K)<K-+;pO-
+zRoqCR5*|0Ivc=>^0+sQ&QKiES$rp=}u<J0-Cc(N!iX@J(^CcJDi7p>)9*TiPS2qdR
+z9!fA9{z)|Yx4+`9AQ75iA=7E%v2T)T)NbK#MSQy4JxRExv6&LB3T&Rl{=+S?uMVfq
+zW=f<EJpT|u<YXSUk%asNF+Ed)tHBGh1gkikDUk`_sTM(E0+NuQz=T263i?r`%%;*R
+zxZP_v(rp6Z)q~$l8qdXT{$zaHZAMAs+4Ds*@Yl;3&#PBRx>3%y7(5p~SDvrpB`G|=
+zwfXS~^)=zg`%ZYuY4d-D`-yUg19yLLtH<WY_3`iI`sI5$hj5)CZpZzHWaW>Na(W*k
+zdSP7BHh-?*xW?{r1o`%5rG0&8U)bS_4)wA1<NGt%y8tU_ESGKmuf@Loa_%XMn_hCZ
+zS6g;@ObZxzFi~M0V9$bf`O{?3IY-XCWe6XO<&4o4W3kTl{~xKG&#5VlO{p?i=zVtR
+z#|o0R`7yY>FZp}qj8Vnr=dFqY4u2iPb-z#VO#fZ(DfH*&G}PDS)YQ&d*f6&`hdw)B
+zIbzu0g*CMe%LmV|ZOEBj6QK?F4$D%1iEu2enVmC#&YXB5!y!LLQcNPJwmMQne@=FG
+zLgt*Rx+PVPW9<JwhwDfm6{gJ!hi23M1CBHMl1O#^#Z^mmYTlgM$ig9-Zm6xH52<UK
+zHwYA1Z#XCk#)*Sm6uD$cb-iW=Nhk@JTRo3p>grU}n#Dv?Z&x2^j|i<cFw`YkHhlrP
+zPN!;W=}dhvQnRR<C=$nCO0KJ#ThmZKc+SF_>RJ{-jl|+a^4Qr8H47tyYidvTYf4O{
+zv%0RXmYJx|Ud^;AWSC~rRU?{Iv0sUzi$9H4a;<c6`pE+^=p)$A4RsB63}pu!#s)jy
+z68igjIl=b3a<|^~m)pjT8RrC2+_dbJKw7XvcJPAD!M+v23&zq<9(unQ7}34>yz2%}
+zNC^aw35;-qXNNWrK5zr2&%2zdbC^1Zsj(y_7#hI;>-gX4{BKP#QV|?Zs(-h7UhpO7
+zoM7irCgE;cMcSWP=uN9DsB9A(_g&-V!Kk|-xHK@>9Wy~OWv2wwf=#R0lr?U}gp^?L
+zP-8_(U>K!;aK;8Jv(F#X%8bD-**PTaI>q_9^X0h5%f?LC64HX<TfPdOQ*nBjN?*c;
+zcACe6>P60RyMpIe1drYoJm6fu{)y4c*8cQ?D2aN%@ik)ox%=f4!48|rxMRq3KRG9O
+z>@6a9UfSQ4{7@t<*!~tOaM@~>eaP9RXs*<i?yg{m(3hcZgUQwN&Leyq8Se(4azmNZ
+zr{|Cj*Q@j%H+y>B#NEM;W68csV!OXFLToR%8_J01>PD9PtvheR3&D)nCQLlFVOdH_
+z@at9c2)!-kHKPByB3sd8Q&NMktx)arP|9l)#*G;nDh+lDbtQ?<u3*KFr$mlOZwiFw
+z1x9ucHU(%;rz;wFg?={pyb05%PcNR&)eZeLH0aQT;tAC$X~E}|36BOsUj{o|erG5*
+zkaz6d;PXx-c>C(WP?r>azAD5K@>7!3z=eO4(k}Scs{0B0V<2=3C7xTw`I`e3!H$<J
+zXI7+znnL-r&tDe&3&p{XRlAx(cajVCui~~?AIQFM!Yt*01%a$%r;>)7ly5$ELmYa6
+z4^sks3VybVq`Qi|E-=;yzf1s9WGTk$1NR4iyE-tM?cS$a<tjHYh&=3uZVB#i&Iyb>
+zy8Nee&RFy<<v+VJw2SO{H5e#%gC~X}!LJ$vece#+rqCUf`^YM8yypX(iGFAmNAB~1
+zc?+7RUv~P0^Mma}UAIJok=KF?s92X>q1I6EV7h9dUns|HcHg67I~uuhA9FW^-Vgr6
+ztq66aK)IhH@Rqzel>4MI?^!n#3H0q2ydl8(53RnR{x9c$cdWkuydkqgUo8uctq7#j
+zT%fm+RUc_zu(&Ql8^1=J%Hnfr<JzjZl}jRZ4s94)Ra5I!s?BYAho}0QORFo1sgl3y
+zzT^_hzsRYrs;{hB!ebucswnMbTU9TEjuTl>Q(w7YaebtcH**E&oP~?)s~r-VM}?MD
+z(U!OMBHQN|p|XE2an;n-)7K};!j<8|DQdLld7zf;@U5O*MPip#&xtH%Ym`w_izXLV
+z78aBhI8)CZKcRB+xs%VFNCeF(yw7lDZPg+wQMIt4T4|tBQx&6HE>tM*G+VWdl{4;C
+zE?yF;SzOEL{OU+0ZBwR{Xkn_(<WDMGJ8y11pQ@KfoMrV@m3m`e<yB=yNx}FDMP*K8
+zainUYWUA7%!^^_Ov=6WP#|=_nGryKL52lu=W2Fmd``d-p4*Pk|;s(lByX{u$-FB(U
+zi|5T#4YYXP!m9a(sD@e*q#Ai%4cW8Us2bJ9cOvb=tV=TQqN*iBYG_wxQl$4ub}CtP
+zJ?TP|ky*yh!b%RcY$c1SoYPQOIcM?0hD8)cm1<@q2cy}l8X^n4h*(@ZuV%iux87+W
+z-FYLZDsvY%&^FN2TI%<Vm5Ue7<vP~0y>hOrUPkk1y~EO+oCS*)Rp-=4s^(mjbMEAV
+zlALAZONw&hX5Ac`G07lqB{ex;y115fkZG4z*DZE<O+XFd8ypkxRNW;czH%WgE_CED
+zXZ><j@kLd27gg8kP@7UXi6&~p@AWz&Nr2wPxKbjuzDjk%NFARzi`u4s8L6ROiAa;)
+zpyDD{C~ulQw<=PlDzdmiH{`{2H4%zv>crCuCYBdfmJ}3Ep{`1?E)A-z=Pt<#jE%Rc
+zx2vA6{LS_#(KYi_Sv3&Q&fI35q{BF5Ed>P)AN5tssw-7TtfaUg-|$|3YQ5w{F0EWd
+zYfN6R(dN+HeO2#WNQ)*3t07M1qQ!HmEh5zL)cQ4ZBIG67^0|(ns=7!eFQwSzITSC-
+zSF{;4H{86cMKudAp(v%LVRgM~LN#3RqK9li^j7M@i3HRvQNxm|*Wx8q(MlzowURh?
+zz3NC52W$lO`Kr20D%FrsFJ|$ep=zw1&GD}KGkdMFaxT}<453BUi!f%go4C@ffylFp
+zCl)!vZ*ZA<l?%AjapR~Fq;UNB5*q5*HL4C&rA2dxSI((gNZytjI5hHzV=8rIs(!21
+zt7<vOoORWU7DsqUnX`<g&!g}?dvbZ^_`JN#;n~Bob2EqJ=8ec5kvl4L@S;dVZS}bM
+z)wQ(Y_#8@B)y-KjjxHVsj~JFYcz)*KbBAOOo~JtB;3ah=l*i%0)XFrXX`fX^C?d(y
+z#TVC_^Fehz+oi`9U8N<}a~PrS=|!6w0;R9VTo90gswLEd++$S_Qe!i<8AVFvvIuV@
+zkFkO~GWT7YxX3Xz3)PhcYRzNL&>_?&Y^ClibBD9Pd3LLwi(y*XL4wGOq>b3wn8;$a
+z-ma{TET)clY31Ddh>lc>$4kif%cZHDB^Ot!VQ&G=m)uqux>;w<Z0Z_R3ANDY0I5=Q
+z4Yd)|3muM)MN6DYHLIwxe#9`+Kd)-x!r4?Sl`pfQ>V)hPBZxc|G&xh2%&1fc-g2I&
+z;kkM?o=csOQ$zJ>m_7~ngNehop|+vET5-<ii?7O|L!3F>amhv=oK=X9pLlLjMbUUF
+zU#l+C)C{L5WuA%)&z@2+$-^pXr9pnG<aK}={ztMJ>K$CQh9wwLxT{JhuCHE7f@QFs
+zS~jJKq><q?cngDG0U#z8E}l<8UZn;+{-l6>X@IMx#yAQ~ndm9NWdtucPZLv%N@d2T
+zV58>Y<pr6hJH8t0mQ>ZNfm3xOH5Dn_X&zMBwB3KhLN(&)RRu;(=j`$0M`sQwpG|Xl
+zgYIvGM>MEZUSr;f?A&45!v<RYP+zxom+Lq8(kYI+yo-B$r*@$YbZIz|@LrOqeqVZK
+zdY5YhXQubKCU|CgW=qPM=>x7#ElAJ3BCQ~OWK+Ad(;o~5`vf|qk0h)heE{(gFO@kn
+zJ*3`#3zMvcB5yIDDX)d)T^%e;&%7dq$~2`;O3z);A$>qWdS(F%7k0cb7NDYhhxk#J
+zL5JE)@JP08x!est7))qfQIdNkTDrQ)K^M*cIfS%%4)Qg0f+NUR`3a67Uw$Vzf_!mr
+z9lRMEeU;Bc@f%+Tf_$xS9lR3+^W&!j%E!V(H@z)xouv0<li+fr%E}EoiJcY1JCkwz
+z*itSwBk07vxTP3^vhRB=H`kYbU7p|w>fOrYa)Nqu>I69bINdt(R61FG)wbg?B}Pyx
+zk@e$~;2f)o`1wI`BAjnbCBh>~@D+r2rFLH<A&0#+uS&vyQxg2vB=~QW;14IkpHG6n
+zoCJR@3I1jh{F5a3-X!>UN$@o4T8aG38%!j^k4}PTCBgX@or&b+CBa80!N(`TrzF8I
+zOoG=Y!5fm`YHrupquFzKt>s^=cnhU$T0PfCXo<EYJI~3UIQ}%6H;sj-eYxYUD>V->
+z+p8$Kbcwx^Feg+s^{H!hLStrMwHQsZCREoaYH_Y6?zokad<;ewU?iEYWA(a^R{_R~
+zjIzx2J|%fIpzlI>Gdivj*ckKTo|48L0Lhf=F<FxNEWCD5#}<9!JF#k1qt9lkV-~d=
+zAB^*;27I-F^L9YMcMHxVxV*?il;f<GJGgw}&49p<{i7J?xdnKC8D|*h^#Sm?25!oE
+z+rUpW_%mcGWH~1p_y7aXH1Glg?`_~q4ZM$mUu)ne8~E!6ZrY<ipF?~15HJ6Yq(447
+z%hb$vX3-z&JKDhe8hDj~_cQQ11MhF(jY)9+LIoeJ*W|w;34Wq137CHX{lU(W20qZh
+zs|?(<Gh*N-|E&gov>``*W|7jY_Y?#F(BMDS!1o#WAOjCdP_plNRgz18d}IjD@(0r&
+z>eb7@vkkn=z;g_|%8<`Gis+Az1qQz<|1twN<v(rUY$NQ!9`mq&gOX0WZOYQiw!fo+
+zoAP@l!ABZ6uUVjXfq@S(@P4wiW4&g79An_-_;7=P4>jbh<O<PY%emgbO*y|Y@L^OA
+zc7AN&!wvjv12_FJPL`Ui*X*ai6P%0j-z@s$<7<PzAElx92Lm_b!R@4qdHr3dXwDYg
+zZm;7Ees&elvwZYR!av61*W9!fQWE~@25$OcnSq=2T4ms7y{-}*{^7Bkj~fhrGtO@{
+z__<#9NWJb)!vBQD-$nR$CE<VF;@_pLp>6k)@PB3CW_{hxx*)fUS>K}s=lZh!3pAT^
+zg28XrH_O0HKW7`bIp2vmT4C!xfc;FQ+j%%P#=x2n{J?SLVdI&i066we8erkrWkZHf
+z6}Mut;uN<jyelF6%$|><^vS~?7o5j%KG<)}|0+9{4(`i*z#g5VUHXM!e#m49<22;l
+zDRRad{49S43#6l1pFF(}$@*Zjh4&P^+QJ_a`<GhyPSLx@!r3l9uGA+_?_DD28VesH
+z>w}+JIMz3tEc{NX*X<VGOYFJF!e0^oKUg^4Y1v}o?}|M;EgW(6hJ~Ld^V2^qe5~Lf
+zTX>74zqW9mOZW(gy=dQmNxHp--ze#x7QRl_D}62eH1Q8#5Agx{xF0pn!ujnJK8h{;
+z&l+~hE&OyI4CufPCXoNS#ML5;zew!7#KJ2@&N>S}Pwd%f;Zvo(Zn5y&Wx%-4!uf+p
+zd|<B~*!ij0^Q^_+TeCZeBk+GKeE+oguMvAbvG6~L{U`@Ha|BP5Gw}DMzjU*3j8mBw
+zzFzbWw(zGVJ=(%Mi+|3xaQrN*%)*Zs{wfRaBY3Ta4-|Zbh2J1{Vowy*cdYQ=VDVon
+z?ea?t$7US&TKJ>VzJIjvV?^&(3+FG9sYBuv_S`J?bhL2H3&&Wv{w^PVFU!LDz5ySD
+zEPS8TYpjLu61`_y_zJ<p7Jh>Cm&q1>fuzeU9P8BcEgTy+Txj8VXLFu~&k%bSTlg2c
+zy3WNGo-6#9TX>z|*I4+!#XrBW@ODz)M=YH07xA&p!dD9aix$3A(r;RLPtm*2!mkiJ
+z0}?NYlRrs1-NN4xImcOek)-=sIPN1)v+#Ce$7~C)lXR_xPnY<=!onK_zs|x-q+a)0
+zc$(mUwD8xpo1Lu|j{5w=!XFa;HVfY@>3tU7BK?zIbx{ZWjP*gfg;$IG<18HQ*U!S=
+z7e5TK@Bxy>4@jZ+R>7xP{FjN|*%p4P)Mv4U50m&@W8r<JzReb1E93u77XBZJhdV92
+zQ1IVd_>*Gi(-uBQ?D>m@<37tf7T#0*hItbHfj!?@{II8;)C2s`d%T6;E`A$e;m?TN
+z;TC>_q|dZ)$iLXae<$_5&cZtgj{7aJ6ZLw);>XSgn=KrE-f7_{iTqbB92;1?YvHgz
+zP5cdeK9Kh9YT-KsKgq(;uLoK97U|ccEPR64d6tF$QsiTw2iSAJ#O;L^|8C)5WZ|z$
+z`(A3{-%I*R3%^U^7Vn}%?+1e4ZSlV>=|?PlhQtqk@(DTf#GV%{{#T?u{%zs-KF(eX
+zhx~&UUM2F|i@%{4@{hLg%Y+}lApk$*WBvpV`_HoE6iIrTg`XqsGTXvCh<`8-L;e-w
+z=T#Q}8xkj1S@>Q_V`nDFIa%c2Y4QI-@CPltM$%7M_%^ZUc?*Ys{$}Cu&%Z1j{{PIv
+z-xB{Hv~Y|I?PVQ-deK8tb#%Az45=5^S>Vr>{xZVihkptz9R4}a!mp9|oNeK_{#<0?
+z_-<U(!gq-r{GJtdUL*G3YVltuetE&d!&0w*SolkVe{A8>jLtp_$9NK8L+F4#SZ}0T
+zIL5K#EWDSrV?PU@D)ky-;kfU7x`pF9@Cpk*P1=2f;M^Ugs><#M4gPe6=zo7SaK1l-
+z`aW&o%>Rm%*>2#>4}ZRB;LJZn`r}^=ocXbSd)vU7|2pBv{b9~#99vfJxA-rY${jFp
+zmOoI&yLQI?VV3i#@OLtB=5G?c#~3*CA1D4i-oTk3?bz4AnLkt7_Y?zXe$2DO44nC~
+zo*rf3%wH?^k2i4UzeMDR4V?KWNxYtC;eABT5(8&B4~m=y17|si=hX(z{M)5Jt~GGx
+zUm$+F#=w~$^Yo2^GaI}9Hu~eE)!@fHQpSH{;4J40vHuYZ$NaR#!bizC@MpoH_W>48
+z$14Uu>&5-bcMY8NV!rv<!hb39_geU01>Y|?^loRRbl^w8z{5<?G0M0f&U&+?9nZAz
+z8G_?^0p#Gfj7x;y#+Ms%xV{(CA0Jm5IP1kYyTQV-GaY{82KnfZn=Ssg#Lj0dTn(6{
+z=Xndqr|4c29P;rS%YPXBZ2ztF$H%7z&i2og{{M|72fxYeDmTY5o?IsU$6NTFg5$XW
+z_+Jnl&jny7w&N|f<a{aoQ!M;wiH{kALk{jYt*~(XcC^Wm!+zM!PN3sD17|<X7Wtbj
+zIry#VBNl(N@Ncp3-wOUG3;&zoFIn<2etu)&cuy^djiUqg#r=eH1c#sTd~T|RFO_zk
+zVc{PLUTxtQh#d`rLvID<M~i=>@c-PxKNkE~7T#IXcgq>_u|4fB3qMu#zHP|i@pHN0
+zA6q!a;e8f<gYX}lq1@@MLw3nHImp5vXT#_iZQ<=?{4W$7_OB87a}9nrVY1j!W8iE*
+z?yJ-rII~_U{FhsJUrAqS;4FvVG38^UfwPENlD@&fng1TC?_Cz2BJ<S47LN7F76WJb
+zJ-IW{@vMQf{Bjw`UNUgz-z)sD8aVS`ChLm#Ec`6W<Krs}Kd52npn<deKgh$hpy=U#
+z!SbWhF5N5~A9g*#z*){GBBzgmvmEr(K?ctJ%Q%ycJOgJ4>$EWj&iwZae~E!JG*{Z?
+zd;@3x<K>mjN&{zptfOiSocUi9{#pZPeymFyEgb#j8VgUCc(}#FQ^d~SSUBzjJZj)<
+z&$nXF4hvr;52)TWaJKWe(!bs}aF%nlJZSycz?mQSCB8Cn=6^!?4+xHaiai2SrJXrW
+z6pQqu?gq|sTIJQ%6D)kY;QcK8L%~lK9D1<_!6XZxF7>Uk<nX6s`KYt-Lcv#9_yWP#
+zS@Ktk{M#)4YlZ(li~l#m|2GTYBKTfQ&hJIew-!Hkne54pL<i=n*M)zeg?}&jP{HB1
+zpj_XLG5EQ?a;3c{7&y0=`fM7VOAOrPpKjpH|9lVnN5^anA0Q9#8w9uQS!M9E{3T*f
+zi-EKJts>_J3x8kmn=Sd+O9JBri)G)9q(45MFyye_TSf1m44m~I#V;$-@rs3?E%=+3
+zUhGZrjm5u8`0?sE+VLL2+e`lj{+!_Hg2QjP|DI#v)zZFWEj&}M3(75gnefjPob|FF
+zc8ebt894jlGqGoxg-@0jdRALFfAy4)b%Miw=)KOuFBf}SEgbh-?ziw?2>;_2jy)9L
+z6de9Mg<lS(V~>ST68vjR4t6s<O2${nSt9($S@?&7pKReBPtbY?2o67B@54D3j=c(3
+zTXJTIob?udncy2O{7%7dw&de}@$Cjbw>zGf|G~hy-JcUVPgr;=zXV6evlf1a;4fPE
+z9Kru);ZecgvG8XEe_wF;4STGdDDx6<>;`zc;ApRJMb2akU%@Z=(otc_!F}O~#s97F
+zH(LCUNdLOa!k-g-hb8BvOr_R&&B7}Lf5(#ZwaEF%;OF)#k@enw1LyX-M&!6Mf5H#H
+z6TE|k|4r}=!QoGAA((IBHL@<fz>?FxHz}uMu7&3bUTew0o;J%2ey-OBsn-<-&h@Gg
+zIoDeFuLZx!!l(6NYv_KDh2JOmuPyw5;J-C+)1F5Sob9>mWF_9&YT=W!H2x34T}pD5
+zum{fv20zQk_4PgjXZh)U=^q`3EPRyU?PZ>a{59Orbo8}w?A<e1aAsq@xc(hy;H<Y&
+z<ez2XO@g0m;lCD~zr)D~?72zoS!LnB7yJ$jKSi#ipE7U`wF_Aw9lH#i{rRBq|I5Ic
+zAMcBPV&Ke=`#x#1PGPak-$mqiF>vPpNaXi3aOU4de|!uvaOTI}Oj88sYO+6H7XQq)
+z@UH}4Xvx9eNfCpe+bdtLzt$Q!%g^mc|LAD3@N&U#u<%O+zg2Lw7xrMf$KYqZOGNLZ
+z2F`k0Mb1_W-!Ax{E&L<FUlkmBv8&q`7Jr}qTr0ZnvGB7656HR?e!fWXkl>JyZzN<{
+z_#jz_Pq%Qqe{!jXV`urFS@=&y&SndLOYqk${QXp2uWu~8PnyOD%Q_48j}?5hg;xuX
+zbtw3k3tndN?-9Jp!oL%|*225V_33&8=lIXnW;(YRILALegz&J1SBRWvEF9~cw+)=z
+zvPk5AXy7a#9|AdK;USqHd&+u~{lIo^5IKVkoaJN)f1!or{knM;jt}hIV&T6LIZs>o
+z8LXU+k1YHbf(K=ti1zwS#=~3-$2btSaD2LBu7%$t_eHO@@Xdn%-oRPqEM+BK2N^i~
+z=Ud!&wQxtq!`CdlyWn3KxKv4L_|Cvt{siIgF6&CPmzd-9H*n_1_;7}WUn+7YTKHvx
+zPq*-22wrdCY^OAnbA^Gk-u=S=QwvX(`?0rLcyGZs8#p)l0{Y|Q1p{aK1BCy53&)<6
+znX+zW8~IXlp^PV|TKFcxM_BkzWt<sp;d2Dfw{Y+mS@<Z@%}23?XUe>Au7!iY%);^h
+zNktNTriH&Kc2*_9Yb<=PjAM(E;B^*$t=PXT3EpVo+q4^;%Po8{HzpnHEgbwU7LNBx
+zHd^=}WIVai!ok1E!tp-ItrlLY&2jFsaPZ$};Wx_o{M#h>!xp|m<Zn)bZ?o`i5}!Mg
+z;4fM@=FL|u{8jPK>lP0Fw=Ep+le}x;AB#O7S~&O*TKMn8KLNS^Lw^L`-oif-J3A-A
+zkG61E;-_a4ytjp857E9!@WB>7OWG?h2|m)ov3?kv1TVC3yzd)Mf}d;QVe#kGB>4Fj
+z{<`$*SxNAD7JjbC|49;jsfB+p@z9V2UuEILWgfpQ2_CiZu{^=i(UJuJnT7Wg{+}no
+zZ?o{bWE{IQ3I2eEXNdj3OM*WtlQ*Au3LGfwfo*aIK2p;Ajdd*Njif(5s$^mXf0^75
+zy(9^~F$sQe61-P$tq1b=NWYbEQTKXf3RjGLEyD-9SGt@^<9AUuo~d#*ugSl}!f_q_
+zgoWcdrjuQN$s*dUiO!KaeO>^nu6kirc7*rR%T`<UWY4AzqZE+cP`j|^qH5atD_b$u
+zE!GVB%%bwLM^c`Gb&_^GkmQ{D2<Nfzxz)29=F=8L^A?i|MOV$9O*_lQWYaE8G3hGW
+ze_%dsHYO#IG6d3&y4A=gTO8VWVbLPmt<K4=rR}k@X`e0H9*ehb(pFS2sGL{Fo3#Bu
+zI5J5Fw-wqMBJ+j7`UyDN9cd0H?(+En<h*>DCf3OK!F;SohI6&20dw>dT)G`Y>Zp_T
+z9MU+m4D%R736}Z4md~TIiR%Aj^%qHbGo}f0mW%zloG=d5A5cCKiTt;JmFCzWjO;&d
+zBb1lRcxMt}Z2u7YGmm>jf1Bknlm|S63MDF!=k^zxLWP$hl)p%58ICwh9sA`uIP?KW
+z8fUI1WPwMWCD0y|aTR$s?{dmW<iGWey2S3``po|0Ar^Y!zbIk0OfK<Q4*z!?{EkPb
+z;(0ewMxydp4%H>@?2nTAZ1dhoa3cFF9@6|<^hsS;@qHrO{`(2DWpa^07w~`o{(?@$
+z^WIGviS+mQqb`B?W&d%L*!mwQERp^hqW@N_W7@ngCMo}eEVQui1+l5aF8?P&6WJdY
+z`_ay9KR=SP?SF$XmWg^2sgC1hbX_a+J8<a7`F+YrRQ{G)T|&YS#XVo4{AW_$V-Vsm
+zQr^Z<4tS6N#_aLubtxaR3ZVWde~^eo{<~287ZyhLANvyJ;a7gVZZ)wgagUVmZ0Wa>
+z32kQq?<`hgoGz*Q%(p%G7PPIOn<tU}FCw}e-jC6#_*m6j_GB;4$<#-#ocW|_{eQ%;
+zVJc_D(A<$4xv<0PqKRh(T)#%HbGp~Q(8uQmpZlqNMds7qIz63&X$9rQ(XR{2=>Nf~
+z;pP*=EekUaWjr-Bf6c)@k<$FN`--ElHuT+-n{m<_E;e!0*ULI)JRB@;+Tj+gKkHDq
+z=^2-~*Y1mSo*4b`BjyRO+Y<R(!HzViI6Bk0U}nLLf|&)go|%_%QX$=|dw9GXZkg(i
+z?bC4lo+0x#u)KB!>(f|XxM`c4@o->lpGeQOTOvn~?a=V9mQwCZ8QX`UjO({#JiI0B
+zZYz$KJA3}MVP1B|No!fPQ$97^^huBA$^lK^r)FHqkrjPC96fL->sij7x1s5~E*a|{
+zA%BIN)56WuLV0iQJX^iD6po&q8;+hgGTgMiNA&dzW{SPdX?br(&mQEVP2U~LSo;!*
+zy6n3H^grX;D_GW?ZQ+(lx#6b$p^T<J1l*G%O2`vOXFPoRJ%Rl7t8yb9G9HPf9h?`9
+zxCeI>rsg`)a$m6cx8=-(P5ZlKTzL*jY5Fb{ZaF(QqiHp1+P95lo=fPuS0cw|Je<C7
+zTVVaUxsguMmq}<k3k@A4d3kSorYe6&-^knY6cu-#<_LY9_jS^3gldZ3aP*sSG?Eq4
+znaxB+x3%>kZsa$ohok4_Mqds$uT0+`j;;*trz(@T-rXM_xGOwxhr7G!o&D^9%a>6p
+zqVo<FME5uC3{7tCls0PT<Y*_i?z6V@l|+hzaP#Tm=&D?jmd4UtlD3MZeMr*24G(-V
+z>~0NjZ42%V-`V!c!9$1q_Vw$Mw?)~is?;`vn37}_B+u$cS<UIHTFsI4AIOD2v^~n$
+z>10}SB#jXFhqh8eD0p>z6`WTvtvGt9puC{0IQrM}!sxS8x4z${Ao^lq^qKZwQ|yJJ
+zpJ^Yi+mf-ih}-MU;^_8_b<c4djHEPj!_j9l)_zLp=HB#gV)TP>bf?NIXfDhe5WOg?
+zF#2V9XHzZ};bUU-vvBmE(eVQm4+&rQcR~xB=VXPWuNSmjpY`|e$?e~@zxdqdiw0eG
+z;Csr<xT2B%7d&}@oc<(7>t;s7E%mwKmK8%D<L&7Rnm*~L1QxEJlN-Hg5XmZBe^K6!
+z!c%jdo#V4O&?%lm=)?t;&qzE(|1mKtk;Jz2Ar;X#{1#9$^S12S7X7&C*+4<`(>?2T
+z|3@_PT%nj)eBKsAf###Sij1}uBs*_Q^y4_`ZB>XSKR&p9xN&G4i0%zv_Q^<6G&kIw
+z(suw?CAv0i00DVhn!a^2u3^_^Jp2>4IQq9yZ5dbhrexCr!g~-gs;xNsZBg{uNbhh<
+z_frP8QH-K<tlL6OH?etQRw!d_FJdjqc({LI^rOO-hJ#z*=~B>sdqL9=#}!8Bay~CD
+zxid|SzBH+2en8ilBV!O1e2V^bOoXF_ru1jSTKYr85RSeWj^4zksyLw_2}en_mc(q$
+z1zFLetmc9NP5V=$MFTRfoJ}?K#=C;1gTahz?jl7+&GQ3f#zZb%knwzB^aEHUbs10P
+zS|)v0+;U!8QS_ZKxA04fWzQJjzkVY~|J!q{8fU`I_pyy=ws3S$c-@-~ZFyV5&DSfR
+z&kYalt{Nd@-DFY}zHB=;O<cRj%YQ`4FIu;6M`2c`ld<+gQqxj&U}8%oD|1rI%637W
+zpYd>~tZ>W9tS$wQQe~aTc(~h4tj<$R<!vc$+V1KKQ^78qzo)E;(QgzoY19u5PZzEG
+zwBe-YvaHag=ois8ZAOYJsd(B3Q>;<Pr0o9`L_hNLqgyi`*`2p#Yg-r1mr8s(m#Rm4
+zHTpS?A=DIIGS>2sm*Ohv`<EQo_Mm1?$ym!P^El=`Z;~X+d>~=wQ#x})!pz%>=lp{P
+z+T6!@NfwU2L8FecZ%5$?xs?8>FxoJv?HpF$au&}+%VyFb6lXx&c~r-6^v^oObkgaR
+zQ5gM~pP{7Fpwjj=4MGLYX9qHNMT=;Z`KawZ0@#$|Ij<>eU<#YS`P(U9wQ<{QvZt7e
+z7B`>QVP}y{)<rZ~mycw|n~71W(Q&wrEZg7EeNTTGN1E5DxTJ}=TXQ%o`cmFE^VS_|
+z_=wtT)XNR;?tNx2jcAVH|K_VS|DPI`hnw5+Qf6Uz-M&bF%!8x8h>Qt)LK{Bkv4u-y
+zbkzEzJB-}_grizq^akd6X5NNyvl@16+*`kdqsKl|qWx#Yk6%9?*S?OvM&2)sZsqBw
+zD7s5KSq)2(&f(~`ynW&5=NfF<9wP74Y6kOHc-^5$=2Wx3t!$Zyc$4~X!zUN)<;9Ob
+z-|5NjK>1W!3g*2+gX(e>Jv6LkJe)@B#jFcygzY6G?53;*l$-aa_-ky3$RJwG4H%ml
+zDI429QquIDo3XYXaWs7w$XI&|MJcUkrsTasi@nz~PRgea6K>WbXu!}iGuC}eF-8Lh
+zt2G7;?eCV!t{M<C9zKhR7x!Ev?M}U%R!=LlG9Sw)C7bEb`6%OSjyW1PCc;0;X&Gyq
+zXp9K+IITtus#RMdMKasN?4idFLIgYZPhTB66f=_-M|Whb<(KJYg#HI+^5&@n3Y%AC
+z6-67fn!Zadh)$!?`DSX?Ls@@idszP1aT)8bVC^l_$ow*PDc9q*&D{EJPf_UW`V_ZJ
+zqlo`Z{d7__7EdCrRIp&@S*lAEH8*Azv|OoH0sGruTw2gPZBTJ^cR|yZKv8sSam%vY
+z;+94|=@+h_nANT@nvzw}^tsIb%_&)h84nX&w7xO7D0<eQqV<#W#_uRh%Vh;>9Z=ld
+zJ*#-<6&x*mgx9^&(7EjdGE?GyTe$gh&ZI8W@E_&OiP7IPkoO8ZbT4&N>S=khXrPwq
+z!Lwcu9eL5ui=#Vt=7(7F&U_wHoSpoS2BjT}1FH>HO|s9gDouFQRt3$3Jw`eX6+C)?
+z%BiK!IJFA8@(_8kuq8hb-A0~h`w#on=x@5GK<=Kqw7<1k8BdjET^Me5_7#@6p^SC;
+zT)pULM)YK?<;^Ub^9xbFZH@{Yhn$_enZt(orHUUncc3erl$Og59XxpOo0og<>br)H
+zNLzF(4Mz8_Swo&I+!}5<ClJmkd^x(+q3-=gFg);Mikm@gog^Ng%26_<dvg%*)n&M4
+zxtq6dGv7GhK_Ri@tX$orDQbowYUpY$Pg%l+CQ~7f9KL1NwpBHa?(ga{K^AF>ySRC5
+z77rSIq+d11j~B%|Q?f{oH=jOAwjOF5M%yFuct`zbQgm1r$H3>bL{&!mBb4X2Q>j^!
+zDt~~KYx}~7(XaJBK}ysPPzh?0vGzjoV<I_w9!_RJ#@YdgDW_Jb;kX5A+b2{dz<WMa
+zvXL}ho3Zv8W=v4AwqH?(V)g28tZ$n>sVJb<-VrbtxP@6^8ba6Y%UF9I1?HO5DgO3m
+zti6J0y1oxb{}!I}@}%gq#dF$}Sh{=|K&w@{QXWejh0%AgZuI&`%On~x>vJbYKUPCe
+zQQmv1Aa(MBjO(`-eDfCOMOuo6X~^!RrU8<av2GEGq}6?eF=Wr%&^&%n(|$MOigzdg
+zTS^X+>>-cwJ-u-B!?1)=cqc8hIG(homa?oakMXUsaP$Lz_#*={*4|7)GM*Zr$May*
+zr>+{j!*jmYE5Pv1tsIBcS;^><ye$)3CT3+Skrn5+O;XKSNYl`#?qw^~_?EGD4fmv`
+zXL4yI99p!NT-cwuR0$fK_LRwdLrY9r@xLg`%uF&&FEg2v<sMHOUBYwzih-i()0B+$
+zZ*U{i-4ajwp9m;!KDHp^;T`)5&vf%6x9bY<!uxZwOKD#B>FPhXwGyZJxp~DPs!oPp
+zn1@@+DZq9>P20sjA6?-Mf(*4R4oA1DN$@GQQ#|WgiDqpZt|X9On(Jv5M(abpLgr=A
+z#Y$VtlHS^*N<>>K_`OvhO-XP=!4up7ZST_X;>E9C+Qc(Gp~j$mzCT3G`OJ_Vg~5YP
+zTOElnY@RU4T-dYyaUO5WK~t$#^2c|5z5be95?=O61+{U^^<bC)=`p)Wa=4}75MAFF
+zN59JZbRsQn^3|nTTN7m|$rGb{n!AyKDJ_?)Vf>ZeyD^M!+xjtvak?EeH9#xDjKVka
+zogLw(H-i%g?g_hl!Y$+bhsRKO*Uv9*8Jj(^r7){Y-j+$xw#P`m6W+Ov9i}b|!z~x-
+zsd-ZK9a%h!PFnX~WJs7hL&0Nwhi_8!qsMwvAzC+MZfx3rC}Z6PB!MoxJ4n1tjD8Vr
+zekhA;NxgHJ>YWW;X)(o)FnXqHPMV+9jldsxkxA>k%oNL6JqRFYp@R~?#1>tgQ<e@Z
+z?wMDxzaE~E)n)CQk++O!YwohAi|$8szc1tA6Dj-2aK=;5a0ke2_;}6t9U>2``Tpd{
+zJzP_|YSuRt*KN7vMpgB=@tN))(K3&wr|yZyPx3=*m@nGG%~xl!?cM;@(1~2Y)ngYt
+zqYUI0px>1FJE+q~!{*nH&YWE}H`DtbO{RQ<CJA40$+8h1%VFdxz9n_l^J<pIvL}$+
+zP<v4=eT2xcq3>MN&f4mWN7IL{5;4WpCx&kteN~4(cvL($lZD0b(YElTGiihQ>Y8Qr
+zH8;QJ7uQ4<WY*NuM`3E_`bPWyiY+&7YQYi99!_t9@~C5s?aB0m*|)#%+|0%E#Bi$h
+z=*-;Zed$|qUVF#dkMgm0^qo5>Q-Ae|BqS1-R9^Aqvi~c86qghf7EU>`h-CFCE}1ss
+z$4EF_`I0F`XBAf*-iFZ<P|4)b=M9SvFF}Q)?Z>|LnG34wy)ajwN>hx!o|;<vltg57
+zruu48CVvJoa{x8*l7X505vol3z+AQmERJMOE}u9tChnJ1)zw!g=t;Ic!nde~#s~WR
+z;o`bXB9|<znnS&%dTB$|!b~1FbSbl+N;&#!8wU=3jbU-!B?<Bocz)oj3XxyyS*BlK
+zk%u0sh7|r{6@8&hc#q64Lr_dVNalx3b~=U&!;T1jF|%&8c6d#_@+&)~deM?dO#Or}
+zzJ5vM@^>_9Xee4#wQ%0zx<%$#1ZTj>{~w?I_Eh6@Y;^P;l0BrtaJ3quVp%fVcNjOw
+zq5p%N8GUnyE_V7Zoa^+h&*|IX^j(zGcWzGKOEUY0NB5mHy6;q{@8F?B>NCe>_U~KY
+zzk`!SuLaNyNC)2y)USr|**iKM?U7Ev4RIn6Xs1s4r|yA}PPu71Pdz6Mrlj)MI0O1?
+z7fL}|(=1}p<XR@BphlV*Ne!iie#SXkmda^2;c^rUy?&-&OhmV1eqOVMR?xqboc1YW
+z=-f4DFx7^ygy})6KFR)CDLNI>r!M-GsZaU(w1!{La9s62p#G<*{~_A5U?_?0#443-
+z?Q_RdTD{=%dWZjPp-Y`~F52PC^Z2CcZ>}XWr0M-kchU5>O!v_AcT8t$`g^7aX!-}H
+zb2WW{>5-Z~$aH=N{i8a%oCxcLs}dzT5m1Q=ok(%_lX(~FM4Ee$5({)9<g&F(bfS|=
+zM06tEt)`siI?>e~Mu{~#(akNU#N|5C-A$pTe3MS}aJy4ty-xIYmk`?qofzo0P~s+?
+zI7KCH)rnJ8;vStCq!JJ6M7Dc3m3dSra+GabbRy5?4YaoFtqD5ZpxU5EhfQ2b?W12Z
+zDfBH|U1@_~ac#R$Q}RacX(4Vv6+>*ciXle1DHVDO&~CcLJLV3i;;QjG4&_KwTqWS@
+ztg||uIGhk=Q%a|kB19{jI`w8oD#KFO(x1|oLHe$ug#N%lsPkzLQbO@}9_7bT=g~~3
+z5N|VOcV(V#kwwnPcIzgPHHy96l|FmB^@?5NQKohE+g-(UCyh5Vt;4b1)l7HScni}y
+zG}~RnbT5rx%XFruujBrz!?fK`xwGX`e^!1`zw6x<NT0=Dz){TU7rxConyzBkXk*f6
+z|C?}aK>D1|h}KHe=Z>I3L@P?K<`36sMd|Z+v*z5R`5Tw%^Lb-e-5=5y<de)twfvfw
+z2;bqTUstAu*oL$as}z8@<2{y)p`z!xtVV@X`gC^>(ULe{1zMKQxj-cb=)??FB$q^f
+z1vw?@l`fm88LCV<vsI$E&Y7d+6zarWRU}Mu#!^vbPj32rm#e24YD_slG3~iXaSfoN
+zYl&NhAJ<rg(rTUNEo^)6aCpeo@tD4F3Yn{TzXxxo{sKe#OqZ+DlU<Tt?Xo%Qhgc)s
+z^jdc*4e8pRC8j+~O?&E0|J1weYQ0rZdPJ4aJzj}!a4#cabPcPlU|Lyxfa=kW5?cQ<
+zm+7?7mGqzAvvC4Lc+3bsN9hxE+8}rPD320OSLW@?{YsZzaV@2T?Pzw=WmgzvCm+>i
+znYSy)u`WAG=^gKJsk9a|iZuwS%IXr=DQ!RTN?hk_yN<PK!71ao4+Vcoz=`x(GACsm
+zvk_TK<lU5|1gDJS5+{i*3zg*UglMe`eaQ=b$$`nr<b58SO6wAnS*eh$#L47;!NEL$
+z1-sImuJUx+>CJhm$Eaov^6smB1YqwtCv(ER$94Jl^eTrEKc$w)QW?Kiv>5(#W%zo?
+z5B%IW{O5iH{9IY2oS1Tw@(yo}s=afPS0d#k!zC$dG7Rz-r<(78@5KXNT~iKxL<|&8
+zBgyct%-mPm_%zo;9nZ?y-L!^Y-|ELH_h~h2GKn<jnQ7$*0{ZjEdx>A!Pw4^t`D%Bo
+zi~NCH$Vi{UX+Bnv9jChGft5t3g_xaR9(G(k+%riBzWd;A;+-Q0FIz(S>}Ni*`Jbx-
+zk*UGT5U+I3&xMWi*aLjHWgTdBll!z}<>K=ux%YxO&n%{j6pj0@i_Bbdgd*PS!B>$J
+z_}fn82zThIZW+D<N18pJ8;Iut%@f>Mk>+P`;g^q4n0ff4PYD#9!qwx0c@pGHdn|>&
+znRTN?jl1dG&gAmC1&+IvDL!<2Eak}KLy|mB@S&T>&IR*OZrOTh8oFd|mE%Uv7r{Ay
+zMeC59E=n3TWfOmcD))Od<rg5{7s9LFuXObS^;F3+3b#|;(m<#;-Mu@CMhWw9Zz}FY
+zBJoX^+(D9`+gk`v<nJJI2#c)GJ=L8O?7%M(d5yM(IOdZyj_}n=F};EB<vvfjYjkd~
+z19eO<;|l6!cStd9?<!?)qfz*ED!eU5G+hpR61Xux(YaPcalLKMF63fvdag&J*n5wp
+z@ozb~8dTPEK;n>L4g5ocv`{&f>BKW|T8QV`LF{JtF|;qIzL&UgH(l0EBI&W%Nb=YR
+zt0Cnv=Ho*L)@Fo`mE`rg<354hACr6%k~Q;FJbUw@lTRZIb#e<TF`QZ4tyhy(!Ho~D
+z7_p#wx#K?bOO?EJ#c3*cqC1i&IrDJ4y1c1jF1}Qf`+yx>Uy#q)-^=KKS<1$nR-}0m
+z%k!FfxF76dS=dF+$>W*VJly@f49VRfa4vplo{Npxy%s&BwFWodx`Nbl=#;v76xU2u
+z7@^_h@Ol78S0UVQSF)a2(1ZQrJ@M)Nbfp@(Qd&uAumit(G|C)tkA=J*?wc$y`AF?a
+zK0zceqh5&a&0U9jBwx&rGJPgPgX5m!x-^jZj*Bs(JB%3P&SS3s&4^H=6UxjAW%lz-
+z8EMv(b+|*^UmRY6->)yE9`zSurpS<(pn-={rKzi(WlkSblD5~Kvdrm4%@tT>3<x|D
+zeWnVQrBX0mpW@3LM6T;ZuZ)vS9)`Hx^ZZ;MX9nq9Pa{p%-blk1&9d^9MS;~6u~P!e
+zE@e~95<F^Lu1i>BlP{G=oL^`js-KT@*{6<BmU+Gro?%oQKWy1gs`AP(s&GZX98$U9
+z85GOp2sf@^doCF0aOlu+RJfgzlHZpla0i_pCufexNj9Xit}BHn*_6*b_x%W-mwp7#
+z-XFnp0*zW+_gH&)*s;A-ESzy(QXvxCT=mI#IVeU;Cv(P75YjYpB{6pzOr*Lr;$c)>
+zynQFvN)HgAu9X4~uh$*7Qm?U@reml+Iqs(KiLpPgCVYmmoJnb(6Wp?xRH-vgW!BS3
+zp^uy8>~6ZA#)1B{4ykvU;-fz=Qaru=XPYU#&Ta5=2e1vxyyOrqK`*whAbIR=D?~h(
+z6l$07OrvMcOiVf~Wu%C5H(h+R%$%9AGiN3Y)^lSfCPPWaF3Id%Fsmh5A1L<h=XLmb
+zq?gBxy>2;==6l^z3Kcp{p$<Z)3hEqmn(i+bxKXHpp3+<zsMSiuIh`-8aP;@8^?MSZ
+zJ5I9BC>Fx=4v!EL1YfE)g@h|pHRWy^*^3&B7pGsk@C>_@)3`1{8m`jq_mw9wU-5tK
+zvZ&z3FIMXGK6N!u^Zlv;)V%w=t0Z0e8y9N@o!;+ae-oYl)(Z!n{?1Depu1S^_wHm;
+z#z#K?bANC*(J8p`qm`q~RRoRY>Trh#KBxORKVl`JCS5&SsFm-?xRvj(0=#4Bf3x&$
+z<lqf7`b*y!8)*>MHjWGYlm#DowZoFiRDjUx{2)a+Uy+-KyEO0ui#l0wZvjw3O-W@{
+zSh*A>qs*xC=JKlp$J39bys#>OXfPy+GiQ`(2ZgaZ+`>R5OG{#l8R*F^>JoV1f3wJ}
+zpSqz(Ho3Wh?-NP`L(=-0($ozomewawOmw`r!0_Kmn-sY5f0E`6I-gRT|CvPaphJC;
+z2c3<t)2Y;);im*b`ThiS0YycdE<(#8RpN`4el|-y{y1Y)N-Xf8UxKgMhUpTq*KG4i
+z(|J0>9qk8kW3FGej#zjLDjxI=coo4{ib(3^KL2{kxKn57F_W$#{oLy*_ese$ao)7-
+zuU;vChP{t)&y^2Tf`7is!?E%UDe!aorp$?wtFAu+p&UP#Yg(XlV`@6YXW^AgwXnpl
+zCVU<qz*mV9dwp@+5z4asXNAX_KD{b3Puq`>!#C)-MTYvOaZ%n&Rl(GjW_+n@+tI53
+z(?7LrQEL?*<JHpS3|hwU2hY+%kJA<880K_e3}8OxBt8%6ZmOiahH8d-F%UaLy%@lh
+z%MHZ>`2Hau{TI@WHeX(R_A)bD&oH|Kn1S+Hg!^(}3!Q=+*R0leDqjikmm>8&yT1h3
+zC_YA+H(clfQyuPGfyH!(^uM^{q8A2onbMw?2l{%*an59cPn_sD<7;RZ?Hc4~L)5Pu
+z$46+h2)A3Xn(Sa3<1d(c1V3gQ{);QJi>WQi1d5d@Za!6w?;zvwW~pO?eaM>Jk8%0>
+zPY|zydt}^|b+6#hxXh2gwAS4%w9LCK)EC%+_J?S_WCq%FuDfxwWg9g$2c#NYxIU%K
+zz*jP%T&j_28HKMp+&zKZlm08~w8*kRD3j!?D}P1C8kS1ew7f;#DC{H4%DnZ+CxL5O
+z=SrENbC-gcCxka;zo2V`ftf2)>N$qyep5WFaK8-v>wgig*F1Dl>x?vS11OQ9U`i%g
+z>)ktv33?hm)Zw-dPGheB;x?ncVYiGLaHQFdSe$!u@J^Ce$kGb=hGik&tn|Es8<jF$
+z#d#%8+`+)!|Jk^huz?9~AULb{|KqSRW)}|RD@nc=%zWpxR7C;ZE?6BqV|gR(TU5#$
+z+drfPzwAjO0`-G@{7b^$*LX}M`~Ax2JwUuc8e&)mFOB1Giw@Sg39g4%8n*CcQJRp`
+zuZdjUsta3w;N3v{YO=_Y31Var<2y$Pu1?%de>zzvh>^kA31Var6GVT01nl|(s9F?b
+zBZGJInT`SKiO6U#t)~P(tu9f=c;fQ8j5{{CCsmEUtB__(_=;yFKf^K)w<y>|dAYZv
+zpWkHn^Y;DO%XC+Xoy_Ch6u&+AB5~uIReTGDZdduOQ%2M2<0O__N8dSDx9l}94SBu!
+z)(dx$=|Ot!!}7G6kpE7lm5&dJkITF|viaXh9o$W2)PQOdF0*`Grk<)X-*~=^pQg$O
+zH}1MPpE38mAeRho+<ozYrJO<wj(X7WP*-N9gY3MGCfnTC;3e#xox8<$R}bYbTH@}$
+zn7l^SOJTp!`YiUE28(caZt!!Kj7#MLrH}rBA=xV3>sm1@L%!@jp6bPp7nkq4*l!n(
+z_Oo<$e7|6m6E#IO70?gigL?1N_V@5xC`D{(`+J!@3r6c{<ZL9<|Koae##OGxW+gq&
+z^uPI~QeW}u^f!Gv_1{O3W(hxhG7N(~8&ZRTVt}cScyRjb>UANNbJS>$qumyt-0L%c
+z>od38>BIl_;jZWU@ZWv-sC>&_PyA8CJ+j^BKKX(#=B=cTN!hFHc8_xVrg!TYOg}#T
+zD7S07E_6K}$Z|S%Je?rw5JFN|ryS!1(?@q4(~<8Nre+WeEsOcY>2|JL+|4C|p28J(
+z%b~3HDK2Mm0meHFpwhikX^S955JRVa#7Qp`b#sI19Xo<Ay|br<H*Cw0WNL9YPIiF}
+z^j1+nGQaC-N=7%55%OhpS0Ym(@@SF~(uT8)W4e)svDBZA^)#olg*}wzWMNNHLOSW4
+z5l@z4qK}^`C$K%l+AG^Vqo?*t|DMI&GCL0I$)Zk3^(sNvUX&2^@{y9vY^pLFq|0!L
+z-kzXTAM7Jylp!aZ9GS|eS;IVI=oJ7FO69p7^LyNQrn04<FC;*1+h439nVcLzBG@=d
+z4)i5*?kUmBU5bx9GVs)^E_a<kkBw*29f?7nDXIoB>IVC@WeM4$og#sgIVX@X=C9~D
+zT~&cTK9Z+$@;GOTTYfBZhCnyFXQ-GdVup#Ck{oU%$-EH;GbL#sd);KTdNY)$<{V|%
+zqkz$*)zLK`<JD3%NlY#2Z6bt0fK-e#Sz{Pa&z1^%?QzC1sd2to&8{aI1s%!L{4MA+
+zJCYZ;(&MEb!cfSrqH)%*>=`{djL*t;n5a$HF;z>w_Ussl;xz07^iw%M!9j>|jm`sw
+zcAavN!#!vg$gu(iokq76i5j2pCqmMF0CkWwkn22X7RajwQqqw4t<U$Mkk9&%P;n>B
+zk*-q)a=uq;CP<i<;_P+HT9JCdX9Nk&nh`1Aj+t==2ms%?PASN0Py7s!(9GgXJv)|r
+zjHMu<Q8OM{=@ck6HB9j|K%DDLv1Q@ndA4W7RFLpqz**&hhWsFV5(!xCI#WUV8cS`B
+zxRp7_(>M(z1a=_l<#eZ^PhKyt4)^-(AkjV{r_O0`m>Gz#ewwX*w*dWJO;D(U%<-UU
+zAo+)Cd~idQs~-w;YLv%V4syK*O#>N?DT~w#9%DJkH#}$>$TwrkBK4WaSniRu_~Jtw
+zh>dzX3QCm&+1rDrfgIsM<sk3!plKl05BEs}$pZO-&js=e4=VS_pt6h#PIHAk+JnkL
+z_V=J4(Ntw<Dzjb6ymrC!KN<}{!tLyzvR0&ad5$at2_I`lq}qH&kCd8fMtHotSN}4Q
+zaC5-fSOL1&X9HOuBM+$?eMXRI5Um)gKl+RypNo-*)NY><BpOdkL~4)E=#kP$QfEnZ
+z@|vy;BwAH7B6XtA2olY%8Fire|ItY)cGN+`D#+sm;)12ENFgqW5ux!fzpO_Zjwx-8
+zZ@N-6-ElFDNTCs3rvxOwT+avT1qpv^1Ce^uXM~^k`H)8%ekKDY1z)ijtm9irA0?Fy
+zIQgv>i(~Up?>G`m&}qnxlf!#|@e!7DduOTK1Z@Sh-1B(}0vT~iPD42O^(oO3{r}K`
+z?rZd9$kq`9@#q}H2of4KBa|ZWh!G_0(2Twjnt~}4rA|R-S#B#5FotGSSaQABoKrx;
+z5>*t2Kx=}@c$28Y#9(+B0S9eH7QzGyj4ZoOP=G;?oB<L#wKJd&gA_4>gaw)r$}s>C
+zBS_ej*u602cF(;Oa!9}!qo<waxwix)EK%--A<#-i?b_!`f5PXDX+{H?o1&RrrxIkI
+zKx}?_D^eSMMv&LVFe0_pXG~_tWPex$`I-k!0}0K%D5}WMqG_zRXU&D4l4&4+B9O@r
+zEb6m^gt;a=Fuw|MQ**p4OX13oyeiBDi7K!wOFiQkc-G7W2}3m_QY}6sNSLS@k@5|W
+zTd2nyJOu`4d*Ww-G!35O8GNnJ2ojpvjw!83`F6}o*7i{DIu#&Sd5)V3(zK((vja^{
+z>ur#Ci)m~}MJrOi9aEFp0ZjoXw-xkto*^Y5`*>BK3Y(ysOM+hSv6a9Vw|dZ2kT8o&
+z+ICGB-HUu1KtAI^Ghjo3C%gnCOmUqVh@WPUYX+=>hlmU0y&hNGz`?s|@$pkR2kD+y
+zoaHtXiPok3|6qYvX^a91(bT3szoxzvt?k6Xj!ylc>r;6Dq(jHWSpnvKo~iY@tw=xu
+z4bmX>@7(CFpF@1fG=Jv{8`6pdB+w`d(hxQzPS|cSKQC3Qp>iO{3lwzdy-XzfrD;A6
+z>GD>jMhi-%LE=ulX0+=NueJ<o`F0*3<a3ZvPAvoSKA#KZ6CP9o@*f^F4di*AsZ&9o
+z??KZ*R(a6WtAxC$oo5%wDe{nkuBAZYqhDk_$Y1(gAn*2|sUUZFP~5N%XVD!*b<m0v
+z<V+8$1c^2YI;#U-1Lb@5DFr!RAa0=2R@CwtK~-ra%BAXQ%zAR56=~S4n6+*Ge^@=h
+zGjR$?n8>Q9B(QM`Y&3&t%8!WM3Ix%&p3<2hp_E1dkWfRzJxDY>n^xg@1+D8kGeM$t
+zNgPPHgSdP*XbO!}>)AB}WSs|<fov8?^*jXbXCB`Sko!zNBphkMj?QZ5dY4`)SmN~d
+zDssCQ2QxsTF_khqKow|Lrk$uor6~MC!n3Y33la5{r*alZU*)n!FPMJib%0qQ(Kl!*
+z+1QGN@8!5@{6SF#J!Az)gt8Ka#HYgFncngzN3C>vQGEAlg%e-~i2(^Clo;DDP!I7j
+zeF(ZJUO=Wuw+cEdSGOY3-Wz6Szz$z2^=Mn^$I=*R_5gKzo2OoQu9Y*5qaYs@NHsJ<
+z;xVtuO3+jo@)AZ#f>r$uA{Qeuv4BKCQ`np<iZJXF1cg<eA4))?>k${a99%>YyyVA6
+z+&~&XQ%r$TPnv$P{TE-(s|?DK0d^_03<jV?ErU?`QXD~#NFXMzrET7TGc+mBD<Ut&
+zq2C;}BK04yUCTj2v1WvBoRRxYj5wr%UK5ppL=+!h9Jr`sK@-lOi_9<O+}^=YeOdvf
+zc>_h<q70?Ml5k>*XQEpO(2p|$tWK0AYP?mFw^q)Et$;Roww8k27|#u*I72X46ILUh
+zDM2;RDV`FgiS9(%JPEbMGbPZrTeQ64)w&#Hu)VHaf}x^|WVL!M<sk19DDff^1t)j~
+z%Rtr|1<P8I!k1KOr47>5P!<;j&~T@xp%kQ9urz7Gfl`n!sz4Wb!b(8GY-XD(*)W=n
+z1$nVw5+whql@H<q3Cj{)$YlvTY@y}=>D$oYfQBu^2J(DgAxM}<Tp$~TD?pEc?BhYn
+z+vQ0r2l<geiQ5|mAMpy7f&9>erhznN#kVYEZT1S5f`l>TQjn&s_{N5;Cp}qHKtcd5
+z*+H7J;@7m0wcV3d0TKe}79~hiRz+M8LKe7PXF5o;;PkkHFNyNEJtIm$e&9h<K|)r7
+zuKk5@ckG~pfUXZa33;>!O$B+Z2bJ3~(=NW0%_3VYIn#Y9ARqRinIIn*NJkn{cW1!P
+zxD|Z7__+J^U>V}6D+T$G2h9KpooqpAD^k7%arY@uo9jGTr6~1@5A~Aw2>8_>J}B~5
+z3c22gK>kXgfHR~uT`GT~=Y+Ti8&7uDLSL0LH95$)Jt(g6;tih)!}Y#b>S7<{v7VJB
+zAWxC^<msY%mXIwz1oC<hDgnvA2Iqqcz9!^XK7<PE-DDJ3vD7{4`5<nMF;*%X_9|TR
+z6X9Orm5RGrb+*)MhF?37Xdb@IklZrQ$XW3fo`tHs?QxZWM3qPus`4w(sJO+}_)gkA
+z)pAboDC=s;y4zzZ0r`*zRcbN*|4CAhnO<$<+z1wUfkFwSUn<Vx10pb0ba!+blizi-
+znQ1^rxil$HFT2FA{o>1&Cny(xFRel%qQ;AixN8Ei%n%l(ABhECxpI&YmC(+=3;$ud
+z9(v9gFI39M3R&nuacy(jky(}s%NkEgTwT%m9`{(vpAd4p2gT`r<j5@O!a*;x%Tt8(
+z<3CRDArX8S77PSqe8FRdL~o*z#1C^#opxjv3@6w7f`2BY-#z05>uv2E=P)dK7dyxK
+z!WRs(po=z-h60ea0_jN)sUGsS5ix?iS0K%Z)O>mEnixS|>OtiouNFv`Me2EvaTdsz
+zV;F6(qGkuYnw5b>b*L>sqAskI*85V=?q1ENf<#?3BT}diNd(#88C(Vub<t&!y2)dl
+z3i4M1(e3-mtw^BSqywbsfdorbsrg>d1EnD030hBqgxzdhX)97|JmX41no1L_Wkngp
+z(qa=NWU_`S2{cSeq#?lyH%>zZG@v!<1}aE2B`dA)8WyGyBS<Kxd$}OdLb@zca6Xj<
+zX}ToAGCI!S>G1|ngQ3rR-EJDlpwXMAw<1;T1?M!73k0IOiz{1^xY_3ed8^OowjzO8
+zraMs};Tv|q^aL$7J&~uTx5871T#^V99@7%-KHE>CZJZZ%B`CPfhwM^t2)d|x=!FET
+zLcIoNp_eH>Bz`IK32bad0?Mhdt@PWtMlD679+WJ8_%1)IjJraLFYb*_DE_0AdfgYL
+z*s<}wa+3trtzK}I+7*gtDFgRyQi^;Nzi2@@FuBfow&;~o9;}IOBE|E>ud8gH1gf@*
+zs;}gHxci~tMK^2jEL*LA1=|YfRS`p3cqt0dUdf_GAxJ1SxNTQJCs-3a>dBSPSuW?p
+zRl(+^N7$Khu?D8$B9QK_u36oRRGFYO6@Y|h&1hEvxih7pQCmQBJ(;B-F+>^M$poJt
+zV<%D&ME(W|nTNL%TnSv=BAPG+2AsS&@7X*Fx@9~|+|@sZp+`kyfS&f-^?y?GUY2u5
+zFX-qU=w!^#33Gy*C$_u<4medtz43BBtV%Es^@hqNy<3s+hwQl98Yl-P3GBc?yHi9T
+zF6M3CgfR~$-l&NW9U@5W5R_sbBs3?ErFW#jsok_VDhTrL9#jdkv+P^KV{v(0%f-to
+zgDkUP{CY0FU?~cwibh&lgA5r)l(r%T4aBHx;{T5qKLz4Zv3AbJ{VUT>c3S~J9M?2{
+zrPfYd12KF<8T2O4ZPRWO5<(L^3ab^CIyuu!)V~#pwVtRFkiRkc{3>e7Hj73SSmm1#
+zclYcP5eaJ#7oy-@C1uj+Ar$Qc*NXJ5p2czZy1GcSjq_Tx9AwJT+J1Th3^G+99cf5m
+zLwsVi>mDz@4B`Wx_-P;^kj0m^BIS#ZyJWvWtgiKfkA8dFiqsumoyu&xV8j%UB~G@@
+zl0rMnr^NLxa23T^fK;g`z8oYpQpYD#ZM(Khfmi*4e--j=51I<{T@Q+D*WK}@Y+XDd
+z=tuAJ_)8ezZ<`;lGUKh~<?`JAK{?}{S-hHTm&d!hcrBMdIm`#-*zexzT>n2_N;`!2
+z$mCTpyf5Z+YU(z5M1F^y@l+g-z-@j!|F+*&!SisNf0sODZj&=!lfXl0oB#jN_9lQ)
+z6xsiH_jD2(0!cW<3kM8>2RV@YOgMA`Q34?l6c|G?AtSlW%y3_lppFq2++{^&L0xs(
+zT~=LPUBnAK0Nr&(*Hv^^(G^$lL|_q5{_j=2*IiRHgRcMYua)UnpZe6RSFc`GSNBZ1
+z_$$c=$lZ_9nZN7Q`5)4=Lw>wx(lbDQ7O3-g(c`sO=**AX-l4S4Z=@CF0Xlz3XM-;B
+zI-i%rt;FNyHLt{VKCeA>{k#^{`Mj*zK=tc)k2?QB;yp~~N9oLK9-aR$%HL1tZ|Iyx
+z7u&XU?oMaDJg+MTQT|Xm`;zc^R^C9fFJFRqM%VRY+<1)J;Fs*C`3?Lzvk3=qFr6C-
+zHRT5DD{CWFf!u{d2KfgK=vN!8k1Xsrw?2|PCm0SHDn%x0gL87{R#wLI2ePV|Lb>&U
+za1j2*f^n6F7KMzQoWvR`ni?w%qhdbpGL%z^?SnmVU^k$PbKv!RhB0SRI1pM;(I``)
+za8<COzaxXSAj6b^``&~k91hk6BnafHKsCrP_C-MnL!n@U!+`x&q#Ue=Gt3TD9>#xl
+zQy|a;8|Oqq{VHpN0YL<JOY>x*5pyEJ+Hk*M{U|gXJpnlUs-qGOk`(ykbegl^r>;+1
+z=9?pDSe@3|U1t2@62p^Xrmaf*+r(n4=0MTJmKl*ttab+`S{)`>jcfCKKes+yYImx!
+zy4Y*2u1BoKoD`3BRXD}8@>f}N4_MuEtePC_^byvKwYNY{cst~D^jr+Di#TV56*>aY
+zOoYz&<eOu2UwvcxOzR2+BlZD6&+^=0ns#TaaT9!;1|N`f#U{uY>B%(@4#^&J^#zl@
+z{9}s8E=w`Lo;G^e{eh8xvD(`sfOhW+`*k3`W9)&%-76*txqRa2VH0OqnXp+6q)Y5_
+zI}a3}Z;!CMUDDrLV0UV^%EET8wbOvC5%6Z+ob?g=^v%bHjr!w!-@Ng&tS;47P1x!_
+zVTRRZtvz!1NYMSk@~xojZWAkgXE`?fUeoseVbriu)`SBomi6*-G<cgi0pvZ)R|$E9
+z?YGM9BX$?-Ix`&k-K<>e<`vK)NOuVjyCNk8%(JW)mfN6Bh<`TiBMv$t#UsGijB?6;
+zAMRCW&amII+Ijk-yLy#xw$`k$H(4#_Dp;>tb8_%=0e*s!zgV6FMjSBh>MMp%w9YJF
+zXOFTvl*7keE6VL&Q1NrZ%5ThSY~GC`alOYLF%eQHmf2n?{Jpsf601aOPnxT&b5>a$
+zHgz68a&rhBn^q2=p6zLitqyjlZaZ$YI&7b5Ee>1l%B@D*dyUn(JTm`|$b4(g){$1o
+zdmb2k-?B}1*Op<U@?NsOh4(RaE&F4n>;~wC?N<5`E0Pno2CuS;%Asf1w%lNWGs>-<
+z%X6$}%~iS9j^&;l^M!}(X6UUwR#&@|T?3{)v(yIXST9&dhOZu0Y+Yq{T5YB8vBD#)
+z_T|=)t@ia+9=6~&OYA*BJD37&kF{Y5M#-U+@`+UwCr+Guz3+azkKJv7HD*s_`iz-F
+zMn)oYud_0bSnZEkkFW3yF^^i+tLz(~k=XUOEw$0Ddo8<@XB5QL+80t%tp}E^1?+Xt
+z)=`kyvJ6f7r>A^d@k`BC$34*QUoSrpDYM=K57w+|wuac9fcDW+91mMPc8)b+EpRr&
+zlN2C*V61Af&ctzWa=G0JfMW(GpqnwV$J}Gp+SS&)O?FS~-^=#^bgO5N)&BK=f#bgx
+zow7E?lZFk({(Cp&bt~7?%e1@@FxFi7fEL`fc)Qj6fOREUVOk%gmZzjx_bnE~@RL-}
+zxh5okv3LYzy_34f8oPbe?n!{Wx!B$cMgL`ZdYh2-YRZuf)-@Ae1nA)<IQ-s7!R+5I
+z!E*aj$|1NOUwj1Q?@~vA+${9Hm5Niwe;1>7?n$*bp}xh~6ZfQ!m=1}z7u(g4x<3_F
+zy()@)mvZ0@NUU0dWz>w{rXH|IS`V&(5#8BJKQOTfZ2Z?^9DtvudM+?=Zh-#=tiNs1
+z`_M~}`Sv0lz4xWTWRYUMwFs--lve(Nr%#uMM_TEgekKG|E@b_23HHjXDYh4#`HQsI
+z;ba}aINzFf|6O)xdxo`VY55i4_s6VNm(PILg_x$_FXr7~z2EPL-QVgO<_G+hHS=(L
+zFPNSC!@E#x8!9VmaVj_bMWu6_DjI7H*!&Do1BeyDdLvxtuW5)h8U9dBLsJ-EgcJ%c
+z4*0_c>?aa#s%%^&6ozYpA>f6={yD+=Du1vMcZD;6oi8SPe`C0z9%~3S!k%@8%O)aT
+z1@L-N5Bh*M3Cync&#4FnjA@0%W#j!Ng+)_jenl89THH_{FvK2pe!LtS)xjpHT8Om*
+z2J5)x&^~NV72w$Js$gZ<KQ|D@Bp6gt+gMW}u3(s&Q(I9#4~44W+#olxA}pF%+fYB(
+zD?V_mG2Cwtwub{BHKEp;iu$VBfN|;NW!|y*`QCv!19I}b{qyn%<qgUk>g`t-j?@Q6
+z!d7a5reGx`E1D{6M#9y<-=G2BesjJ3CiVCBs}6-LD(CfUY-$JxD#Nf*CinxYbZo8$
+z$D+}$9g%vn0uAz42jMML4M>-31Z<@6C2nfxhrKt!Cu$7T21D3Fb`x}GeIu+V!qskT
+zQ7`rczTT>?qOpIl3iglzv%(GFyXxACxgqJo`bZswOQgwP*-#s)gN}Bza-W83U?<Ot
+z#>PN>NU>0C&!@AYhy4wW;UES~Lv5A6p}IPREunL6O+#HESNJM-(&dFEx%0=CjL(f*
+zg5<*L1tX;n)WBkHo>;Dkuz}ufjMP_ZZFfUi#t&|Vh?a#G3Lip`%?mU^+hKb^RJ$ku
+z{T}20kY9wn2<`fYDiO};w|e{#V<k{ghi!*$;qf85GDgd|qOnu`BIXSt7EYZyMHsN4
+zDHsmGFhUz3c$$p*3K+B0DY7d=VsPRpg*_{k$N+PLp(^NXG0cPY6%Yw9#6lG?8Hh0k
+z)-_cc5F0r9Lg9u+9Au0Ab+87;HDv&bVx^Gj1{XTq@Wa5GXM|+fV5T#;M7W6v=`X6q
+zz(pOP8GH!a2^xYb_cc}2$_+IUsBEaOHmbo{BI2rr?atyCI~F<uXCg6mK%dq&EPxKe
+zuBob6B(y^WRWvQ~i~bBzeHFElfFZWIlui(11HH<V4jRr4!4XGsP=!u#!&;0ap8H&w
+zx(0QjXT&6_j4x$)A?1>y;_*0%K`Brz-7m%-)P)QCm_~@bb78pQFaW)9F96dXIz?1c
+zFPcz?VJBTGqQmVi2u;J^*bp)ru_Ihu?7M0BWpsy(xpl(LqH9FME5Z#y;V!gMYHkcv
+zx`8jIKVb^{3_47d#QjfU>KB7Tm?(#V=ukgw=UV}7nIEp0Qybuc?e|l27Rvc%p0EWv
+z6s&?qgR({l8yrb6O`@Ot)fK^71A+;ZU~r+!fF1$^fu%Yd*rFA}D;QY8xirOu46ti%
+zxW*7I@%zR7h<^@tpCR1o`bzE%3V~8uSs!kymDjcUa6<(`3*`kvTqC_WZC1>IaVR5g
+z4vZq4Myq9fF2MN2J0L$4ZZ!PDQ=(r74M0ypWQeGwp{c}=7(XIHkR-;hoYt%BAR;Qk
+z=$M!hVUCrD#6*bI`r#T`l`l{I<>_L18X!*t4ZaEpL*%R@Dv8ubLV+qQGzV`p{TKJg
+zDyxHm+A5qGAbfF_4pvJa%WE!OZqPvynEN4M7yDr%5*-@>FAbsg&Ve3{G|I`ybvSHJ
+zs)Q;w4qJqA<Z|GWs-!B!_SuFQSPR8u34x$q)zELUP13t?DZopffyP|iAFP2e67z)-
+z!4XCA3$Jb(J9e12Z`qtkeK;a7?)?TuL@IxI{-B(^0XYNC*Dm^Sn@dj#4Ri4n!(5nU
+zp4q;Qy%uiOiy`kUybp%sdHfiYk#)0YOh)%L*7ywXO(}&LeXmO$myy?;=9$_qqi<n`
+z7xI8JCd0loeW8XFrW@s;q89bQF&*!r3p28=^Au)uZ?-_oigp>@$7W;|V&RF7T$ql!
+zDZ`iUxx`6al0MUsed$+$x;^j@53wf|*zq&8^=7nnP0E;zzBi$**QJfi7}DHkQbvL2
+zwRRap3N!Mc6=M|3p^nQSV{BZ;rRnI8i@+~<h~0|ZIzR)}0UEDME5te`WE@Vh?l2S9
+zB7RwkkI<HqzKexc*%#=0Jnp~`&*}{1Wy8NMgbzX7_1&ZlZ$(D;al&;*cgWgHygtag
+zBqOWY<9{{-o-_I&`3dD+kIzFB*)Mz~>@UuE(DE!uXg>HJiVvaZAU*L}Y$9E*FUDo8
+zH9hwx)HOEUGb3Yz>Cd>+ybR8Tzyx*Z>kXv89|Ep^w?AF|mu9TBthR}L4Uq@$#Dsqb
+zNuPM%C+NEgWA8eMJ#TZ$gp3`wXMej4FF@d02w_nSO2r>&PKxox$@m=n<7aZPmT9?v
+zBNdZl;UlU9hh@+MYb6hVFYQtEi!n+07XK-o!bj1<r&kFM%b;JmYk3xY!I9{&jP{9O
+z(4Y9hvL$!Oj4NX$d9Z95i65X^&g>Mc%91;m#)6Qt<hG#+aQdc6$>|0%J;qj0x$R>o
+z@bg|m#asn)P7?mWB=`uxQ4hZ`g7?askc59l61*Y_9!!ESNP>GIG!wP=df<!pQYi9H
+zZ0nQg*_Z_XZ4!K25**_<kv*>_!QTg5*a>qP9z17$0W#uQ6w+ee1k979y*A*;=RY+O
+z^C|GV5zc=ABIZxPdlSxoDk0`hzy~JLe@PPjA4%|%B={9c@Tw&Eyd?OdB>447@LQAM
+zn*bMnqu-i|c^~|6e-i$-B>0Xb_=`#KSCZiPhPy=ZgRfUZJKv=#MO;6?&M%YjQ{lQG
+z;)fPO{66SzfG5)Lez~EpEMZB8_q*<zk5+jA;F=J!W0!=qY~))}aW_Jbw16w0FvUCw
+z0Yyy4TO6e(TwT)RBfRf$o_6W0N|8s8iDK^LuvE<5irWf&I^(A3zE|EgxG>(gxhZka
+z?Iz{T8>EHx&dsX0wGhwS;3kHi?EwkQ$LD=@^0o>9<vB#`eUGXUZx^8?KJWpU9xTbn
+zHtsEqa4X!|Gg84fl8_;9+*u{m8G8eYJqS)xZr0pt=!Q!^1As7d-WG++4GgJo@%<`r
+ze1w^B;Ch6nFp>TM;t~(M^5WHcCH%wV7~!Y~uT`w4BLZ;X30{lq;D02X_4Gv&98W5I
+zRnK2FzGNH5z9jq)HGT;dIGTiChU-E&FdJW~%Jzp8{0s&EnS$ef3(S95!SO22IDF3|
+z4%CnLDU6R&@Us>Ca>Cg^dqrsjz8sPQ>QVg@Quyj>X;~8fMg{Mo)Vo#DgZ;ZjR%bk_
+z@YQ;AXz7RcoTKPzP;k|sHz~MR;XkI}Jr(>d!Z{A}AP<l46u#;=Fa5Sbw<n))_U8$y
+z#u%ya)pnICxayyEnw~t0`(G)1RnKb*ANvJu#p5%D-wV<l54;3M`_EPI?${Y{u>B8G
+zz1f5#U#)kD#y?E_;w1cO3Lovny78Ekgg;;5qqqYNfMZn>{;xH@kH*OZN%%W7{z}sS
+z*ChP6HGTo{4<+GyXi`I3HvD7%XA{nT=3AjWg|GT~q{hF2+Ql3Hp?;Omo5QgFM(UTV
+zlIUNf;HsUw6}-1%|1W9qv;GIkp1TRx?fH#@_f_;fui$u}&i;8z!TTt<jTORy`qlAr
+zkZ?R<(E|8~$JYw~B1p6T3+XpR%)dmi;l<;GqkeTBo}u796+H_H#}m5hD)@)TBMQGC
+zq`6)X-7=znb$$*hINnn+f0csgDmd<cjR)$%xr+H)6+B<TQ|Oiy`TZ6AbOpzI2i7x0
+z!3QXKK*3c%Jf`64_5Cdc$9qE7|G9$qQ}FKe$9>o@IHXR{_26v6(S9|~hbXuj4<$+P
+zr3$Xvvz~CS_b|ot?FwJ5cbkH%^}eI&DIxpcSNN(Pek6eHQuTCm{&q$Bp*!h0lkhk{
+zD7dQUGEEP^%xk*BSM90N_;*shAq{UNd|?tj>l9qI=hq6Z&L>|hxVp~ilm(7~gU8oe
+znKUjY9Q`mD{&8IWO2M-g{7(w5@?R&M=YcZPe^}x7QuOqq-^O9R>UbGWIO~~6dL}D;
+zRZoS2<GnW9zcC5^n1T;g_<Iyw_1n7&K1|_%N;unjCE1BPLgRt$8V>*1o_2J<h`6f1
+zmxALn9p(>HaFt(7IFGLqT33}Td^HZQ(fItvxn)WCe^B^1|4)X0cs#4{RsX-F;A$M+
+z&{>va|J2E(fqO0EfqobT|G2$-6nv0^x25}L<g5BGSMUObA5d^LuI^Is3l;vOgtI?a
+zl0P3;_^Ll&QE+uUrs2&49J-wn6+g0+*BDwq&~gBtB*-#e!fCj~;do8QL+5)1>f(nf
+zjcWrun7@|v=SkSX`Q1-AcJN^StF#U)5U7hkLby-EHxOQ;;ryDkat%L?9B`F}^ZNj5
+zG`u@q=NdJf9}zFq@J70Ruhj4@w4S&@!yhF5Yc-r7DR0nl{tfS)8qU8N-lF0AXkK_w
+z!@XG&*rwt9+iAM(5cd&ex?ocC1db|rT}stB_{(&Cq40F@zhj`nf%kfNaKFoxyWt9s
+z3%aC;tUMwhj`i{@L-AUG2jl!(dK}|;Fg}~s1LGy^;F}3A)^L1IiASkCIs8V7w+am(
+zM(wKB@K<PDU!&o_B|XbEd_VcES;Mzdhj2V_yDlI-ztZ^osa}o;=JWOO5sm*Ewf6}P
+z=Qp~)t>M?(5;&mY2g&}AHT)dXe?-Fv5&o5iS5v!0fIuGGe>3sgP&vlWq5F*t4Zn!^
+zT{WDapPs4VrBrWE4evs6!aFH&y>qDFd7~4?kCT7KX?kv>eksxLD@o5x4L_UsH5zUb
+zKdj*oll?0-oWDo7NyB$hyEbU}2(tek4d=LdP{S`EJD<>SUiZGB;k=#V>l(g~?0;Xw
+z`F*B`H5}J2czmbfA9I@g#Qnn0xlYsYrzxGS;qxe+ui^Y0XOxCdl;#){HQZ0*qFlpy
+z1B`%%XOaJ#G@P$r{BBWhR}bRfr15(bew&70L^$ukz<NHVetcNtPaytI4WCc^JsLiq
+z;_5XG=jS``YWOF_|3t&v)4X>f<+Gi4kUfJmyf4iIlQnz=>6xkFqlsUm;qxeclZK~L
+zdV_`!qyD`|!}(>CyEU9&`}ubb-$#1(Yxr1-tB*C@CO>?s;U~$D7U^TZO(R~WhOeV>
+zcczAaLFqmko=WM9HT)U!^JoqK2idPaug2^6`@}ER_}eIbm4<gAJ8L!kR?@#v!-Isk
+zX!yJ2hqW5c?>6P<-t4!ph_^-KKSlAsL&H~4y?@nk-Y)u04gWLs*GC%8^T>ZSd=UA~
+zL-n(r|K$GF@BxIMrQuu1&hs^VG3g(v;pvo~pySjp(>0v!snT$^=Nb*?dRJ@s9n}6?
+zH2f%~H*5H1WdBwTXZ`PKcr{%wzSZz2$Zt03V?Y0q@Gct8>!e;9&VI<%@Rj7Z5gN|@
+zQl#NWslTRacs|Wzl^V|Ny+OmDAw9Qi_(kOB-)Z=z<d;V@{5<0C(C{dwU)S(IP`&@r
+zaMsWBBKw*3f2;9Xe<$)E^H<P(*h|A%e?JXp{p$B1I4`mOaT=d@SedHftlzKUte@{k
+z+0Ki}PM&ue|A5MG()1LOpYPXjuJ<tw=X#&l@T;lbe`q-Cc~`^JDE+a9vwyzS@KVy>
+zhR)os(KKE<Yj^?mtNMKk`u{%^Z}}RZpT~~U@Br!Ibqd$Z@jqSTzeI63SHsy4{JLq@
+z!~W!#Ju}XJh-!KQ)L-{#IQQ=#HJq;>Z)iAwPxP6F&!+T$>5S7CT|z|5+S7c%c78<u
+zIZeU&ULFgarQqoQVU+Hp;K+X($#7hx;K=87z+eSO{-rdpUaH}IpD<m+ZED0!1xNjl
+zQasF6aMZt;__c(yAErVc9@i^;)bj!PYn{g5E7*qdM}?32zassQDmd!tNdDZR;K;v+
+z`kmk0i~dJ^6Y=+H^|mGd9M$yfrg8PHhVwW~Ma6Kie*7&g9+`x*AI6h@ex)yF(^naS
+zf1aj?=cQZ?zm@b4(ePem-x$KV-i=i61ci_F7KmC6=jFhdjs96rdgds6#E%m`Ps6XJ
+z^fh$mdQVWjtqP8=TnYd1Sg+vNwOy%y@7Hj?&)K8ksHZO~f#X#LM-~4fJ?;yD<@Y{<
+z3?Iie{+GmWPY>77Y}8*u1^A7-SPbLsVe)@Zg^w!ucbNRkUgV?Sj!}J=5TEsQqj6NC
+z;K=89-<B!38s~lmNB(I1fTLc+4-+0zaMZ)=v1JO5)P?l?vsJ@6NN?Bh4HUe;CY<}7
+z_l|l><M*S7h`Tj>3gLS-JVN+CH2u5*)z=!%&l~xBVe~VaxDx*1(UJVY{qlR#e};zd
+zBm7(q?~Trbqc7pyUVb;o1P$j6!fG^p0bPHu)$l(Pey@g)p?U0C4WCK)+X{|xyH{9g
+z7@sOQ#^<%fZ$tfz_S29SB|0iN^6w=6`5L~R@X-p6^==Vb;N1*_bDZ;abe_UT{rvrD
+ztHMW<o5;^=6&xX6SKO}P$Uj8<-)eX_`d;dO1xM<+Xe=Dt6dd*NdmQ<N-fTaQm)#ma
+zhrX}+tAe9`zK?ia!BIcIi0PjSj{KKtKKVewk$)e3&-9UkBcIp(#}pj-qr1Wf9A7Co
+z^1mVd7L8Yq|EGv=D>(A`zNV9cqyCHWOE5T2Q*h)Dqqyy<;K-j&{PPqX`ESy^m#5&!
+zf06hD6&(3DQh$|dcoc&O4nN^M9{HU-a}_>{4+^$nEKqQ)*MFMK;MX>@e{LmwwWgon
+z?Xy+G`Q1K$QuL$vu2gS4tKeAgOQioLO%K2G=N}3m#Vl+f90wE}^?X5kKGpEEy9>H;
+zT*C_q|Auh(8^2Si7tMb>Kk)D0@)aCi&-`M-*>7t}f0>5wC;SRc5AS?)t%mdWlE2dQ
+zc<2kO`!u|O@CP(JK=_|D{k$R0yBf~h+<dF)xsmjwVNk-se&hR)UWBtB?kE0*8r}wf
+z3<bvk4Zn!+p_+c)@n)We|AxkONYR5`T0n8qtl$_YlS%(g8Xh5hy@uaT_#K3Ed;8P)
+zeNDr8N3G8_d@b=i&=-@e$E0<5KMl_&+^^w<gfCKXoElERKRlWh9OIL}m*jUmalLnu
+zo<|fu>d7O&J+0uVr!UPvZz?!K{JqNw1xJ1f@jKD=2h}3P-<K39IP&@XwJQ`HugmAc
+zKRl`w9QoIg{^bge&<@Om;|2vsh`)#8_eZil{Cm!=8h<b8-=*LPtt9<>6&#^YiT{y;
+zBUC{AV+xMY0E*iTx_+`f{JYH_3Xc5Ch(AQZQ9s|0Pf&2=R}sHT!I9rc{To(r<nxA#
+z{DMUszZk+tiT{|!cXo6loX7jqG+y>AIO^eb{-+ww>xyqR{5Q0|vgrDcW}uz?z2Uip
+zbG`qidh<0r2Y)mK$7l^-OZYeiM?0J7IzCCkao%`=__H;<0)KP~M<wBG=Y6!OT&CdY
+zfBs$T^$L#d;=P&fQ1qic-_yKtug2%Ut9oAHqn#g+JufOa>NyK5frH<7$bRcV7q&Mw
+zKKIxA3Xb}(CjLPMNB#W#;fR7G|54(bw9evsJ@}&`IQaKMh@&2khb)bMIq`dF`1ORJ
+zOE~-g1@eEnhQCAjQVr+7N4r(iznApiso|&N9}U29ucn80F?v|xW4pT1e9P-iw$qCZ
+zhhx9ON573A{Rb2r_3%3Ia|K8K9mGGT;K)A+|L{1e;K+Z9_$jpBWdD!EAcZ4S!I6Kq
+z7g6|I8wE%G<EdTQ8h$s$?MMYjJ$HKH1CB8Yj(T|ge3^nH|8*~Xz%fO^k)MtZgkzS1
+zBmbVB0ygF-IP&?vsZPO>{}%C^6dd_!G!HCOaO5}if)6-u((qddU#H-xXEn`Z_Y#g~
+z<51*XZgwhs)W3)H@O=P}myZd5S<^F%?*ETzIKR{KTSY&vi+KKTPwQpY-;*x1T{Zl2
+z!h2}=b%dWwIJb-6nOUUa{Cl>5rspZrQ?KFg5gyX?@V+-2G@Rebd8eWW+j}P(2FHU6
+zj(*O`7O?S%rib6*`KpHVecET5p2?)=XcE3n>wWg~^~CQ$IQxw^-|=cVZ>KXt)AKvh
+z!}l?)hwtC2G(8W}ea=cv&r76dbrSyV8sF+I{kB=-^9DW-Y4{1M_ivh>^GMI%lkg8}
+z{F%i6RO9phKKuhd_Cp@sx12@yAMF1Xq^Bq0I)9MHe}wqMH9l|ubGe4|hCWwodiIf?
+zh9vwJjh}Iz^mA0>^X@<!H2e!}ARLb?I9}=s5QO6|3Xb#7_r(85!w1uR(w^2+=pWQ`
+z3H-z3ECokB{G4~7hCfDn$~Ale4n8;<H2gZkZ_w~9gx{y(4-)>AhTHVq=XDJ~oACEF
+zoHuPVX?@4>z|X(V(eR_BXN-pPbDx<Cj+fFCDWbVXwSuGHcq6yv8or6f%LWBUJ^c40
+zcPlvR`H=WeC^+)@d&yl2j{I|IT)eB`$nQ>eex%^YzmlH|(7KZSvy|{N6&&?6lAa3{
+z9QE+_g=K_e_~G?&J!ZmjmB!~?o~~8+*yZ^&F0NB>_4>X}!I7Wd2eli<FBKg5{QHNy
+z6dd^-`XU>y7aG2b@JAFJ_3-aTb|^UNIY9iEHGKW~s2$ef3XXbsJ+oiIQP0yCARF{4
+zIP!TNcud1PlmF9c-Hm=mJ^v*=U3fhX7`mP}1<TX;S6>L3a17P(-x5AX!}k+@sivQ|
+zuW3~H7_xgYkl@&;@%i1?_h@`!Eb#xN;MlJ27oisT`)ds!PWUbj=iNE}LO91Wzgzor
+z4d-`or_+4^`}3Eizl(-%C;V&;e~0isgmb<8?(STLkN(M{aWPuK+XHU)!`8xkhBUk%
+z;gdD|F2bh~&h_%U!CMp@=lL?B9mb1-qbb`k=-}9?;k*aU+k~@!o}+sIqv3}M|6Ien
+z=1Bd=H2u6O&DnIng7%}G6D8dksNiTP^CuI|_EeGnD>VE`!YehreXgvaM$^xm&iq2d
+z`JL(;6+PIGS5ZH1RdDRbT+;uDhL;k~_h)SXe8QjA>b;YmyM3tP{P!21EBeu%wPepp
+z1xI^sBmHf?kbr~Zg!h{1?G>=|{r;20&(ZLY2p_EB9r9%P5rnh;zmok|YB;|`zEaVH
+z_U|D3muvhCdcO8M4d-{sKcwj~EKml=GhT6W+LcFk{zb!Q5&oKnuP6LX!ns|e$et4#
+z&d(pa^fbi5{kx6yoUP#p2tQB5+vdyi7ZPql5?#aF-Aq+*950h4-S8_o@&{+hj2krk
+zJnEPA8qV=>w}u}e{&o%LcmMxO!O@;8$)5ixINEa_`7NcFB$#kQd?w*N6kM!xQY9}(
+z!I6J0@qG%8eEz$?DGH8!-sx{X;n*+enw>U$z;Ug{=l9;+t?+Ril~cd`M!``JKYw^g
+z!I6It@t@J~w+Y{^;HYP;2R`6<Rl!lui2edL{;lCR6aJxsqaOZ!!Vv{WJ^P4n()~Bb
+zXYY%p{xk(gJ-m+Urs2FUx`1%*N8YQUzrx3H&A%HNqu^-Il~nIU4Zoi75=}qv`B1Ci
+z7;km(504fF_dxouods+>q2V3qIp$l0b3BZ}AcErqjh{vQv}~EretU-OOjmI9+h6Iq
+zSvLj8_Vyeg%U_`2$mjLmSOrJ^O5zt2&VDW+dulZPW5mBk!~aG2Vh#5Ul=iI9^z-gI
+z_h~rqtMiPeXEN#8orM1{jek4w-_!WKNzY*o4^n%-({O%neiq$-vwxl@{vZX%uI0ab
+zy;Q+5PI#}LYQi}lN-XK0Yc%{9DH30*;ja;YrG^JmCI31NXMU@O^Y89{mIS|5!<SOM
+zcO=1ot>J%=<`}=x@CE1$IR2pF%zsG3Gl>7FhD$Am@q~smf2W3DP2=VHB=}1jPT^y`
+zk_3NK!|SNO-cEvlpy7Qnkl;9!1ph+AXG*&9UkyK-`sEu9XTCxAyBu#OPG)eVXn0TZ
+zb2|-Zex`<xCi^>U_)ePNPS<ee_t5a)rb>HyY53)Y_tkLb_tWr&be-k<dv5R7QoS)a
+z34er!znUfs6ePjNYxrVnZ&4C_vW8D3KbIxJXKMH$^21e0@EQ$oq4w4$!9yCJL2<hv
+z3BFvzdy)QCN${wK)8kfSO%i;)hCiMrE4VEQey4`7qxiok3BFasbE&@`OoIPe!=Ix#
+ze>@5PtcKr4`gbS6|EA$Dkw0J6@Ovpv_Gvit-`4P%RPTF9@Piu8f4B2V68xx!@1i*Q
+zG70{@hG&uAJbh#Xc|0=SPQy>6NnVDAUrX`dMZ=kYx`yu{JI~hepOOA^HJte=%J%{|
+zMbcv&qf0+&7d8j+GMO~q&~Sd9@Rz(;{$%3U(>jjz)Dcc*iTg+N5g)i_!vpyg3L<?U
+z`BlfgB3E)%exru(rSxAloY&8Jq#t$QzrEzol{!xI?JqQ(e_ydx!}<3H{CD}RpT9Rh
+ztnvAK?Ge-%=JRvijT+APQ~dX~%;$BrkrP@}2YUp-8D2pt&NVDG1!^mD!nnym4(!oT
+zVdTsS!PaRA<V5OggYyEli;SG62F%0K`8h)%iDe`fo0m^{Re?E?x&B~%bpvP>a>blE
+zO@a9_*|;@;R7I4giu$?mj(sY@DN&hZ!2Tlv&IVhIoXUo}I@l)7$f<|DUUFd57})Ct
+zUK2`c12z8YCfwcQ|L@@i1=vL#udJ_t1YX}V&hg7>{8|7*sel1GFWe{ves2hVy@K^n
+zc!_tVBjY^6X}U*9922^-6nmy{a=?o~LY+UgJl;+xYX6U|zktfq?J=a}Q9}0rj^;VW
+zx&7RZsgQv(g+0^cOOPP7!$pL|<r$s?LL&e7{heeKkYe<I8~DfN`TC9PNvvPDe+PZv
+zvjp<ggYD)s&O<D#yy0ibR9~8xIZx-#gN#J>*KCy~yan=%_TxON+rJbrT_={P9E+cz
+zo8~#0is$|eG7^=ad#Nn(B;PQQ0-bv!;EC+N;S*V4A(cb>JHS8P{>^~tI<ZLhGW>++
+zAM)gU>fGBQCsF;zr?Lo_$NDqjpI-m{fayB1<W#EvDs5ot+?`3v|7j&^fxjoxCKkQ?
+z6TnGie;(P-af<eLf`7XGF9C)+xt$=2<9FA~Gygpw!A@J*j(w1ksQedeWeKhO<I2BB
+z<yk+U&s)b*?3wFj^f(BJ>EpjImG7?kpWDynzW^bT|9s>>FI9;C!=IvXdG>2Zz_cm=
+zF^rne#3?Q~bo&$8jwK6zA<K8C{>SMAAFb&1<Jv1x{pA?gaPaRFWh%}bL+;d*(~#?x
+zM;@K=BxU(IXutrGGid0Lp@W2URl61Ai!bq*Zi`HK<C>e|8sR&&b}m{V-~xC@U3a5!
+zdf~LfvcjolrM~Fjea)Zr^+iWy`=T#L!`XI~uQjE2Um*LU<FdQw?>LC%e5-e4wiH2E
+z7q>3)`J&HXw)$jd%PvsvTQfB~>nTBrelDm_4HIQ|7e$}rqD9eN;gaGtHRdk(nI2{r
+z6BpEmF9NWz^)%m_g=TbWc6(W-vN*eaQFPqP<wcckikg@1E;lk;RzP)yE0>!_=IU=j
+z$J1D;_)&&0`p(h&GF#d}z6M5?3)2M3#$>kC1M#xT+}47u>YaP+>ao#r4Zh;&hk`IM
+zI_`6uDz%|fbfAx{Evh{2NM@F}Ec&8*j}&HhY<Xh?7}31LER43v-{EUs;xi(Hi=#_?
+zALnPDGtMwti?eNCYnSZ&9YxW7(i99CX$rD4Tb_sXHhj;wuXSd2_bT7TX9?$LuI`C7
+zH$T_+%2|ao3uhJ1F7!WJoq0|R(9wFR<@4=$S;;>xv_X5YAq#wm`h%_ntzO*@aA0k(
+zgSZCj)CS+7HUJ4bpMtuKr*TGMFBL_1hga+d03HZ+|Ni7js2bXnze8%qF|RaY^>DPG
+zyi^=LDY6coC$z6b6;SWCdRZ^{`q0lnq3asWFTxpzJ_Aa8ZB&J%`~@hYrs}mKnxn5n
+zKo>=imHJxGDPHsY!_ZOeuj1%`e9`^B=-Yz7dPgK}-0Dz4B;D8iY)R43w<G)WKfTfy
+zJxHE@b}f#NqUcE+A}}h-N{gbeM~@aoUxJ|mU8IZ;8+v_rN;bAp`UA%azNzYI8z2}c
+zjQXO_X0{YShG;GLO8V9p{dXZ=NMvd8>TO?i7X%{)^e+LI0S&GLWxD`e{W6HVE$o1N
+zaQVN5I<6!<Xyp(ioZs5{_%ohx=3`V!XbaCg{)`!(E7i4Ob&+Y!FWS-0MbRGId(a+;
+zLzo1dIK=BL#9?<O4%hCsFklWX=J;uTF(umh<84lS7Do>iN52-f<?ndf4f*JPX{y?f
+zAK$F7Ki-?aBl;$neL4kd5hY}gS3rF~5EP?;B1&YQV^rsG|KmLOoiF;OFM1TZ&=v%U
+zg1)VF;8tl<=ANO?XRhCo`RI->_d#>*D`!3HmS+;qSHpd+zV0+)JNj0?8h)iUVtm|D
+zj1OP)P8jb3?b7N2m4_prptAfOpbjiTSrkR>YhC>ixcRS^M!$Os`&GOs3(WM!L>kY;
+z%_mNV8>7!|&%$nr{wKPB8<xp@iNnyhdt9~+h!L&LPN|NjWQ)d9AV&9(YxN2sf5+-i
+z!|8?1-&W#&8%E@89}GyGe%g!aC(;E>^<tNU*#&Zf`uJa>B&L0<U%-n;c!21kqUdYB
+z=u09K90ZXb9!gUaM^#butn8?TUI2yBFMQFjxf`9>5N`SS9mbs*M&i4$R>fa%^(u-U
+z2OE6Rf0S;AK0jF${p)yW<&ke-Cc;68ufuCzIL^d@xB3_~v9+L}`GhC4<xY^7=QN*4
+z2`_3sVMnI=)|A2(?a;XBXLt?pz-vo)o;Zht9j9EF_nJ?bkqdpRKh11e1*N%FqOoIr
+z;bpR6I7t&<PHET%x_%1hxb{PRzUW(2Wy6V+C$EG$dG^6LiLvQsnCMhO^;+NVu|7}^
+z+CN_H)+H)w-gEL04g#95i=#&*A=c4{&IC&Sj%2ytL5(r->8uvMc^c<ch|Vmxzpc!c
+zOz^fZx?5EB7=9l0-7C69AUJ$xe0}m{41()}aR7?T4$qV#QAE*t+3HVm<#08Qx&Y0W
+zYkcKJYs%o?YP|9m?jDbBFnqhmJSflTb1?52+qb)rAdGK-U}O$`Ci0KVV2uO)y{|Z0
+z=Ytr}a(WsgEH3(Z;Dae)n^!IQJ1$#&Jp4>C&L=R~q$65EiqR+C?!+-`f-bvZZRvJ2
+z3TC5&W4;pc8cy@I7Wl4w7NSBcC$yJ}@r3+N#P5xKbWBRCA&Rl-PCr9X#;Q|8QACFu
+zkEP;|zfu1~5R9ny)b`+f`d{kWZ=4ymHEZ>&nJu^wb$T6L-)i7^#Mf}dz)(wO%S#E-
+zJ9HGNH=`qB6d-ss0eHjr3Ba2Z*B?w&Q(SprD!#8Yrhb851t_lk<OPGTH-JPx5@h${
+zCnvIh(6~&N|Hu#IuRnGEp(YsD)oYX1e`v}N<m2k`ROLHCeiGXc9fw&XS>9Wx$b0G(
+zd3T>8?>fkn^Rse4bL}TXV9fcVOSA3#lgbseCA%-+d^;0;R*b7PBf5*T_z?Y>1>;9d
+zaWL~RS`<yoY{A#t>NA|L6>1UP>{6f0Y{54p`qs?M_U3<D^rQ)E7#jjo^jk45*o1ks
+z5W+F=0EAHHqvNu@&Ci=7&dt2;XOM<@ptT)LV<~H{J^B6j-+%c^&po|Y!Vx|c-MRBn
+z)^As?gfioH`qoVF_%g@665VO+^fkX_`Obf9*SId{NOfEGXSUQpWh2^Vwp<10@%bk|
+z?jZd&qHVZqQS^;5Q0;KDXw7ufw`M@+E&C%M?n*PnBn`JzFufhT=a`rcU{FJOyqadN
+z9wf{kmz{O_nx(@%vfZt44_Mr4eB7Snzo>b)S(N!yo5JJc3QTY0Fx(UP;N~u?7;h<M
+zndmMb7V|ZKW`>6WcWIlG#W06<hawB1NRLBsqvx#OF@Nw$nHBB`D`8*su&?=`8TpU6
+zb1B@FGT3MxBd_o0VY!=M1ee1#KC|TxA=sI#Pk<mg4BQI0dtXIAJJ=PP2R#rCKp^oA
+zAT}GAcxfF5&T2u~D9Zfx^O>tg0qxKn_*lziUn|@&a|u|PWwu12_F^!u^(GN-&Vnj)
+zHMYlh?Q<BNe9eJdI$@EtX6|8W%^TlAHFY=+o%JiOKZdgtU7th5`l4fenXB)CB67L`
+z?HuHX&PN?0?&9)D2ZXQdjXuX^{nN4jPobIM=R<eFIe*8Yi*VROf7x&!8$IOCY&4z@
+zi6MN7{7tCt6#2^`-!)QL$8Lq%?}uE0wGMF_Z~LM<MG5r=Ln*Tu$|%WstU~xh-rs$X
+z_jhnthxd2K;6X^?)6mM3zH2|hpF-da(pTIvK$OPJBi$jF+P!*56c#_n!Rb(yutwU4
+z{Q|L!tCy**-B<r}`Q;EXMQiHq@pQW`77lLz3fK7HK7s>l^^U^mZoEHTRsxSZQei?V
+zY~E%1nxD4|hrScpi&4|}|6P6fCk&^mPt**Pq1sqGvjyKkSF~pQ5Z{`u+4v9==fDDN
+zsTWY_FYrj_IV&Lpry|khr!b`~r!!mdZDT8+5XH|8{}Z1s4WZiP(<KOb^y<#y=!wT{
+zQF#AR-|xAjw-+GPe4?N@dfb<J$==5bB}E#F%JOBH?P|$h30clfJLt@82}17|@rn}W
+zA}`#S`gRu_Mk0C~Zoz!bAD-}?|5fwOyq$+Ewc<SFG@r<$ig~G6xNCf#@l-Bm^1Uxk
+z`FKBqQ+`2FbpMFlNPC<w3o{>WGa@&9tYt^I52imp-HneCxj0E@w&0_An75JIvLgcb
+z5b`pD;Rciaqmav8lG%biP~6(sy{I(}oEGVRXa!a({a@6)%a(Y!wslD6%LkWyaq{FE
+zpV|DCx!`>uPsirMZ2kSgXXK=`dIF3eF;_v?i8{nM^0jWv#^K;RE*KX*k-2&S4xekE
+z!%?KnbmG1d)xx#q;5<@$6y}<bf3sF<+yfDH1Tx&`3WdAcV0#aBhMvLlMQfJ9bbAOM
+zr%^Y-xi2&e9x(0FyT*rClL@Ueca*c6wsR+e1sEMMopdM<$3EC60yRs{1=5>%oq8+_
+zYJo_lVB8CR&o*F1-k3Onr-Nus(fQvMuDOgN1y%PI`d|^jbC*~h@*MgAxmXTt)c{(p
+z@az|T(-(b47!p&yfu}gQKZNJ0xE8+|jK*hUMbYo!UU_`}r={|GFkwx~1;wpb`7T?1
+zAY9bEuplKeq_8z58`di@WbM^EmY*+qzSiO7f+Z!s)hENLA_eOdcyI<Y(M8!S-sTyr
+zsI^;B^YbM|*M5gLh>>6UqHhRt(QbSU<pjdfXE8;))K>>#Z~LEeKxD-{@2-f1Yy1sO
+zRj>*BPdaQ(A8gzRyQ7Djg7D4vPdV@^j5hK?`hs<VhDeyf|KY6bt8Wk*{|61RRNa5U
+zP$=@#dP3^e^<jU60!{OOYJb3*ImUk#m6hTDOMOz;PwQK3vEE+Xqcqr1U(vKk`s087
+z)b+`DX{x9SMt+i!y1r20nx8z@61BIkqVfM!Usa&GB2pXn!=|XUb^ojLfUmb#dd?sI
+zsRK?QZ=|m&@DrzmB>JiX6;){C|J-6--<)8573`+_6KB78|H=3hJM8|?wqXIiKYE9T
+zdGU8b-riNiyhZh}OKz~r+t7$(#@o>3tqasOG%fO0R|IP#P3Vmnetm<N;=|k6&=mGo
+zLy6vUSj6z=G|Y{JSSwTkGaBZ**M?!<Nd3I}h6VNBd4WX>;Bqlc)su(^HAU(J3mXHK
+z;XqYfDOkr&nKEe#s%;8XHq5OLE(VrtmQ;<~{Z>`^<>hXeH(1x$5DEq7)CRnj6`_E4
+z4*Z;|vZg1zqo<NM@bj!-c$hcP)C5(d90XS_4%W~0$|=hWzp#qHTu8k_<#79B(Ku|I
+ztc?B86u2f52!Zv&Am#__p^{i)?~r#vMaT=k*@CM08WqC_=lxjyp{Dsi${y^W*s<yz
+zF%rK04u-tJ+S<Te*q>P(3XjI%5At|y#pn|8;$GY1lqmUf>WE`Vd%!Qaf3wrEl@;}U
+z!r<~iJw%ifRazX!L`iG}ih6l`R7DzVgOwHG0QVt|94DS)>P;3<U?1+7?UzA=T^*^d
+za!kaj8}+${Cgr0R@07xEMP;QNfe<J`Y^D)o39M_p4b?P~jf=c(4P^}wscJOnVy0Zl
+z0l}0Zrx_YbdgFzS6ox_k^&$?B*vhaWFh{ucc|$N@gVn)6mBD$=`a#L#MF4Rq=|%4-
+zEalQpL>EzLu~AH|g&>g^49ex0geJS|OTIRvc9P{NbQ(cyx|s2`7x^S>d|n+&dqruD
+zp~r8mLz{%#ocUVLt1#=<Re<lI<GpS1hX?L)_~|YA^0z$js1v7t@%Q;|K1fTuxk-<S
+z%WcEs!LOkWk9<$0$CfEm+%0%KshDS_q{2*Pcx;ivMWNBAc{Y4Xu?0mcm};ll_=`4=
+zR3HfUzA-L=l(b114%ivF_+t@ah9Rv1J%EE|d7@2UvSi9DPX+R{5`Xz)$Uj5z2suT3
+z+D4k)0o1lbJA?sk^Uj8JI@0&G`{H)EYPUzZ-I3{dlJb`=AlgzsfpV6Vze2gYl)pyV
+zE9GxcmhUQV_btkK68{e6AyWPx<$@0I0lz#nG2xR5QzS}c!Xpy$HAd}H%vZs@t7J}^
+zxepRGGGUu&ZKF)I7m2V;WSDrZmhYEt*U20JiIp;^vsna*RWi}Vd<V2O%S3ncGf3PZ
+z6FtpFpve~kw>#fl1&IwZ=K_(qQzkAHi7hg5kx0lN=eEl+@yBM{WKOQIZHG+co5!G@
+z=fs<$jds5jebBw#Mr@??(XUV>c@s95`rvMCZ5DLpU4W(8*nyeYp=fs25)cr@t`ukr
+zJn|A~XW8TF`RIidWTjt>k%qrgGepdt**yT{xY)6j2uc-ln)u{xMQsXGTWW287FHmd
+zlhxt2^`KESr^6knoaBuNd!&K)f+!5^Aj@a;$OJ@`Psupv1&~GgjGjm&%QF^Wvoi7H
+z0Q?ih+fbbupZA2;$ueKKb!HqvRq_?x8Al%kIYn}gBOQK7)en^CgGkEK>=poo8Q#pQ
+zm8>$e8eyqEb1w2_uVmJUUJ)uYgD7{A^3}-cZgj>{-b~Yc29hEGGA$9^lt?j!E}4@m
+z;v`EZ(gdwL^eJjhv;PJPx`?jb50bF9K-y_%4Nif1NYtA(6xk#XLpcS?Vu`NE5$)R7
+z@v?G|yVX@JG&)}H@;gpKShlNU3H~*tPw4D88S!!{PpJWUg8^T>z&Hev+?KfzWc){I
+zk9<iv)C-YTnh6=Fp}5D>ads9=q*B*am*Jc$<qGV5s(Vf;;BvO<SUDSHIoousx({Tp
+z<Oe<jxv!L~&xa{GuiKnRwb5}d{?(G4Z93LqxNVc1;Ap^iNe7g4Ivr~k8J*6Uhx5CX
+z&qQYwDDt>&uv|AfowW*ZA2<?iPqWd~?tp+e0|3#-Lpn}3(LB+49cP$VqE?x>LUe1k
+zOk61vePv>%D3S+ys#s4+N56?plY|OY&m58HDRU}?o^di!C5oVdTUk$D$GIlDMG}Il
+zo~u=R<_T6`D0&QviugiLiEdmW)A)Yb({X}1Y09D6vGzvjP{Bp#39eVBmvDNtq;@(R
+zU3LaK%j|(0{F(T1W>XC$-vQ|?nS&QS5^-)iJ7}0*?28`fi2Q7vOcfD5k2R&)2jH_E
+z8Yrt6goVs(xExAtgIvWTi%?-hqhX3{!;5uzx(TmXW1wtL0<bVC9xoK%;3yvNDi&E%
+z@px7&vZcY7;>b68p~{rYF^;V5tVO0p(G)QbNyOGltJ0RG;6Ss!g(Bzr{UL(@VIjyk
+z|Fet}Nj8>DTOkUO<=ceiyJ6~<Hg0n*7g>a|<sw^Jz8x)>;^SzA6rXU#CsFMEOHeJd
+z_PgCAMC!f$SUEA!7^hp`bNNCf{(CO}J;{fTehGB6>jz~;M_c_cOsvniRWdF9^2IQ3
+z@Q5Z4Z%4iX04EgTCy=rI*=U6cKZJvkEajU#=)XQS5EW}YSQP3U42bNw{-WbT0Lw1w
+zuZRm>RCHWd<aXTyWxXI6<^eI0n-2l)T#WkzCI-H==78y1^B*xZsL)Xnjpm13=%`ZY
+zs8Z;^YN0lsvtWWZ@k7+q#^cu1Mrn6j5B4@Ra0LuwVPx9F7TRu=V^I-j4_j!Nuo5!S
+zp~6pTj|d`_dP<hUjXGqhr<77piBeL7l%<9ps)iS(hJ%iV7ZnXJDjHPzFN!@cNo}H=
+zQpHl!!u>VQ#73lkM`AsQ*aXpeso(X+8NO=^e5Bc(pp{+E0YG;25=5<;kd__21T~PT
+zpt7UULw$j7m@_C&F=718BTk075#RW7J|@f=$i;(_%%`O256Ha$!q1^zh<x)(>`pvn
+zawZyxhfL1m<VA>?vxWKV9$eAy8pHH+UcZoGUgaj{LnRgbGMXGLhljXOz<DwVa<Hz&
+zR?2FGh%6(Hf33q`@A8Eh%g2br;}PKZ^ZVx;=54rO!~>EGm86l26F49E7b<v|H=lr#
+zc>^gcU!q_)e0SF0Eb}ab&#7i!e{-@q4EB!T?Cy}=F+)(SqvjMhBO5YC$_&qZEZY|5
+z0(pQA3w-Eu@l8cn5_c(bJ@&BJ+(ncttiW7un}G&6){KV4Lz1dir_}9ovEYkNr7k`Z
+z@P89NU(r1s@U!6Wk-!<|#c}OfV5Idor=+givf>vh{mpVuNGXX{`DDo-w5k%g0m=2)
+z`_Se2u4!ljzLgVA=pSQ(%R%$+A_c1Xh(AX73dK0o`6=l<b+g<$uuR9SAGYIs$$|cN
+z`>P4c!o09D#V`i)o9{6!Cdt@<QT-^C%Da=|Iq&x*4EiMqX<y^#=E08=ID`txyFEw@
+z-2pj6{{kOQ055?GF@QrNu$E$pfq1>=<5`+H%#Ax?EabI^YaSkXyq#NKKSBoKhFoc1
+z<LBnVg9sd4$U-p*!*Jg<jPD$&i0%p?QP2@=n+v&vn}{1f+^djtD{}5;juYJ&u}dLe
+z4o9~;ZUp@25;upqFpj{dh#o%zJqwf|K<Yu#07G0EFECbPm>5R*S8Zs68eSL@r%Bwr
+z*tG%axkOio1mc$_QL}*542Uyi1ynl)I?~mT)!sq;Q;mp+-MXBaLqy_0T;uTZ3lhwY
+zyE{V!oTRM0bXX?fF%-9Y8+tB&;3jUvUscM|MaeMNdCtYc|K_|ASn_s+SdF82BxVif
+z{o@9sVuA1uaWNIZfDwmzr>7;Rf_%y_ehJQykq*ekjNT3CLr{Qn9QOSRdlZt*hs45;
+z%WWmW+}IZWFnBaEa7Bkl0e+Z&a!M37!8hhgTF)O73f3FuBOZLN;8|A?(=x|(Pk65A
+z0`CPAt{aXw1AIVeio@LQxdj+`_fuXT?{%KHf!R*GAA|Ni3}k4xm@M&QvYF>P<~bm|
+zE(s7*5Nr_WNGWh9tCxY|D0~YN-#C1iB;yEgZ1`v*!Q42Z8(2Gqt)0a}h=f5kAf$bb
+zpPL6SB{1gl3^TJh%u;-vfAY(-7~sz3*_nF8Z8RvrcjKSJj<INgGnsOsp=gm4FF4fL
+zm+oZ@bUO~hdFV{22w4N-3&vkvj+$jKpkduG)iB0kGtIAf;fARyXJ&pBOu7IU_g|re
+z$NBhSeiggy`++3umTRtWcu_e15M51BB_3wFIsY{9*H?t+(X(MAFO#|`?+g+gM{_?_
+zK*6!t;bXD0$6`mvI+uw*(z%ZNaq`C@43n<w@sU~Z+C8WdGQf-A%&DH`keKXgd-4*z
+zQX=TG@xuCsWP9W?3zt)qt<WAgO##i9;I+*YQYyes|3((kR~!R`ui)c9z;R-r0@m~W
+zp^wm1r4CRkt8ke(s|4biiZvLNan}4y7KvYiLCb$c%pnVwANWY)Qfz>kYjQ|oa*`8r
+zyWvLIhau+@3gNLyzPNEjY5{(j{l)DdiUs&#UaX}D$Qwu}f1r~dUP#kDmV=%VhdIg&
+z!E4O(=2BkXOco|H+i^7xx0`^Bo!<_Ad*x(cR6H#+gx|HxImJedXR*kU|E&mC-wvFF
+zJ#FuEYe&3S0vto>5{c`f<XC<LIJ2p2NQo+3F3cx<nTFp?ICQL|2kUw$ab3=U!n)9Q
+zsK*$%jJ*p9z{O#1+;}FWZss1ijfBDXlHd$}7$D+k0{$T6r@*+|JO~Szr9&uFKB0xg
+zP%Ix~Y9*8dQ#7~WI0oZl#+ef0*k#!DH12VLO*Zr0VQ&n?M<RSoCc)fz2i$JwJxf`6
+ze<NY=TO>G*f@l!OrNAGAeAy^0pfrkEL$Q2JqlQ4aAKNIWAT}y23&u8VnA<R?2eFs2
+zhPVrh>{EQW!-w0a`1bC+6O@%_rAx-(OcI>tbDv%U{6WZ<&Bp>t^O-di%R8+=!v;gS
+zAKQGVMG5<KfZKGMvwAqoF0}qeT0fZ^=k%mGtA}_pg_&~Q)<Zm<!n9)}dgpa%Be*MO
+zsU1uD=7&f)cDy}AYm;k2()b@DVZdJfV@N;yF{D5J7}A?RL_)*A{~?li_y|vRpu<n?
+z0^g4z)%_3&<Lg#QN)Y_8LU4K+nLB?p^Wz`Q?CMQ6^z_<C|7d3LM>Bu^qnS_sXy%7M
+zn%NOXS>kC&Z~O35F`Yr5d>X^Go?NBW#H>;-q<cYl0@{a%c#U{!4FzZ+a<z$1UGXTw
+z4|AT0-#fu`i6w>bd~%-rk`yuuL~gCKERpFtXPHw7zg#oSdhvZbQVVfS)ZmztconnE
+z9NG(}*;A}yhT|h?KC(zKuQzYOav5ZKp2flmVmnUz9s=7LZB{$OgICL?pvRfOhmz9M
+z&gDklV%|tt0iI1aovoxN;6r*oSP5{)UJLlx2z~_N!?~<8W$+re+;H`l0>4VZ!+h9$
+z32gbFZY$tYD2{DV@RYX|O#G?06)T_`XV&NdZax4tVwC5(3y|&rJFAgwHIWAir!+1A
+zv%#ZKI(A(;0$3AeM#{PkOW=X2vNCnc<3(_Rq=~zksUESm;d>ff!8=y?)QU?Xv5^Ww
+zdmMuv1%<E2)(bZ~5HM-$?p%^~t`F}_R>+&56hz#Te$e<CX@uZ%G~(JZt+$LoFvr1>
+z--B?KkBg2`4j<Yr+V7UbyQV6c&z=z$qFpWvCyE;+OIs?s4vD!L!&|JE6R6c1j`vww
+z!?CJ1=gA0&TV9cgc*m$e>c(=Te`2`>Ke5~$R4&=`KkTfBB_}3!@ZpXVNLQ<Ygsu4M
+zl-9VNg4#R6ER2(p8VZP?@8V8HO@PxEsjrG<oY?{_xKO|Z@v8DA;%my6r~h!jJbhh!
+zdD=%jZF@s511}Y2567$t-$_9bRBkNHr8VJUZB2OCSrd*H%){baTogIof(bbAzW0cu
+zzOXg`Px6j>*2zq|fE;u33lKN|>*32!AzUwxdmLSGG5OL-$xG7-5B{hGE=|j2`YX@N
+zV7|5P-DNWUwcuOp_AQgTzj4aT^ta-BS*%v3zjM;#Z-CHN4|A0D_r5R(pW*>x%#{fq
+z8;ipnWc54$f4ee?CvqNpCCoD^>$WUQgXhH;(B%wO!i*pebDXsrHJ9+EZafRaNPx(c
+z$9#~SYo3@Ir+Dl_(5to*x?3FP1nWuEd#aYI_P}EmS+2y&yx_;#vzqLYU&=x78{_e}
+z7wTcovL=AGvF`&u_6_*R<K1~jB5m;J4u3o@Wz@r*Z4JE;3it?@1*TGJ@Kr3-vao=J
+zm}kp04h-{M&vtCqzuQtBiCJ%X-i={7Gdn&-KLJ_N|L*X|XYN^GCgIL7$1f0^1U_na
+z5|{&?Qu_=6^Bk)VoBKcaS8wZSEcYYgC$_&r39SfOM}No))pA~KnPKa~i%xC5<H}z^
+z*o*}-x=g)D;vH!X;rJ9Y;o<<V@hcM)z7y~}9o!jnPNk@Px6Dsjw`W<hwFj!-@2GLR
+z8P%V3@Obrjmv~-3(WX<W#}&|cK}*;;{2J~WsYP5{6%tg56QFAmS{fy;dfh=Cj}VUE
+zm;I2AmlEi}@8drvTs#}_*tu@a_>EaQbUgH5%DM-ID`S=^xCrXa`8e@8oq#3Ba}Je+
+zFm&><O|xXaN5xU&0xlP$5&gc2bCP!}UeNbQT7ny9H3(7R=SdYhgZR{Ihl^nn2JggG
+zCBD0KbcmI}L^1YPTX@1_qddWd`&GVhueSIJbsxA8UvEtZO5xQkAwL^G%o{BHDT|{X
+zpP9xa95-XmbJ9c{fH5Q^6My*kZ^#utJM3gY(8CwL=b$z2w?4%Pw%vlio|fWoQM?RM
+zJUoBCTneyC{yxQ#JI^vFG2TT8PF7|w(~&*zyK=`b^dcp!A(<-At4i_r6#0PZ7}&L!
+zBX+yS6_+^TY5g5@x>vb6JeJ47JDzk+OFfEKIi*kE;jp?da7%c`xtcnD@5*hnT+7aw
+z<P`0EqYJnF)P*;=^-3=$^F+t@T?L(gW|$q#-Wi?Kt&B4>I+~r@WWlpbPqvYsJ_;aM
+zZjlHVWcaes${3bDJiVy1VWegP1^N+Bm~N9|qJY^ZB<;SyJu4NWK?uNvZ99;c-r2M=
+z($ksOzJsH42#`8ZGPS5PCNsE3_}Qyz7Ij9=Sv^5dE@XC05t`gOJBg}bLDku*BNa<@
+zfhD`qb+D+u8&qJ+Hedy(31%u=)4elTGXkDnpDro^^UuhEN-(?6=|!ErqG@NQIx66o
+zKag;Ia`pfvrw8tLc@7{>wl~KdeY!}dy4re@0%$ROKjJW`z5%CW1J0!y1t*(SibU^p
+z6A9;$m5SazWQ(BnRa=3bT+sd2F+%nEuKgb9_zS2e=t)do=$enoi<Bg+3;R(OM9xWv
+zNb1xE?a4jc%<qhe^7I+PXL+eczR;K-U1b6-A4vUgTxA-b?(4>Ys*4%M(gPr2NY20<
+zQsfv6yN!S*C^8tnN){@I$a>)m6hvU3b&&y#;ffU^5Jse%Wv5{cBT;}`Z`ExvZW-<N
+z3O2le8V=6HWFa-2l4F!4R67<egfFgR`!YuTc(iN^*Z}?!mR*9r$nPwCaj8>KbZ1OK
+zpBo8iNReU})I33LFg#OH6~(A2rgG48qff_pzbwZ<p*}-Kt6^Lo1HeF-6a%E!!_-jX
+zLOl7x8SD^;X_T?(?zFJLVENB5I`FWJb$71d1pkE7V=R!l2|nQ>B@WY=$|4s7U0dM6
+zNaBOZrZJhtyU7OAC}oi?NimL^lQ(nf1-Odg0YnzLPDzy6@t<6iX-r{JEjVSfUSt#j
+zylI7L_}PfwjuCzq`#Vqxi_H$?zmLQ%4phP-w*u7b7R)7J9-U32ghkh=nQT<LqkCq&
+z1v7QsuwE0#1UiFm7G2%b;&o5sYI-=;m9XeGcp8gqTo(JlZSXXz+d1*Cau&KqvG|+=
+z&0?ee;l#`=M*|5r(0Q#>s)WT`39^hvb2BHn^I@b=wsZQ5B>C5q7<eV0Q^o8GfP&P{
+zg>HKt4J2?2@b}huc#L72D@n%p$}#q?rX6{#p52O=Ea85>Nuo#5l}P`O(bb-Gu&vNS
+zw<0NVHS8CU(U_%k_=lUXk~-6f>#4ouu!D}{rm}bjExAo&CX43~ghPF5oCo4{O=ev^
+z99^?nRCP`ML0ujrFOK6Sr8$oBG8RYCQw<o^ERH4!Z7<u*sd+Au#rY02nZ@@V$glgD
+zjVO1Fn95?rfl67tLos6NW==iss4r!aYfS9v_)4d6rNbOuvsmP|qOK_kT0Sej<x}EY
+z9v3>?re8YEEMf61$B0s{oZAW)4sPR<4y%Mk=c%kwsyn)vs+mD&j0l$NT@zSzO_&yM
+z!Zfz#SFQ<cm1{!W{KzKUs+hp?-(3@U8^_aK<!l1)JO~5&X3Aw#0Ai6%NEGxRP(8;S
+z8wPHkNUEmO*<%ch8!TTDKhxn1isKxnyc2YW>6pcISoq*!8q-)jk03dqI2Cq@EJk98
+zoN9K7EVjfDWrgl1TW2{1r?QysK&33QJ#qkXD&!JbWP2o$Q>$Dei>h_;lV4{l(A6mz
+zH)a37H-c+m&qHsq$PJUd#VPhY5Lr~4Sr!)}rPMq>ojt}iMit4d6fylM)HtvV)G0%V
+zatWOiT=cjm{JUQ~64kVp^6qxjl(G1C2b#v>2)IecL%K!E?&srF;1#D}35%VnAk1ej
+zUrI-b{iR!qMYmMk<nkS{T}s@d@fo5VptHv)i0hzuPW**a=a|NHy$uD_yvv<tma&Lm
+z)Zigq#;KcKB8#^;&}0@LiYY7gxSw2Uxl?c|i(HKyrJRboL>9Rw2rw4aO5+D^e5F&k
+z(uI!tX)JQhXvdVzoLb=!r?7ZCL6XQRHU-9;+iWTMsX&9HtAs_a9Ab?XZFE^Iy1L^c
+zvVz!+PN}%+S@G|QB70XiG7&4@r8+A?Yj;pJZ#x#1vB-aWm)L^%f>XI5{<S$CrZJnv
+z3kX78Q#W&JhD&7eiWnlNHo8O>e-%UI)RQie#iwG3oZ`lTjnY{6lUw$8$0d_lJl9b_
+zjYVz?wrsM~vQn4GBDX~nIfcJ{#{;^CMQ)2Ea_Y}6kwtEcBy!4aSzK&!%ebRpY_izf
+zQ9qMKwPjPBmX*0g7P&2G$CS;S+Tapd<hDp6ryg^OEOJ{UkyCEV;%4OdmX&kM`Z(%m
+zv8cAJ+-cc#m&hWw1??zzT6VijWRcq<iJW@eC9=qEkwi|pEsI;-ze7>@r4x-MEcSHN
+zmvW1yxDeZZiwm(`54#Xs@V*PN_>lvZu$V?)g2M#JqU}I&>#TvKfa3&iU|D42Vmp{?
+z2BI7l?kDTwo`G9v7FAv4o8uc4=Tg?CI4izX+}zEjCOK}I#-;YS&|gXXrwh4_kWwCb
+zjNa7*L%)ng{*zAdFN<C1X8`D_vdx^DNhlCmtcoFWYK2SG?GP`g25>LgljttzF3P*t
+z?PV6*IGSg%RTVCzSGJWD>~R&b=qj4ciq3Epm9SXpKyefH^`x`a)y<--dnW7lJBs3h
+z>=&ef|3nW~zAU<mrm><~j-t4Uwu}@7=$vA}pS{E_5p`BOc=Sxi4{{SM%H>PH3}cOB
+zR~d`Ek+2LRu7uC=1*dYs4UVo-7H=a6bxqyODXswmlGXD0W-5SxD~t!2&ZU0mLNd?&
+zWQ9*Ulrl$zZ@%$J+?x1;Q@P;Fj;>M`_Yx#q!>JElB8vxOh@3LXlmyLwiVEy@bd_+a
+zFI`Bs#Qn@7g=ag8%UCQpWwYZ8PUV7q9bKg?p0DVdx|vg4LxR@ypaOjyT_s#<m<ze>
+zkP<5_b0}pjmce(OctBk&PA5qAE2my;?+~TnezN)rj{2!APIJ^xW04iguI7}hK5i86
+zrJ4^q7L>904L#$9?{_vVaSf8v%ntG#qB8_MixrtN3$AcCl9)rP02)Z*dKY?_#6LSw
+z35&-aC~hLVjcP7}@5Jx`C$o5!1Nm93BFHjUn43A#*|F5$hs4niR2px*Ki>GbncyO-
+z=rYHK5*8OaHo)(iIdQGSo6O=`mB$IwF>Er6Y(9ROw}h?T;PP0!k08P0#7>vT;zufv
+z6a2@J@C6==Y1An~A15-Mo|??!c`A<+ZYWG<Z%%ZImPANwbs^ci?q__MP2;w^x~H-3
+z^^T%xACl<CRNQD-MV`Oe>4C--n>n$?>8YtK?sT9M7WX(s!z(s(0^e+c2aFQ-1HO$z
+zLQ`2}^Wp2N6`RW_pFNUj<<gagzy<CgWU<2O-r4cqnawrjIYyMQ!(8vgtw9D;HJ8#k
+z@fBZZo$89Oa}!+gxx3}ND$#{;Gl5P4y9`g<>OyBFxB$FM4dcncV+`G_dk-=8)p~Lt
+zVzM{gPhFQ~*xop00@Sq$&{ZTQR`)fTh~dC;8z;IZvxqMN!UMjOV)1kbnk@6&&nGEZ
+zc+4l9@pV#y2Q4~9Ob~80Qex5vPK5e(ihNxs{1B$2%z?WH7O!@o*(@%ipM^thdzNwH
+zPx8lDw0`2$3xo<PCvJnk%fLfkk~#Gzp@PbZcVeirnDR-sUFz64mBl)$7^0WOuwvoV
+z&79&I5`;N>g>}M=%woM$V=0U52(bUbgkG7vIe}LmT$acylQ$>u%7e=ic_sea)p)a~
+zu-RiBugqeR{eYb@#qmmz{0?`-EV4zC$SF1nh%B;4B~j@uA=Z-TuA?)KE0%XSUY-3f
+z5|1l1mh&k7;4vF}w7X+(+$6e>*vIIcZ8RF4&c#jT#9`V6-MT2rez1K{x6Yd<cb10N
+z&^fMDUZPUR$-f=QoF7+8chOjC^B~fOE@GLx&12*{oyCq%bj6xVt)A`ptb|1+V7Dye
+z{``aE$PyM=Jp}faWxB09NbmEmeipls>k>Q-<*YsqrG&*#9BB5>sQui@2^7h{CV)Rt
+zcLLkbrGD)~y3upV!7J$uS3wrvAP5?}Ev~VgdDtz-qT<YLjx!a{#VdP;Jhqq4a1~1M
+zg^xx`)Wy1@1lQSSQnTKvD?wMrlkAmoS6Q8u;G*=?2AtkUtmVICa)Qo}r<Cei&Y)<*
+zU!CFsPLBV^OeZCBvd&5HYnz`oWk|c+Pu3E2$AOzErFcr*(@1<p79MLIEu}0z>Og)L
+zpLU?hEb_pD^$ZUrcNk8V%H7Y6q~IPpqX${O&ru$??BGhyc7|$c{OB!ptC3QBVt1i4
+z{5VRd7(9!(n&Yku`^m1)9s5djHD6Iy8^^v97TE~PXj-wkE9JYj#i?R`)+vl$PkFbx
+z)#(;-9~>Y`!g$t6iQ-x3B#7t#n~NE1$#5<#aUB{@iHqlcRC+v}q22LwlTJ$1Zk>~0
+z{^B}9Ze8(nhE7UU7jt+8r7Wgccj7hDyHxYnbcW?Pi;KI-kbvosMc!iqb;bXtqcaug
+zMQ1dW<%y26X?mbt1c3b2AU$m+0#~N<;g|2?sHJlwotx;ql+M@ESud}D5rQwW#Dl*D
+z(Z2$bx$b8*T_*VYq+b+Wrj&Ss<SA$i4XAB&*7?liA-<M)Tu$e+o>z$X8l8FI>U@sN
+zVbtZL>C7>t^WTGS?mR{YbdhO(lhFY_P5d1w{4;YSp{CqmePwN=DqyII+=W91`3DW?
+z2RocZ7WSK4AIY5)ge{c>r8YPxcWz~6JY`^FRrP@|?9LPZ0sWyxAtNWp(U22MuV`wl
+z;5`v@DzSy3a1|Jm1Aj7Y7;_ed1EB>KjgW#?!cI@H8`Q;|s0udpXBjgn5nj|72r*s-
+zyJvw6Uw?qwU;~Jt71XncXnk11p@zzNxRDr@g;W4@pyFUXoZ%;P(AX-n47V-=5F)v{
+zDG-o*-1Mug4F-fZ=oq;b78(LkEG-8aY9BEt608mP3)YXq)}jLehXIDw3mJ669$58g
+zEYuyT4}y`hC{+qdDzTLkl;!*cKneImB=L!o^(O4`(#dK&!CElFYHN?UVtvGFzt%o?
+z#poA{3hbVv>~&VV0}sGPG#-1B-PvAXr5}0WlNLKN@4|>xv(^5CRkzjZS8kPiE;3U*
+z){W)}_(P=Q%WdxicEq~U4u3Fw<N&L`-O283`L{M(S@sBPlAU8W-)DDjww^aOSqGPg
+z?T_r=UzKa!WbS#`S~TMIFI%oyZ{N7GW_0D1cAh=4{y&@TE9@Co+wxJ(xmKko8~z6A
+z$Z>mabF<YDwrcm-Gww!R=WViXw`}ihYw?K1x1?CsrX^d!l7FY<SY0<+O?Ic3F1-@a
+zTb9^+0RAFnLdhllt?(wReYw@)K*0qCw@)}eWAPopIJUSvCB?chM-;X@6<rpY(Qo7x
+z{fZ|}&$l0oSSJ^+?Kb4{i=nA6nsyjSPb@!Bl%H#b%Iz5ot>2rT^UOEPg8%xP)zRJx
+z?(Ae$AFv)+UcRn*_(bcVnUni2I3jYu%7C0EFZ_9xRd>MZ{JK@=wK|WmHZI>}y>G6v
+z{;(YWF5Ns}E!ty`v=(iGk372^d{aJo#_*9~-FM5Xq2^Z45xeK^ku#>_|5pqfWu=Gh
+zBIqdVdi-d{k3TrlZ~RvbFSh1kM_`VbR-V?<PYUAG>STMZ*?T@{wtj1tpIbKiid!$R
+zd(K8-1_VHkwJ^sXIq(8|q&<c+t&DPTcKPB%_B?x*JsYB9lGVeW0Owia-|SrLcPozA
+zBcB5EGq;N~if4mpwZ)H1H`zU{#rQE8Kia~_-Ecm<?1<gzDy(pjT|DFGFNhXDDO&uZ
+z=ZMw8)5}arwZ2(?09>%rJhHxQ^y-u}>!B3SX!8Yo?y#DbfbUx}VU!*Hc(dKJ=n1>0
+zXrL#jliew8-xbzr5JC24h@Qed)^6iSi+#N{*K@vUHA2@}H!Lf+dqP)rt+rNL_EzYu
+ztIMs&S9toGR-dr7z&-#Ge88G!ANZhov8OkL-QSIH^8)Ku&nCzyw;HR%R%W?%%?K;g
+z4j;sN?OW3Jq}eb|!R0n=)|BE&`<>NkkI1?|K~}dt(7(T1>=}fO{DWz4ht@ohVta3a
+z5-E2<-sZ*jTEIR?eH{`{FJ1-m3#s<@Z7q=e`C_{hq`ye@<eHFtSmgda)ec_)9(urI
+zmp@*#y7<`pKzU{9s?EcL`yk$5Sq%OF<d3NnW?0`DtBRo^6JW66bkJ^-Rqx3&ts~1J
+z)Gg~DFf>f-_o)*=+aIk1KB(fA1!&-|RC^U9wlBuPzbo|!$nPw+y^z=fmCvwVFv{<>
+z7F7fM(IQlFM;f;B1Cl)hO#2u(xqNfLb75!blX9zlxZ9)lxEIk&HTFaquxo|$ru_|1
+zVhF8mj(A`LClfa0^UJx^UlD0A8vTt8Fk{2!sv+2M&>t2jocj!aQR&>KipCn=P|(P&
+zX{Zb2hQbw<^KvI$URaVle{9M4+_>pF7cK{&rQTm%Q5URTBt)^Fq`zpAKU6V4;1ASS
+zu~OKE4HX#SnqbIZ(+~>#ar;Ssuu+tNt;GPYTU1{G`&u^oVLvx8%P;18&|g_m3){UJ
+zrIW@^^iL_A4hB#1FK7ye1O7R%AtKk{hy4Q$KM>~`)GV@sNi`MqRj_rizp|zR-Y4v@
+zj5NVke6^7}ko|M;V(GuQKVERc4YjaMT?n=oH7ddlL05mc$$-7n`Uk80wQy-MLVjVc
+zFl*e{u_drU8*I6Vdyj>{*G*wEc-&=<29XzTs;p@eZK$hgng{&>+adJ#<BL(CBO2j)
+zj9oLgK2YTaLnZN&qT=y}+-lCKn1iaRXJr+o<0qFCj-5DuszF;M(<RhTJ7B`4P}NxD
+zhwUN3aUr9+vbF&n==WF84TM7yHr$=+{9-@MkO7&E!74-UjtSO^>#ewM8p1^3fzqi{
+z#ur{DO8YCq;3{D+HYVIuU)c!Z;cske2sen9V=rL{!U_8ycIY#32R-3Wzh7L$u_r5V
+zuTK$I!k?jrNK++*5Ud~;H`E6VXb2V-oq;hS_7-e}s>L>ju<=}Fje((7Uxz(V1v^?c
+zH7qj3_JJT))-@W?Pa(0usW*a+LYpir9cY9q)Yx7eXaei~p?uj{viCxw*CO@*A9e2?
+zUsaX0kDrqp!j(W0z=91f5Hx^<1dt-22?V`pfFMP%#gGD#ki--~nkYnxF$#7^6s&`<
+zb#$D;hOy&V#<4OwMaPQRD;DIpp1s#PcW33^alZ4u|NQpnbMM*v+0R~k?X}D4XO&WG
+zjNYh<)M77>9yva$pgx8gbc91kEmmjhLHOT<VQ4%qR2>HyWOSJw#WfWbaIZ;4%4@BK
+z7t_?LF+&IAbzyN`ac(Ku!x+#E!=TGCo-n?bQaei;$TM(pMODfC`eDQ-gU@eRU^>K@
+z&P)_|@Z)1Jueh<gvA(=)7^_!NhQ=-}tDIlS`qM<Ep;%QW8e$lc2j_WqA|E$(R%Bvs
+zZsf@95!pGBVL7=Yb4KQji40lPK>kt3&o8eoud6JjWC_iP@pO1SWaNm*kol1z(}qQc
+zRG8&w2!;&#QLU*Pg3ha+&wXwtc*C;dMRYKZ16}G`V^CVLU{30_$|?e=|H)=`rFLcp
+z(-Te~VG|rqQipIqplyw{wbWVEXSpbiT8igkAbMprjpTq8l+x;kI+7hML0ID|G3cE2
+z7Ap}+H4a(58Iw+&J?TV}S66-}H3gDwY*-K*Zsbw5c0p^`cd-SN*UEN^V<~YaEGAy%
+zJeY)J)6$B{XoH$)L)Bn2!fuZAitFK)i<h)|&yFc_AZb^Xsne!TD5NE~UBjrIcKmq7
+zi)!c$$&BLC`dV6~Q5QAZCQxIL7|!E|PE%-LlWR$gFEdmfo0)Zw#*W9Uy`4B_KVp{<
+znyywuQ_?Pp!Ae$KOdfX|YOUr4$DK$kkx{_R4Rl*cRqcWjRPQ(-rRANbAa*%1H=y;-
+zSZUV}!CFA;7Ky1YU*a{A&bcEgP4eeel~gaJI%%pBKvpKd%Jt-_x2$H7t-iW(5!REk
+zl7<oh^|d9ml-bqEHWK?op4`R_ar=Iz*2`*XOF?ZJNgnw^HVXue%6T*g8f)!9Dz0BZ
+zI}3EOT~JUR&&@@4pK8oz)gC#56zBEHERuGIQ}0bHnmL)iEKvbZwRTmnvkMI$T^I{u
+zLSO)6I@H<*ncc#~!fBJ{Oq%E!611qP3HJJCQAZohzLtzqRkMVqpDD*Xw3rc0cLwXF
+zX_(#DmY0&lRNLF-C1mWy4J9;HWko7B>%J#WRG}Z{Mzxu-W=Dq6g}pD?5W6XRDoRTo
+zO`--_#e=;Inn$hR{VW{I(tgc!w)w+|7(R^b=*&qwXsJ@OhpQnI)5>nxw1Ab>HyB^u
+zB-8P|Yfg<ZO6*c=8{2*~HqeSh-Bl47-yRU5S==q~jwiD1(qVR~SQqK*G4y9vqG6ud
+z_fu;ZQMZvnC<oTSbRt{e@PNhydJ5y5j#TKYq7x?`70H@4ud%wJ(XQ=7MmCyM?yB68
+z**PP!M+{VJKF+8;xj5u6JJIu(X7~qp?HpcDr{qz}JH#;9KhuP?j7yRxr1iQuG$Ae0
+znmi#b>!MEiX*uVo<fn~Z)A_ixGeXz;UD8Gql%JMG6rxg*32EWuQ%94W1uSbCwv=%(
+zWVMDSrA01ErUK`8DoD#&ld?E1tH3ErROoRt%1|)x2gmfFvaAP{WjzYhijsE6RbxV`
+zH;!a{VI+Cp<=Ez@Wt^XspVn(lXi8e7tV>!i0`k+sC!{9jQDUM=6r>iU^*Yu>bErrT
+z*#_Yb{E;pfq5S!wiD{8F$wg^-N#}M+ix5JBsOghZjk_yxdr*fmlY%n&C{t%^C31dh
+zEoH;@2&POzJ0;ERl9ol~10x@oI<EslqT5-sAa#a9CZ>9GsIFwbz+%3YAFGo(k^6=^
+zbxlekweFcNrhDC*C#5D$?1<*$xx!xbJA-AzcCh!Fq?5X!tr1GD;5>8l#pIoC@+`xa
+z-<+U)7L|XP^UU|MsXX`Pw6sVlL}QVA^Z3+4;>w%dgYm9tYz)O8%U>jiu1|_PicGs8
+zZ!|xHY~Fp1$%{88XQaKI6goB(S00TJ&&#9VI+nMQ;@;Fm^CRi(C#c__rjCD}rq>HJ
+z$X-kfqeQ}h;gsxsxi=mmgbR3aLMZltb-UaUt{TP(AzV0&6G9%pjG^*ExQM6%9!*Vh
+z^pTHk&?im|E-&kw^@A{bHQ)ClY&ZFKzy#*Y+qY((6E=nM^{lFyzl7nw4C>8eRm~hF
+zte$?pV}~!CCep1M%Iz3J)+ca>jF9!B8VB#%0Rs^7_&F<;8<M9dJK%ixz5~v8`#Ru!
+zDZT^FcTXJrLK9EaUfFxZ3S2_bj94;=U7Y~GDFOaJ3GiH+^YP?wO~8LN0seFX{DlPg
+zKN8^YC%`{Rfd7;L??h8EUc2^BfWw=0Jbu3f_}>%Y!wK&}BVFDMlYLcw0{(H#m$!4o
+zzsl?c{1WEN%M&@&euPDg%WDX71O9Br<vD%fH!&{HvWt&|4UEe}=w^K<`I`xkXP;XV
+z;P|>xJpS(!;14ChA4`BglK{t8Y2wxUw*>gR3Ghz{M?cD=a`H`vpAztKQzc%#-4oz_
+z65xjuj(X(=ui1a0gYD5con1PolQ;!8N7VLcIJ=Tg#<Fu<23-`j=#lRAB03Oncd+b;
+zq+@$qK+b3RB3ylNoh`d?;ustxH`JL6BZ$}&P@D?WnR@%nBUBa6g$=1nPJ2<h-Bk<}
+zrISBCU!yYa8C2|C0vY8E&Iz8qO6Qrg$_|&*h)ri8a&}`cDH7(M)=*Nem~jr8BPTy}
+z#m<}tqlCHe>YgnT-#yDVCn2O9t|7`PF;Q>^ZO<v~8A$sJE>sszL--0MrR>END(9Xj
+zQIZ79buwaAo2z=zG<K?J<D$7-h^9}|VeC+#Vdaq%9q;G8HWUG*fa3)0s*#6)<5vXm
+zalRt_1pp}kKa_rguLVd!<1%h_y-!(sP;Vbjzp3yeIlW8agE;+#!t*%&EpJh8Z~BRz
+zSoaaMKEoUwx(I)~gX5S<@WqV7Za9R=p&!C(haaJ|@LzQBz7GD5BM0`Ec734mY|2B}
+z<;Zc{bub!40h@mGlX}N8F8vD*!X$?up|tSlIJj$vGZNqzJMx`FIqzzR@5;Z;;q##(
+z)lT1?Pr!f3!Cig+<lz0Oyy*X<gJ(MUEIyt^wmbe8I`{yGzk+eGo6L)g6&|HB2$wl>
+z-1&05;!8h1r*M(~QUW<YD!$0spHCgoF4sQu8JF?78A?*9clZ%Xi`|wxxGQH(0{jXk
+ze<_4hxJlu%j@;?Ui4aff-RAJ!@c_5w2xwP?e!_pr!CgK7>EQhxzMMiq&S4Io&Vv>B
+z;SN5+!LuCvj}AW2!9R6y%w5s*8wVfk;J-LH&b5R;ni~&&T>WP`_yC7r<=}lCyoqt?
+zcd`E^4nN}XuXFeurCiVZZ36xTKE;Hd?mQ}CT<YCzq|ouG!;cUq?X7cgjAg-JaOAl9
+zyy5U&IiD&1RFZ|TI|08dpK^(wJ1pJXpK-J+LO;=Gl7qYUpX<ossc9rFba3b|`>&M>
+z$Jj-<B7yuH6W|B)ySt))g!cyn7}xrXPiElQM@hSma`^5%nwkJFcj`sE&ZHkgjl+*n
+zTI4TraJSy;966W@b6Ef1I(%2o9S-h}lh>7;bu8y?hwsYyMDe#We|G}@9tU^p9RkBs
+z5c_|`az-((?LW@JT{*`(a$rvx4<|bO;e?AlOB7$mRb>MHQpIm0SqQ5gelDd&KAbTk
+zU;}+VK!U=R3HUcFemAzm9S)x^p9k_EQ2axf|5yUPxLZUv^cl?j*AwvHRr1F&e^&y&
+zI5rgdIR7>Q7Y-?)A6@&TF)sW{=I`(D-S+lZ{3XmE?C@RrV-)`y=9>$narCKB{B=;8
+zLaie|LTTyW^A-PQkSVNBz`xbuW1jYcK`7jlfd91O=Q01K1pE&ae*yEqNWf3wOM0+B
+z^jXLJ491a+&`;WXnBs3?eog}Z1c#6D_9gug3KQ^8SN!dk?kz~bU#9qSeP?X~{*{V<
+z4v&Y;3HbLa{te83I064>2Omkgi`|lgmssh8;to!qr8fa)9PQxU9ej*~AMW7pese72
+z=tp<IImN+Y|G%>SCpvPDa^$ad@Uaeld>SPvK+kdXlXk6g@bM0Q0Ke)AJ|49dejf*S
+z_g@7L?((NQ_y|YNHV1c)mtJFB))OjX!aEK>LWt<|rNhVgkFxRhB;Y4y7;(l9?tUka
+zahXTEd0rGce7D{+96tKxE$)}91pL(wA9~7tgo_gJuXOm3kL!O3n-lQ2ICu{6#6G`w
+z@WBrLkb@uN;M*A&JIH;IR~>%D;s4FSa~ynE0{nXicaP@_x>I2aFnd1zME}{0%XpCE
+zfm0m5dpxkx!QJtEor6zs<Ug(C%kjf=4&Rmkse`-nyY(QU6rjH=e<b6ge;Y^?#yb35
+zN=tk56kq0h)Zx4HeS?F$^ZhO*=La4?e{lHj`S`02?zZbo2cPKZxhH}AE_@3Jc5vlS
+zad20Dxq}xt@|QUHp$`6>gCFMLZ#j6DgCE1UjG&LZE^Tn|!yW!t4({sNWj`WOfE-uP
+zfe!A<AIrGz_p=?o+wW@~KGuiLypFAR_z}WooNRLVSRdNxhwwiR-<5x_gS+d%0}k%4
+z15Y~gp-(OA^OD1l5H9+>>EQ0XK7w!Y!ETtl!aphjJ}m)0KLL)mBf!o)HBFj#;|533
+z^Y}W5aKHzC5es1T13u;$0<LW$VEUj95(aVva-=LEtbqt3Up~T*V+I7l|HS7}7&8ch
+zKL}$}m}EBrF5jmvRJiOHW+?pce4bpQ@H$=xDiq$p*9Fc}_+XZ^O5qVsw<^4xjdZEP
+z#g3a4KAP*jRpDLP4u4d5F5}x2eh=&Ul)_V4{__fdjP3u5!e{X~aj&;yoLtLt-ckH}
+z*`6OMT*k-e3SY=_zE${4Zr4u=U%>Ou=XzwET*z{IDqOxx*<0bbABZqW;d6NWk5u?)
+z+>a9!UdVQvs_=nqx04kvcC1kNE|w$XQQCDH+hLXB-^uue3a{pVzf$35!cu#0Qux<w
+zw|f-6%vi_s9#MEP+y74r@5Sji6uzF@^`63ev3<T&_yWd%QFtFt%laYq`JUS==beIw
+z7#D{xg3CA)pDTj@iQ9Dy_p{)8+0KOuPvLPgSK-|luTc2DjMpptV8&M~Tt4qC9$7@6
+ziEN*16<_Y7+^F#D*=~0!d;r_$L525YeV$f$CflbIZ$+PZJbp41-oX8Su)<Gbxq}sc
+zCgZsZ|CaR`rSQM-_#ChB^SHee75+ZslNG*z@o5T|ua3(7AZhQpY`4=De=O@+p>X*O
+z>sbo_3)^j_!bR_9g<r<}TNQo<r+=sLBU#T!6uyA_MaH|dYce7f#9xHqH*vpwspM2x
+zy0=H+&oX}>9;YHl_M`hLd<vHzt?*XH3l#np<3$QTkn25F;jeRA))mnw!gzz?|BL0E
+zt8kg0;)X-yl<@cwUmSwJ%j02-lCzxo_bYro*Za1@|H}9$3V(;w;&4Oiy^;GjgV!y=
+zU*dYR6n-&}6S<!ye7UcXr}!T-zfj@bxZdRopTg<Y3SY<R7KIPvadoxA@8o{JS>exc
+z`W}T}$#Nc6_$;==c7^Zc^s5RVE&ZbKmE7Ll3O|a|$=v^9&-a+$UEz2x4B=3POTP?M
+zxEv21sqpSR9!^$x7N^S<zL?upr*NrP{1S-%)0r>l2ZD<}*C;thgFxX<h2PKX*n<j}
+z@6<n|aM9;gg^ND;Y5{`iBlXIDL+~9uev-I;!R3?r=?c$fxrZoR<WE<48u#N0g-_=B
+za)H8Se|Cey#XG|t3Ku&+rtsO^F8P{;wCgt3M?Q%z_+)O^k4nzn+`pYzU*V79ah0L)
+zag57xgzyWv-jRwg_ai4N{ASi?hQdXk(-kiIR4QEbaqpkvJY^xz$7aR<gxi0O!c%yj
+z-mGw+<=n0C(P%h@hZO!E_sb52zs&f13jdVt@P)#E%jrD|x3!YrSJqeTFLvvtaIsr|
+zg^S%rDO~I}LE#T@#Zwf{mzTXc3SY*0%W;S3DdV<Y@nzh~2jPW3gYA5w;){Lcv){rO
+z`8O%P$iG|RBL6{!i~Ls<F83MVRd_1Ti_aDQ6VETRP>~Hq&!IdXx^nvjf0M^&FNMo}
+z^h|}zx-&uHIjo1=FBbVS&QDYP6dvab6fWa@mBJ_UeE*HYWgWX!;WFOtQ+Nx@`Ln`B
+z&RYr>IUgx}Cy&o$=e{A<0g;oTaFOHQhXr5umwAdWz8?w|F5_gb!e#%uSmBqjozGMF
+zHH=@ZaFKtl!eu|bRpBE4Nrj7ix!(%&p}jY8y?;}DsduNs<qPfUd|^@Ke8%&Au)^g&
+z>{x}%I6PM4tj~0X%Q&2;@LJ|qF^=IRQ;wqE8pW4&vem))5<ckOr4A1J$ojd_!NEU+
+zeh4=>IQTNIZg+6-uLhaIR)x!R5sx@H<lM*mg=ZWba*pNs^1OqCFYEB@4i5fy=D+3O
+z;LCdczJr6G$;SKG!NHgH+;{H7g8u;X>BCVbU_1a%;`QxNh0A$gKgOlMp0ve1`K+{z
+zD_PGcIC7wmtmlOej(V@;dgZ>b$p0(LpYQM?N95NjT;#8CaLE6T<)6p6$j5sm2sbGH
+z1l}*)qwsRZA5?PWeX7?KznS@OD*nq{?+*&kwd#01_`bI2c`D;W92`UKV8)MjaCB`I
+z<EJWo9plRszM1h06#fI_8yy_=<}rSo!Ur*apMyi6gSfrVDO|4GzN_%H%-`eSSTf}P
+z#GyQK#6F)hf0%<q&urEw=48M=cO-gFcKFZ}?`<GdD10*Gs~w!Dy5Y+=%SE44nSZ0h
+z2UN!Rg9_is_^S@iOQezinS+D+N9Kq5el+TJ_37c@pgzj{K?;}m1}7+7?wg;+xU3I%
+z@OZ9JxLns*uJ8hGggieW_W6SKxmMNt3*&NsU-<I8!Rt!CxQhIz!sYqhj}$(SjkHJM
+zA2OcO-I&`P?_u4T&Bt}=3jZtPhcYgD%JsOhihmmKXY&<b?u!*GzC1r#uK3~-SDq7)
+zdTV%nyIk?bf9>54j;6}G@u-8t^y1w1uMY0=cRD!u2l06DVJr%w&l1LaDf}G9V_)#L
+z`~3?Tm*)gT&hHqX=g7g3nqzA7yrm8feV%9jr4G(rYf5Z%aMNDq|6bwZp!sQq%X_l#
+zFfQ{#u0MaQ@RRs>K8f$|OS^jVyy(ri$oZD}nGVjk^o{<x4vwnieB&sEFM~h|$2hnv
+zC+gsk^Ec+pmxV>2efc=@WW^uFcq!x3E^*;{j^dxp{3gX0udvrDJelotpTfm%+a38h
+z9@vNVe?{@vvz(6=U(Vycb#T~W73=w<gF}8c%kRWS6#M*%`SJl^!96|>JILWfj@(xm
+z;NYltB=g5JF7_0Ew8aX4h1<1U$(hS?)+&4@<E;vp<KWAbd~uB{UkMg{zT|q}P<*+r
+zDqlAheiBc<pA~-`<FStd+jSt1ad|F9?D-_?Ka3w%5PS?DKe^AVz@B$8UZnUV`FLV3
+z<DzE?*V~}@moi_TdlA04TD@Ay5#Ol4Q*!QSIS(rQEykZvxX=6h7ZS*SSK;E<^#=#%
+zCXqGh*;))f3Znm9&OAinmoYxf!O`Wi-pU7qVSiAT@_uKQ!^gVX#&Q}Nm;TD+cFCuU
+zMb13lKdx2$)0p4v;E4Xf>*Qq)j(#7-`}M0G9MPAd6onfd9Q^LQKl`nNBP!>QzjJW#
+zcQOAD4vwgtKejnI_~HuTS;ocw^0ni?IDAZzJo+KL<KU39n%AR`75+TqUn{&9&$piy
+zK2_%70j8Q@JjnIvK?(3Yg^MG~*$(cGw|Nc@(;v&nOG^|k&wJdW@ZQYdq42X9|H{EJ
+zK6l&Zct1Nh>RrtIeR^4f*nb1#!xern;}r`3neo*Qj`mLFde=KR>OF|Z^Q{gJJ$Eqw
+z5yoZw&*kyF-Qh!yd^cdH!^e1#FT{VZ@IE~Me|B&Tfg@P|&IeirWIj%0epd$ve?04d
+zfP<sni<p0igM;6T*MY+w9Q==%e}sdBe-Q6SMmae6xyYoD$GG&@EY{~##g}!YT;ZEp
+zPPM|HXS_klm-{}g3SYwYZgFt*`;kUVTIU=b{dE!Z-*Ry9<+<Ol9UOeQpOJcy6)5e!
+zmF4tT_&^>f;~gBPjG!Qe;~X6FbD3YP@S_=DqVN+LzeM43-TyWRN4w5Mr4;USaMZh;
+z<vg!&`L4x>jLSIuocrYqg=g`6{z2gvF#d~@FD^hc`2<JoDfm$ezn%4*>EN)ZyuViF
+z;Aoe8f1_UE;*InMg$w^-#-+WFu>Mae{5!^9RQM{M&#x%?;`{T51b8|gVx}N=_?g=~
+z(81AOd2eovgQLAZ6s8bWxVRy0RJhzXZ*g$Qm-qNKJ2>RacS{~(T<r6EZts%{|CI3;
+z6kf>l>SZNgyov5kfT!W%YzktZvE1G)2Z#RhKHz8vhyHoYKThGj89$40Br(ME*#0XN
+zU*ufp@Ub4A$L+e&!68Skhu`Vo;J?HCdzJjztj`M$?ygI3I5^t1i1}YRxV!HC?BL+9
+zW&Q!ZDM11D1iy`b2z?zKe7XNL&cVU|0AvcsIym_Eu>2AS2VbtkFLZG5pJM*`4i3J&
+zpSa$^!GDwaw>voaa^LWN2M7Oi=D+0N;EzSaDZJ_6;LH83Zyg+bc|UQlgM)t%pI08l
+zI}WjDCCkrraPWsR{}=~{e0e`{vV((fKBPw5G6x4=-cPJ{aPS*g{yGN-e;xf0u6A(n
+zFK7O}4i5g!AX9kU!NLDM^Z(}Hn0NA==qC;i{;SMSiBN(9%mRKMGAZmIF`Hmsf5ZG7
+z2M1r?Pt0?0h}f6UH&1qO@a4YPnGO#A2s!U|aPZ~*#LFEV{37Px<>0W-m-Iu}7BQPZ
+zf4NV#!@<GdZfV{}4i5S2SbkDpOMrdAm-iEUI5_w>Gyez&2VdS#9OvNRw=w@j2M1r?
+zPb_5|(**0)zI^;y?eHN-zC+cd__DsOcW|t4dAz^B!oeZGkgwxyc5v{QGXE9_2mgFN
+zUft&4;Qz?{CmbAnIlp_+!NK3a``uR@9DF%{{D*^s{}u0tK2!KqUQhQZd=KL({irYn
+zpMJ2L+;8j0IP47hRlJT2R`{iik5KqF#*b!P<S*sxCnqcZJIpUtcrwq=DuoYX{46D3
+ze9K;@aB;f2#gPMh9?0wMeGZQHPGR|59UOew|32a1;9tZ1?G6rpf0n<4aj}Ew^HTym
+zqdyg<Aol-=<sZVh$hn`dV~ke(NfA@r%U8IpFUKpqmH9IielO#57?*nGe$u%K@T(Lq
+zE@JO=aLj874>))dfsb>$UR1cp<L7;ahZ+A$;TeqYRk-+D?wV;ekai7b{s4u~W_*H!
+zLw|V>vCzSxzxWPcs_?0NU9L&t;;#BSg{QI|-cb0#jDN21{)~4X(7s(!#``FI7URb#
+z{2Io~74GwOuyY)|6ICVe7dJaN?2y9zD;0hq<1Z<^i1Cjdyc5aU4Pg|*huN+4S1t4V
+zIXL>|Ef6T=IXFbDXa30!4*7B)aH)fXe>3whb?_9z<^8ga4i5eu%>TW@w=({i!XIV)
+zMTPHR{38d4o^t>6M+Zl}Z!^Eg;gp~t_W7LgK??tg@zIQ9oxyr_2MSY|tZ;b_ZI;62
+zIkXam%X4T=3cr)jQ`R#sddf?RzjOFlS6_=j8_)ZLgG0~Rd>!L42M7P6zF>Ra(+&>4
+z+?V-_gM+_|`L8=T_#d+TcN`r28~f28h0hh9$Lq^ph5wH6<SbiG>@44jOLuU{FXj2X
+zuY*G$c`mb$gM)uJ^M@!ro#)S3g->EU&%q&Ij$4Wpo)V%=3TG(%(G-i<D*Wco7GLh*
+z(DP!hceR6~Ub%kQ;^5#v$^7*W4!&GJyw<_N|C#wWGcMz*0+|%<aQL`Xy&52ehaDW$
+z$vm%~Qg}7vFDhKtg&mAbz2YtK8^yn$<?K=Tn~bLnG-?I={k@E*GA{DP-|jGli|5*@
+zN=`o>mnSKF0pn*VyoK>{C10H8Ua0Vc_<q5yO3qy@=Wd0+!uVE&f6w^iO1|7b{)gfp
+z#CH5p;WA#oQ1}|=f2-t+Q`~(AS^JBf#hc?HjAQ;{{M=({-be?>__>wkk9BaDU*O>2
+z@5g#fV_fPLuaGA>e8_p5ehBj&9C8X-PL+eZ{6+@{|2*ceQn>Wr1qy$b`Rf(_3FFr=
+zF8YgC+WQrM6sI3meDP5Gmg1kn>30<W&ph6KP`LQs?LHV*itPvGK6-D3OTB{?em#sw
+z;b?`6_swG&??N0<Gth7fvmG3E7W)<}{3h0Wfx@3*ypD0Pr+BixSn)q*{#6Rk;q+#O
+z&*1beycPL!zx+vsi}%py9XV)k9=G>z4vzLN=Jfjtzn0UVDg04R@8+%OBi>2(J%WT%
+zfSn=#U(7pH;hi~sn8F8h`Uu{N{3zdVEl{{TFIDW|DO4|?etDG+j^nO#S<bl%zk%@^
+z6#i$%w>dcE%YC2i4i5QWGXHIbcZV?$hS-g?>lnrlb#TaUvo!B;2Z#JZ=8to5@a4Sb
+zSO*9HLFSh@IQa4%l{yCpU-m~ADm;zn?=24Q%K3wXLyoNfFDiUF%lSm%**t%{W>aAb
+zVxNhOAExjo#*bCF%)8SSF7slk!dLQr$txTj?P`M(6gD|H+I2beA8_zagm32Ku4f$_
+z{JWU{frGp9zi@Ey|G@k`3V($0E<=e#LG1G?<CzW)edIeQBODy^|H1qTjANeSIPC)Z
+zAxu_$`9ArX4j)6RjK}wR3crW(3mhEs<$3tal>8iIQrN8UqZz+b;WHS2O5qC`f0uD-
+z*EcW}h0h&6ca_0+EB-*v4CR<?vyMUZ-}kZUG=<A^%RLg{2P(Wc*~&RI0X{(CUT4c6
+zm;ldJ_*LBABNe^_gMz|Xg$qAV;qrcUK?1x`;SaNYiW1;+6n+IJ0fkc&;AINm%KQZi
+zZ!=QJDYL?bU$1a^ZgWWje1*af<?*mu;ceV6=PO+JEeh`)wu)Yo0KZD%-I#xE0{kY0
+zU&j33Ccy7jxV(3FUjqC=h4<tB-If4<O5yjgeV$E#zohW3Sez)lngD-G;S({zDf}}5
+z{-MI<`zE^*;9o1e8~6M73GlrNm-nhdxmGV(e+F^8_EEU-(-fY}?dp*LKTzSvv;0F7
+z-~$wXo~$Pc@LYwT!u%r>;Nulu#N#kO0X|vb$MCu|B>_HD;qu(eoCNq83h&SMA@7kU
+zNWTcaP~qpWJ~avOB?{lf<7BzQpJF?lt8n3;uW-4ac%j1kus-V*F8nJL{xIuvO#=J|
+zg+IsZ>MaTI`*^>K-3p5~cD#k}|7e`Wnf+#lHM#khIQZNp20xe+8jqM<%XRrx3YY7v
+zTNEzWhrdy{tp6iWAqB|BPo58#@5%_C#|^q%@!J>=vvR_h=k(<L9>L{#r`3ut&jsDA
+zaCsi4P2qXGK768Zxqmv2I|<o_(w!m{E>gH0*Lm6XXD=crle8uOE@rzxVs+(JCD{$|
+zotSMreP++AulKU+YLEauH+yvZWUgoE*^Sjzl?%(si?)zU>l;9Yyt49njq}OlN<|Gx
+zHSv;p^XkeMx66i?T9;lz&PV5yA6PCSDMz63^vl_#nwMQ#vuF{V6lYhH)7@<H-b+q*
+z$rlZaEnh$$yy129e;Xns07FB@y~xYs$O@i6g3CORG;SN?kT6dG-e%llBW--Vj>maW
+z4=*dmM<5u7G49Sy;B8#*7rcG|Lx`CF*dGqpAyb#Xhwo3vm^Q}KAb_!K02>w{HX`L;
+zQ-Vc*k&{RCc;%ZSR?Z$F+N9wkD)2OpYx|$qj|-@cloR-LF3+dQ0(<MYyyz<#l9p{P
+zmzR9muIKW1@VY9vu74qA#Owc;9<(K{F0@<pKMuj9UVi+|TS1tXi4x;x;-8)?;`0rg
+z>d3u>GUAnAGsl+rkk985mA{ZO;_1Jjvz3~|1)+ae`f2?)5f-ohGn;HdDQ{C9xxb-|
+zc=cZ$r~WkJ>iX{@EMEP;;reS;rb>E`B`DwJ0?MH9z8aXi{KLeFr~h`=U-}vL!&0vG
+ze}OQ_)OPy3l|Tw}cz<D2v9^jHJ18Sw`Qxs(C61JWyp?jYeTT~{nzw?>Yh20+{vDT3
+z5`ed>x%~D7>xa<4q)0sbz0LNM{W<K1B~jZCHdR#+Lifk_VNI37Drsz|bvNZV8Zq8_
+z?teT^gtcDRk2xK${v9{k@*|aST|ay?XV(mkNXU^0ZEf8Cj~p?=<P0A+W~4>V=yJ}a
+z!ef*Cm_(nxEF4SO`thH)%!!+5o_COUfHy1J{C@sP`Lpw9<<FcEJ@=FCq-(VKk;tCC
+zd!x<w=a|j++fbk^+LAmViz3nHN!xSVJ^~hPYKt~EjV4z5+Goiug{^nC{jzuOGfi0p
+zfiNleyNdKa1;lK*0<>*VuCV!YDV@Id3o>r{ADU1sf6deWxc=$q<N4xk{i(D=YzRF~
+zFFr%$12A`C^Jib*n!Xla=CmMokqqK>Y73G^0;badvmhoDGj~z1SrE$_gZOHQ1<~ym
+zY#L9V*a};l+NcT9)>e;{jkaEqN2%O4V;s?R&F)Zo)9rM=McH7rbcwEcJh}DUy}$hO
+z%lCijyM4fF3Jp7(AA4+P#%-%tQ_~9`i?$x06iqMqOY>tM#hZ-qHE)KZ10RpB`7x4y
+z0Y1-V?Ulam3Zp@b_gz7eA5LGJZ)$o3VD5JhqGg8oC{~im%}<Jzqs>pGuRWV=6>YsA
+z;veiw`O)TQY<^2?gvu8*mu5y=@^hlibLlrRYv=JqtXLm?(9g6ZKAL{h<LT#(AarLj
+z{iXLI?IH2H)s%{^`6OJ}dP^Rnt*xs`USKU_rWwXcxouOL-yu^y-Gnk$SF+gL)6*|L
+zgp5r#L&^WbW+)bQZMK5OLjs#!N?Fm?jy5x`X>Q6OQ4f$=spmhy5Zk6k6Tl{1nO*&e
+zX~Z*4hfoQ!t(V?(8@Qt>>KeZ3QW|=u`R2WSnK><wU_Kb)R=D}wIh+a?wzjqrO13jC
+z`u8I(Ilbw768(QT(jKtl{;xXWd$Ll3PUvQ8>evZIWIR1^+svSfGjLm%_oV?1ZOwqT
+zRRyEDfJSo`jb{2yjP6|Vle;YKTtrD8sEH<WQhL*awwtMfp%~}1Z73;hc?7HCHe7Qq
+zY_=Up%OEM;Fo|YC5iL_RiEa0tnwgG?@gPP=(Uj&N^0!jNi>`V1iwE*3vJHRH=6~{#
+z$bULHbLgCtqb<Dp{=+n=sV%+v(H~>;O^=&s%arY9(cxXq(wyGZKq^OD%XgfTe`@||
+z`KRX>pZ0_up;VO&+4Qw1Q469iO%d7@G~a)ON#*5CZhmIHxkpAiS!3FEb*45=Uh|}H
+zrbV>*A7*v@`qpUc#LnqgJ(hmy<D>sV>(`DcO?w-1rZoSut8026Z%WJJtSL?3HS{5V
+zVe|Lgl*W&yG`*L;_A1h)u=(9xmsYGVXff3nwlvv&&6{SX6f}SNC^f`m%j`^{31Zh|
+zXJ+DYehb<?f|;%j0hnqkF(5v$Y?*d9Vdn6c1X|Oerk!uoC?mbi^qtcDJ?kZAFe~UN
+z`e3{};A91DF-rignfWcpWj^+HMygpvnkUkFYL-?Sh!Gly^qZKo^XuI(eQfgQw(T54
+zRZnhR*|q&hG*z$J?WZ@LLYi`KMO)_NM4R4f?7pjB_N%945ztUZishjnx$BzR8sBS~
+znAvRh#5-3}rM9iK$ap)y0nwQ`QmDnS-4+B*+nIwspzS5<9ahzJ*3Rjqzm-n2+S_@h
+z8BVR}&w}Q!?8@hKrrUVC@{Q?OVAl&)Ao^?Pq&WF^l5O1@c5T!^ivo5op%!SYG!8b6
+zFk}3d(YE_ruCQbCG1HdZHZwF$mev1k8W$!><0sm3T!fZ`h6BddW;S--weOhP%!Y2!
+zmOSdUw#Ki%ej>N+>nFZ`q9QxJ&su7l=gpdd6(ZVFOr_px$c;9CyQ^DzpFEOt3OX9|
+z=QHUZlJHS<&6DA1^Nv$adxHC)(z$Jv<o$6V&y0$8@}gEAR?X(mjJ_oB!<ayOoR&zQ
+z(Wad|Q^WtOeq<k*qJw=%SX}$$&!iT$6q~vR<~M&6ZGO$_+0HB}1!GDJ8hVn^(8$Jr
+zos!#jTK=hI6Ix!$Rwf$QyLpc_`8j0ry$uJ*JSxtyz1{Q{*}L)cXv<2f)Xk6Td}@fB
+zpVdD9nMo0JaP*l;S-dspcd$2gSDlwXbLNSYC(N2T$r~_oc)k9?3v*@le2?53m(MS+
+z^Q;eO+AJPPj*^jHJhHZ~yrOccN0;)-y~X9#Wi@r<z1jJNvpP!jGAB=+SU9U7mg5bm
+zA3C7kn>4jx$ZYzXcA__7(s7fgN&@P5oZ+elr^UvVGR|2lYpP4?&ORzqTGLonR(*Iw
+zq^7pKIugr?45&YferSE%a+TGKOR6f%A|(yf)_IK$<&m1|2rdFf29!l=D%wjjQvSW1
+zYPuL0At%lA8y5Vkq<HNReMqauU(@B^m2Wt^_ScHXwMR`OnXn?VsC-dP-P!*^d##>y
+zfwb=I|5bZq_Wuu!_bdHbSzTJySXLhSPc-{?cARa-^pMFk82+nq(OA8(x@JjrBqnD-
+z{jZ6Nr%!u1G@}2lkX`h24EBR`)<pYld&LafAS}g^35O&<j98NWG;&fh4sX1qu-*7L
+z0i`_b1ieslC%8CI3Y(OvpwpVuDZ@tBBFY6jg;T<~rk7*|7(&X92{8f->6|>4u(YAL
+z%wp8=tTrTvaFT2{VY|t&n~2@y*^Rv=;^P3!OEUk-=0EJEgz-9O7wBOW=$vyXrA^a!
+zguna^9f#nY+Y5hn5;ive{aPS4z8moj8~*|EUN-(C;t?DF3Gpl&{~7Td8{dQYXdC|p
+z@w{&IM{V?xh}wj25=AzVWD;|1BH70mM$WK_6n_UL7T84Chqkpg(bXgxY$DAsryTpH
+zRk(*gf)cB3PEUU_CG58f!~6RGAZcrCPA?yxP3+rK;l6$?(bn6Xf&O`vxY{NLnZ#zB
+z7;F+-Y~l!$xW^{4{S8!Rt4$0wy0zIvuKx|y^Q4Dsr(XC<(+9o68_`H>qw5gm`1NQm
+z_rZ;5Z3cDa4TPnH(ShmcP^g`;oFYKcl?F|wgFJ)wv^~Dha11Y#)km_r*%1)#GOB<e
+zQ+t;&u@TVaD8!RVDoS(*Cn=nadd#)`?MbPp|4quJp79Pvt&G$XRBp9So%bQd?Z`<j
+zh0g*za#G8VB1sWbXKFcoFxiolTJZ?Qb9&BetngCjKS6Oja#9zhQ`xPSU-=5*Pn)Ms
+zNjd0{5=NEg3AU8*rxZ0ec}Az6<f9s6_|&=n=M?9}$)-y(ZO$nsk!2I7nj$$Qa<|AS
+zN-g%Gq9v5La^{&tUz<~E<P_LMnJE$_IeApn=#!H=-$(N-q0*IermN3F!^)zf>xgao
+z3@tX@d5%rLN9q01>2$G!qBNJQ@ZnCw-7DM(T~b8WX+D}_<K;fovGFP&@_T_3+TSP;
+z%BKYlS9SrI3%<C_>LpjL1%yum9&FQ2bP?9T?jUqW2~!|xJcdr_7RoxLxVYX+8jk`L
+zt)?huh7prA9%T>ZB4(Wky%7}I6DzU@(rl4Ee<uQ2rUzBk9b}`vf3JT4t<UDKcijSy
+z((of-T0(K?)rX3C{_hQi${#>QQ^Ng;)CIPTnB3l|M}mCV+uw*!P4<P<-ty7Oejxe1
+zjfE)I-y|bY2O$%Ge%~!rEVSXCWj5K*Ccofhf6iTQb2B-YlLI(+h0Q&Tb5{%~t@ZrF
+z*Fru8TdhiFNgHhLz^$Z3j66u(Yuenwuo{A`=ZGh*$}0~8<`01=OU!OBb?8_SC>)M1
+zmSE-|CHyfD(mpfmInK&zlgRxX87L*-6mXC~D`_SD&kS|({6YTo<i%T;kyeBIJCeco
+zkN1CqSaHx12szLS2`z40PE!0FlHngkFV<izO9)h(>7PJ5%dAsHrRiEFd>;@h)f<%-
+zuU<jolEQuIIpYorEo_0P|5P9I{3*VgZ;iVM)4&?nM2)6HMPIW-P~x8f|Ew6_L=Cf}
+zPVe@iUH*Tp)8TP#^hq^j{1+x_Cywv4d;X`7{D<QDVh}7|O}%I>KDf^5LA2LT@$uP_
+ztgEH>S|xIx?#AJ6HztMiFeq{d`6rs_oP9#ZeDpWSpPO_JZB6g|M8b0xd;b1rl{n&G
+zPW3p3K=AweH$a77q~@<Vl56wng9RKJ)`jO*Fi<DBI$>oX=5Q%Cl`<b9$u#!t3<z@O
+zQqIdZ#~<zm(%>M|%$=@eHn&03t>|DZHFFi$(Xj?CAi18uURIF9-6jrTo_`I##r|(v
+zD8$4qTt%AAq$xxp(6^EGH4`f-d<4Cc$Q9ZhA|+m+dhP6JjE!~^HOvnDJpuph7~e$W
+z^M}y!gO$HB#y8RU{L=#dxiP+p8vYP>_5ks3e}PJLoH@e{o&K=6;6v!K1!lt+%Xqj4
+zhHAe8#R##nf_JjMv0{=J-?J>G-2jNuVDTQbl9*9qdL-OGmW%O&kA(-h?Z?pKHd5?F
+znvS#p&cWIm3~X;bl^iZj!uLhbVlm;I7!L8j`wzs^Y&YUD5$V|rnLQmVd0i?Q9jgRW
+z<4248!xC5l6Kh{O+NO4@i3JsB*&MqE`nMLqx-|D!41te-!=B-yn2xCB&i|m6<*_2a
+zr6TyAH$<I7|1*=qLu0w{WVFlXCNJJ>dOxXN^++h46>*FOL*VP)FvNx}w2vJweF!s-
+zusO8C1TYFrbqfTYgOA4siEWe!%0SfRBC1`F&@fNlK<dT{{)xDB5QgI~bKr_Y6?2e#
+z452uRO$n#c>T2@vxdoHA*S;y_FYx8a2CXo&nzsJNei`)5R~)P@Fo%HttWn6P6pmp0
+znYbb7`Dexoo98k7)iHqbCxb-6-*_=e8v|*pjWmFCXhAuv?cp&+t;F*J0l_?Ox7;T!
+zCaSIL8ea~=ASqVYk5bn)s;+B-y2jE~CeOb%5YVwM>_bgm<J_e^R>=w7X@Qb`R<On=
+zUdioh9aH`(djJj1Da6cv4aqfTf2y6?pK53JXJUn|DRu-cfwU<8DEJ%k5|=Ui4rPiR
+zK2G!yY&Yysrg<|Em}_Z#m4g!Y1mK_M#N3SsHpCZ>G2>!Q_Qpeq{}r7+*szYb{>E=a
+z!>@cfDX;_Kn_wX5wC%ia0}XAyPJb8J$mYk=!G!x4DVjJz&zw-`yaksIZ1grnk73ol
+zq^}XnlVs?RK@ROvD5zw<5W96x%9D8KPXjphOMgNDw;4+%lF&KB4<w{b3nYYI_Jer0
+zq!=ZASPZ_}pD2|ik{){3_x$eufV7^ep|pe3y8AskXB<G6EHb^+)T0TalQE9cF?I6(
+zUMTIT)Um0P$(Ehci9)LlHb{3)_7Oq0Pswl=aSx$|Xde?HW|zY}@KSsFp|sRg;dSj6
+z$Q(_iZk+5ixhIloQX?&BzCXDqBxm#`IrzX>_fbY*4<oRX2<%A`!d6L0*taLiA4li3
+z`vvuOf|UJ@6w>biu7YZ$^Wtp(m;+54I~{)D<em}Jlmk0i6%FH{fRSn$BMyYPgPCJY
+zLCqEwXy?(3`k*%>Mns<xj=V^FdFX(=URO;pLi@(#BvGgIi`9W-e-=YkBAMwVsmcMA
+zWHTW5uvjjge;(@R_C!r{Qs<f$W_9v%jgW!O=lL`o@LBgk7m_p7q+S~)kg&lhaH2o!
+z04iXtcZ4Is07D#x5t*GzbXaC+Dhce-8POcp$yg!R;`Ge!2(Em%R1WS4N_bY2BLfqe
+zPHAVNkuk$2k)os6L{tNkqq)^ck`cx@WJ;2=McdUjcWg{MkjG`Sk%I0R@9NP`i=$)K
+zJ?20RwqvqAM5@#5e5s~+l-C~ey!>_mjl>D<0Th}TgJdStb^ynHZ<a)5zZLT6;6@U1
+zF(%|~SdY`DxM2{ZzBf~%W&tOd<V#dUlKgw($=}>TzU-Ig1@em|>ImB!2s>aOOC)8t
+zER%%z{qwydi8_ti(xK8@xUvamNkt2a#w1y+hPMP=%zMK-cuSBtNX4NO0zoHm^pqGR
+zQ9OWUS*PM+7{U>}rGgR_r<T5VYBzH`#Pd$$EkWxzdPM*gSxK>fn*SyY<!!P@=lPo?
+zbw;4X42doYpdyLh7C<v%f^AH?V}4+U)5S8eQm4Pm0@8y9o-R>oAa&WsW&gwZ(p29&
+zU82%z!)xUBR?rRwfp`)<D}bg;R0aaEEIsyL!fMCVFB-(MC&p|lQK{DVX8gdpU4!b1
+zBswI3I#}xlI<!W3khj#)5|zP2vMnd}|B(#D*y!^)+B<+|oS>SL<mGG<mof5be_#?{
+z73&L$UceA&V)s6Q8BUj|bcOE~iy5TNC>c}S#<XHI{WmTX&7AJPXqnV0cBa0*Xqm3U
+zfVz$`49IYV9uohKjZO7#S@shr9^(;dKpCFzb6cs3tCvYa+?P^cNmK@u;YlLOYfn5A
+zh$?iNZ35N0wZpojNy+r)ncu;hn&o?^vCv@iIFFZSc}r8iZTTiiy(**0n<de|w<88}
+zIPw|iej8)0Ua?71G7@R&muOOwEs3ROMTZ86IAN1rB`O8u%z^J%=AM{rYLleG!Rj+h
+zqWdvq8?W0WxiasQypfw^6v&VSCJT~`NMJGwVq<>frYO((lXwfBd<T7tgMH5NP%v0V
+zb}-NY)_gi|le|%Z9x_9Ki5@aRfOXVkR2)4<ZR)7Us1AB8=c$4la0u3tl4@m?_U{tC
+zvK`SDiv9nVbMK0=Xmm(QmO&au5`Cy0F($~yM4YglrBn*W8Ag)zv?F`@CQ1F7QBp#p
+zFSR3TB}Ck#%nEt+eK$!$M399fD$)#33zNNV3olJwVsBG)=o`%qdEvZYCB?DF7GCjQ
+z;%%}=7soeA>WyISpDEG5wIk{#h&W-<0@?AP@jezIq&RBH!NJ&IA2s6yj>_(fN=a09
+zUvxkuQJKTUk|`70Yn`gqjw4$H$u2RDlDd>>tS%SV0#b4ow<!f?O6i{?X=zxT0~T43
+zq*d;M6k7=XZx<x_;9jiG(Qy`<(Qy`<(Qy`<(H+LAI989zKPrx_qvFUqs)MYZY|@yl
+z5pl|m=uj?)2j!^P`2J$qCP~QwAT10MEoes+)AIvFv{usHgH4i>BSR`KQTZqa6V-?m
+zZKN_<+$1XX(twmoMJBN%D&pe|+nK!UspBn`YT)SN7^D>P<fZS+1IjFkKFd(D_q9K(
+zgJC-soGAs(D@;_8@6DE|D{E#4S>kznYoNpoiHg%~>;^dZnHWpA<|WP&*ABEqOH{tf
+z9KSUk3(k~+UFb$30<}h>uB?u&d6Sh8KX24m5={+c6-o4f0P1jl5aFy50cDm%D;bL4
+znvMl$O2N5-tl1KEWp!-LATA(pX;Nz>dU7DENTTxts6%TSIP21YQgk^-uZ%&~*0KN1
+zoFz`ZsYfL${<-7Zpku+AQt<Vlx>F_kcZMKq<|avf7$Zv5t+b=DI#xQpW2Lj>RXRPW
+z^!=dH*%Eato!(*gY~ccL1O;bE1Kx{45*1lAp<-6Hu`igtCnz;bqD$y%DFRIbiOO@H
+z@y#y<#VI=VTX&XmU?6LTL=O$1S+<_of7gzsVwpB3rE_9ZaydFCfM!T^d;oQ*>xhn}
+zbX`)qC?;h(N9P9642g=3sP$TqczG9UoE7~DDq~NJ`0RpZh*T|7&JSPX6S_BfE2n{)
+zFXvuzlQxY{Oynd=^AqvpgHoEmoR6L_=Iv#?mGcSBpUDTvawSc!T-7tK4~}*DdzdHJ
+z0OVj%j;-XXnp^>p6FoV(((+_)ExTsfFUw9?^YNHuk~f{K?)yKHw{o8XagZL`SYJ1k
+z9~>XLbo9vLkt2rCs{oBlhs>{T96GPEq26;THc?eMZ|MBe(vJKiMO3>&9eMR<)AvZS
+z1F~n{#4d%}^$lf}HN&#$Hmr$LO%$iGW?#z~ZZq(pe|^9yE3cq9HPMu{bShU_W1~Q;
+z8*IFxa#1<OsJkob%FF9Y$|@V{hm=-T(i8IpQ!kC1*H~HAFr>2D+)lHV+M=bX)JDte
+z>Z&0eHuU!4>jQMpska{<7wQr25vraO>hWH3Qs{L*X{ev<hwfb!9(ToAQ<|SW`IyjW
+zUikRXSo$3jK0Z7()QkS7gt{aR@k9G0O`}_$q1oZ<smPJxY>J;S2hnkJ$Bs`<4sBjl
+zL8*_alC!3qFgf(W$~!{c!|x>>nXx$3^{b?52NC~%-xPjrl_`C@kK(VbqNmrBlfDb}
+zrb^2iLWf)*+P@-nyC0qt?)gyY<5ky(x+RUUwTlYljg+ZI$S}y5I*#gJcTTtm#n<>r
+z1AU`G-}RyL_el4{{JO<M!{f(}A9?~c`k__hi1no3K=FrHq4bkJNkZayN<2gQFQLY7
+ze<(C+PH4lbq<(%Va(z<&{hp=r;|t%PJU?`OQbl-f=*^WRJ6sW3=Z7O`K<MRF;U0*D
+zr@H^)!cf0(gw&f%PZ#*1W5VMu+kNNc(5?RZhe8jX(-6Ae55E`wI`lP}B=o|n*NM0U
+zyraY8!hJ*Ed9R0dtO{Qrn)hCK^FyIM-u0mysg<D_?}a|~X!|q%wgI{L9O~Og(7|7<
+z439f0so%b#+mfyirJlFn2`6t0Ejxb2&`|2@l_&g-q9^YPj~yE7dOfFp2oEtSD4i0H
+zq-^-mX79HF$OCs%=Ic{V_=XaG%6lmbLuVf!>N2Mfq2Y=v2n@ZCzZ38``}|)^uUWH(
+z-e~as;`#+Obq#p3y12NeqN2FL!z(}DqLM0n9jLf;K}lsbrc~*oTA6$GmCMS(!zYU{
+z9gEFdE?&ce%KG93HT4a}^D3*$iurY@;>k1S*Ok;R@TiJhk5cuuC8gzfxyBU5<Z?=K
+zArgo;g*;3o(#y=W%IadMv7nBGOe3hGcwR|;xmQ(FJwIap8msFo=U11PMeq_vaZN2=
+ze)7uD7^!T2d4rp*AT{w)mYLyDt*ml>WrHITf><Wmp$>8ulvI~hm3#D|qsYYE+{lsH
+zBeHWM!*X&*=8Vi46B)9op|QGr{QUCj^18}WN|unq<7urNGIB&@$o$BVX~QBzD$Ey>
+zhSb*47n4dGYU=2VNp;kSKue<*X<b}VNiX}<Q2WvD+Ow%I7Mix3x4WRXX*QHJtyol2
+zJFK#do~tH$Lk-GTmCUb4@nOXz2n{5&HZG!0ZLBLUt*L5URPB}4R995aXKU4aWi^fS
+zsCi|Lix!<tVwCM^2o%>;m0_IJmp7nCE9kwqp$lpjl@B$I8ai!ie$mjy6N@Gd?XYSN
+zrG?hRdrZa9wx+JWw!GBCD!Z(vnmT#%jM~QPQtG&%x7)Sb4lxurCLqHuq^iw=?Nu5>
+zVZ5{-0<c?o$s%i}c3B0JC(bOk@8Ov!Ui33^m(*1@lo!`hEwDL_H8Tv^vQ?G!q+dPe
+zikUQ#b}})XE6R+NV<#6*GLia{#pQOGQe)~$&1|u+<P`^Rbk$QGXja3r;zhJKZ78o_
+zQcm@t{@Sy>Vw!~ugQ0-|jE=WmJIpIyR8v;&RS=9`r_PfJX)KIl=wBMc%gXIknmnVb
+zW(gTiy0E^!w1fzO0nrFn&{(|Qqj`jZ06Sodxo5^7Y$WpvBi43JaT#<633}5aVJ&T6
+zU!?NJrX(4n+`8<Dz*x<-W3{*%71)tt`k(@DE_%haH8i4a@6%|-;$tc<X{f0*gA0Of
+zDGaZmgJk-e5@ar`Ew3Z6sO?a*augeT7Snr=CG}{cdYRHIUQ8cwt11^0(#V}xRZ_js
+zv%OA(j=q0}xmsLNQdva{km<1E%KDnpF=L9^;ASq?E+{cNoAwzEN&8Y-)UehPqm*77
+zq-i{P#!|a5L22_6CfUgxSis07W|^xft*W8Lu-L50W+5Lrf~+6(mRTy1G9%J7xVo0!
+zUTwg#U$KZ5J$k3J*eo`+C1tcu7t@Bu7dFG~W`x}wX%=Oe8RG1GF)eJYZmch-GL;pk
+zJ*0MHZ7mHo8rNm@4VdVr#5}T2W38POWZbHn`Lx5aCNjrO#q-cAs!JAq8WXIlT>#rB
+zNf9zdjjIi}b%tr5*GP>VK8$SP9XD~}QIV`!^BSug8tuY8WMrdB<*v#dnVmBtd&EGs
+zpyQ~`zCc7<f7ywizcj-?xNGO|dOD!Psm&oEP%t;`^V2fUPny^*rRb8-#mTLmE=pO`
+zIrL(uE=14AX%#)l=M{oX;V`=~-;+9n<CC#9GV;@UtqB#RMXI}`^(siq$WIF&ms*h4
+zYodvoGM6VTQxlXqR+ZVFuuS}VpzqIIM)bu4W*O#SmLJTUkd|>#66t$>C_gQ-Cb^z!
+zCp9Oeg$qzSwT7ZpCX0SiF1HRcW9>XHEt0gtP^q2BN)%8$+52*Dy!?<o!tRh2iruGZ
+zmlwi;eVh=&k$s#H>hR@3OA5({qg5HY=b;ec^K}W88?rCmDU?nWf~VlyXN5d^@-<Ef
+znNij;BV^ys>yQx&MtA$HkbO6;JxHmL*RunLmiBP$FAuQb)hvu59r_Xw4?jEso}B>4
+zc~?9+m}Bv9T+NGzpPT@np8&5;fHx+<S0=zON`POL0N;`T|6Kz7al+9rMSLw+=J3mm
+z%hhkQ?hy7a<8mEY@UIz{E3$$o(}aZlS{~9Oe_zJsLSmH4BlIUcp8W?gUoPFPvvhA*
+z0>0VpXP3s?HQR#(IUcen3wqC6?Cxf0_klxYIoolMw0Y;mdsZT{xORIZf`c8l-Y3U)
+zP5PKXj+^8_MAE@=lncZ?V-bQJ5V~nPb%0uQ3?ZmF$qM#4=q`7aJBsa%s}q>r^r;jR
+zmOA*p4t|4!@8{rmF)s4uYR3}_pTp@L3a{bxrwYG-(@8WQ5Jdi^Ht8Lp@S7Q*sPNkv
+zKY?-Rhi?^1d$%|^Js%n1e{pbn<}$$l;ox|uROI~P;0HN)B^yNa?@D<HD;d}N{LR5#
+zeLB(gD+FY_`gCDj<o7i!I@VBl7UL&5a$NlvIQ$gi%6=Q)twKP(Slgw&s~sH2LxSJw
+z$iaA%2i)#=_^$m+c$W<MZhJ3uaJRizIk>C;A06Da|MLm(t~?pUZcC|tgnb!@KCYhm
+z4t^-*NqcLQoO2<B!UYb$H>HJtorBYR0|CC(!CiYEh|Zt@ecX9>B;%rgkzvsX5gdLW
+z!ld3y9X_I0Lm-749KPGXw>x~OmSfoT?PG<HV*E9Q=P~}V!cSm4!gs5ohTD&M4(|5j
+zN(XoCb0y<q2f4{~t;2Ww@l^+R?XyqVDh7SrdXHfo^3jyH*>3X`zMAq7svSA5J(oGS
+ztH1b`5c%7!81FtMe>CGyD!i80o!1n;mGKW0F5guDQRB={<KqU=r-<9zi*Y0)^pkOg
+zcZ?B$_obiU*-8#L2uC@5*FKXSydUvI&K3uE`|F1Ucod3LfIcq&Q3oGLc_P0X-}?f8
+zu!9dtfKN$)^DsC2DOQc7@n<k-i|XmocTarU&^uBl2z~^oF~<=Ep8&-uV2&W5n;0@_
+zv;_ftdiya5GG9f`-+3LB`6~EGUYE`N3@R=73tY)0mMHkUjN^D4LGTEV9~^HZ2;Q03
+zwGs;l_`}SvP&mpVoMkrw{}q<AO5yLZ{;djM$9y?n5PgO-Pu2;++Zex9$-&1Z5dLU4
+zfj)D%!?!6Mx6%-vvYUXvnDu#H;rp=sR}_8&^WRiB&O;F1v712t8?4Vq3O|F>pDSGU
+zXWuGZ-lzXb;TLef%O{P+ZXdJ$J$Wnm@vMJug%`1XaQu%Te7WT-^F#2VJZ|OP2f^>=
+z@>7)@^Gy(vd$Pi}vwbQQF2_%G3O|bZ_>wV#)O(*zdKW7EC)V>yh0o>o-lXs<mVb}J
+zcd^|bQTTl<|4$0Xu?2$o;1NB4!@TztUyj4@l}!ZU59R)q<5<DJW?m}i3qFkX?4@uk
+zmEPu2_$Ic)Fol1|_%RBX2QCX0zCYV-uEOz+7laChXEI)|@WG6)R`?^VPpiVC%)eIQ
+zGr3=GRQSD|zDwaRu-zV1cn;V5w8G_aWI6s9`@hZlM7W&btGN6T3UB80XoZ)soD&tE
+z#&YC*LFD5TO9*9(Z@#olIKIG)ApEs9>8()s@r<uicqXSWSNI}MZ&r93+h5*#l6sdh
+z{-okpa=kApd^+3V?+Sl|`JX9V=HU+tf0*k{;jQR{?`9$NRQPY%&Jl%QXX)M$g&)Ou
+zzQT`Te5%65=h7((7kw5eT=Z#FxYXOMaIvF28YAt!j(ImJKE7UsaF4=8{`(3)g4Z9p
+zcp>uXqNEA#c^r<fzGZv%;&~?gVwRh!aCy@HNQFy#CMf)BuJ=TRPht6|DO}#?kVk<;
+zpWV#6M)7?fhqo&H39k2fg}=$|m3Ku%{@2z#-d@F*eo5teg#Q%Vd7#3@N7iu0LE|b-
+z4Ko}*WJ!?YBaz>U?K4mDr*MJ!4vv1D%<VnP!6EBT<}Y?|@b_b-niPIG*L%6b>lwdE
+z;m<LCufm6M`Z0yey#1?#L(hI}&wn^L^n8N#{K&z<|AP6SIym^9IsLtZgFlVs{OsW1
+z-^qB2b6yO-JR+Cs;Nbt0ehB+HIQT2s{s%cY_-F8V%5-q>?_>Tz2M2#F>oZ#6vd+j;
+z<VHv0%eptk;Ulk(`{hIjhx}@mf2xCn|2p%_8JBUpfbtMlD}E!lt6AZ{Vf<2sw=sT|
+zlE1==_a0TaJmUC_BS)?UqKLfC0^RYG`5b#E#m+l<L{e@wNxS4FwnLorddQJ+J3!&*
+z^0*nqxX6(=-o)3S;PS}j97hiHm-Ec|4vu>N$nvX{e0db}B8Lw-XV4Gf3I|93wsJpi
+zR`@$mjKcpoIO>&ge-GoLzr4dHz5~H^<-g>}0WR|2ba0fpk^ApGC0`yH{lwv;UF+$G
+z@RNf>j@aGfiv^;mJaU?;aCy7z7{(z3zq47cyzD9XcE;ttoXCHO?OCtn3x2VZ{|n2x
+zO5q}Rqmm;pls&F+c|`V4jvUyhjeZF7?t$q48|J<1@R9d4r$15nE>3^RTWPPnyC!cw
+z0LRolmwpKHmH=c!A9I0)Hu(T3h#Yy5>@>!)!7q)|6$%&LLdLb6)rx-}r<)Xi2amTK
+z75*@<KMyPX7M^#nD0~yk`PjiBLau}S?BG~ZGg!{Se7y_V_}#+1Ova^M@&?&4ioY+X
+zqY6Ks({epc%bBP6YdJlix5Ah6=rszL^TF#CE{{~-$2gkft^?Z?F6+Q{2S=GlIsGDU
+zMIU)J?OliO%KuE^B7e7oL;i3x7(MS7C0|}m>&f|A|K180`SzQ-whvL}GUjFTR`i$G
+z)g~%AvJOvGxX7R5;E?}MPS4}5$d^ac&vf{R7J)$FYzK#&1Nfrmc?!RU@e3Fi`SQs7
+z9SZNp>)4A5m+PLp9Gs_?(dSzS$Go`3pmZL`^-I0eSpRGXhn(A)KgGcz=MLtdtnhy^
+zUZ?PL`8cQ5!6Bd3^X_$UP~T?$qY6KTkJH{z_)^BdbZ{&Iav$&~2Z!jj%-;`#n}XQk
+z0mgG29D1H^Se`fA!6B!d_eZ4)zn1ak3YYV`D;*s2<^J7W4i5Q~kV)Zrh0FETPZTc4
+zwaNUbjkN1rUO#&)ypG4!kqTeM_%wwd!uzLF72comN`)WI_!<Z2rP;LW3I|7fWxxCy
+z<FY>NVtc-=`0|`ca)uFS_h}Tpo$b~`;c|X)sDq;ppY7P+!2ylqdb1f9d&+Yt(;PnJ
+zjAA)69UPEc$0&Ai@N1c0=HP%t&l(2@|6%4gFfRJs!FImH;e#sId4Hq$^1RGL4j=OA
+z17aq$IXL88VPWq%2M7OX=D(%z3mJc#anW-R>$z9q5eTDj5Z_or62DhiPJe}W<?=@;
+zd=BHej7z<REWgm<qg}V~d_PI?<@uoHiZ9oHniVeBA1-%rRCxpI^BV_8z3<Tv;TFb4
+z&&{mo(+(fd8!YEJ2ZtOv4}IOi!O!6ITMiDsjKdEc9Q-Cuf2Z&tIsFrFMbE9QXIDG~
+zKmkd}m;G!nh0A_6lW~#r1k1@&{3Q@d;W)*Y=dBhve2AFH=|v6>ePkXjb#U-6;q*!e
+z2Y(HZhjk7P{tixGt?-{XeVv0t4kx`W4h}g5J?W3aoemDZjGwIz4*q=RKjPp<PhLc~
+zJ2?3FF#iR{#m@2$=$i_c_ccFMxV&5Wts@`xK7vIWf$Kq?z@KHir7B#m`=u+qJFn0C
+zDO~smDf|^QghKBG_yC39$ozo{U(fmvRk-j+DEuC_^Js-%#rV+*7yd+rw{m-rOMp*P
+z_|wdvkpMqg;VW35(-Yto3a?=KXDa*`?#HtfF8sv`@5TIO3ct~Im$zEs!f#Ue7T(V`
+zC%`u-yqVj3MFM=I!Vh45HYdQhD10I7b4LRF_X-z(09zB_k1AZwvz|zRKd10%++TlA
+zfWNBn0o>jl3YYJj{X^lxe^=pnUKZiQ1o)l2KL-seo(nPs?jEyW;6q7+^KL9S-Zmip
+zozC@OBTEeOBKV^K%*Bfg8pGu{uuS1{oOZRs<@o1$g-5WUA+SDDuN)8HIbj6BWq)0$
+zaM@3J+4W~HqE~NdOHb{Z?E;C_l~<KyH{gZDY<d%^#LJ#nPp=Kv)gS?SZgy__<Y>>(
+zvm2|cDi@YlolUtAQC2>$aei@Sbwv#cGVzjm^XkeMx68)+DK5RFuB3W?In`%NNXik2
+zw`(MuwDGb_YZfh{H;KLMYI+GUo8Bg*mjLO-7#3T;ptzzA@3Z}%ga}E2No5>~&^(Ul
+zSMg<B2@lU^VG8F7z}t0GZDawT5A~uX>X9*uG{Rx@1J27EAQQIo^$bbNmb+h)<~<w8
+z{BO(WQd!6x7D%)aseh}&rGDAwQGUGgwS2<ePbnttm-5rNyte<Pd_1nIH+8vKDVKLK
+z#HIY_yq-wD)GKM6Z^!GuFJ@WB=zeyK{(|nJzw}=XVOl0ioZBD&o_CvSzviAt9F3ve
+zpu_P`=Ow?QKi;2+r+?N`Q{4Lcp(ymlkka~JN?5%5_wbG89Ljft=C)F1y!!LFekqUo
+zacM-?e*<A!CPChivH17A)hbgZz26f@V<>m$IQ)Cwm%n2FyNMG||JpeA!`#>Uw-JW=
+zrJWQt;rcwgmFt8y71LF8evUHYmA~LPTjEG5$Xh8V+gG`~qInN<d5uds!FO_b>}TB2
+z#^vR?S;>?3OZq*E#IxTzwqF|)(f|9=Ps$^WfYUwIMFx+aZ8qN5b`$(-{gKwXgPb$j
+z7KuPP3V1FQrx?0^99G1uzi0|&P#C2uR7vt<THM%BS(RNgG-5)I-8gZJj2tn-V8e5A
+zId(>ub0!rYo8-qN`t<SnSjyIK{;|k#$TQnKddHv_eD4}xu+g$;%f9BoiXw+dBzZs<
+zaih%znWJ;tqD?P1j@`Aw`ido1varUPNVN43V*aBn+H8w|gjy(NY0>7#3tI~_lM7o5
+zGQ-i<hRlp;^IxOQpBvVi-TfNwBHy=%L|c&CQkXe9aOd6Fm%PPB$y;o0+phP;3$QD8
+z*Kdss_WhfGQvU4x<~Q<Z<<Fel{EP7fJg2NMrfaN4(cHEv<XC*|HAYQtbMv=_tyP)(
+z7PgjU_S!X)eCPhZwsUfG8|p4-{&8~iUz<N8x8G4}wsosZ%{+N-!=2R7Of<Atv}I-{
+z*?suF#>$PyP($ayQLlAcjt2id=!|G{16f9VlDAMIumM%Mvq1bclRMt@wd<)#WQJMB
+zH8Xh+rY@clP2bk%yC?qHaLT0IPbcNRm%ptOk#-%Fzvd}Ff6bocN$FEQh*F$rr+MII
+zt^O&yA>Wub+TwjzFvkx!z8o;}%{?*VHSWl5%U|<zDE*4I?~RvXDDU`o&L^MgRO7Cj
+zj4n^Cr{VUK5!%#7t!aqZ3dkAqVdNmX*C|w0i<iC~j-A(%ex7IYPa%Z+H`;8yqd$rX
+zXEMq2vs2%U=AX>te%ml-$;WYq>A)-`XcUv1=;qzg))kq_>Dwup9Mm46iZSlUs_aI-
+zaR7Bk#wk*7hibQyNN?A3M#B1-FKf6}Zra<JwGG*i;xDLUL`z;q#bevU@P15UZTmX%
+z8h321rX!hMJB*L#t&0$UKCp+Gugzaa&;8_Tn&#2w51sa{&0I$q`-^XCTRI%`EI(TM
+zip(>b!z~vXQmmPWMbCW_qKy0OJSuH93e0QzZPzoV6*M1=FY0qY$)FM~#bhm-Sy|M`
+zX!F|4u&JE<bq_`@NCmYt??`XD8MJesL`ma~+O8v}HX5ISm3lE^SBBN22Q?O~Ug~>|
+zM{mQrMh%|a{GK6G1FtG<{*dF%Pc%;oH=Z9;p3ShcmSzU&EmEcQgI3zpB+y8BdTr)j
+z^wzFBOwzUYxu5hhZRyZd^5dNmrJ*|*V@I_(z3DaEUX(Sqwf#-Q-+Ut0)Ix=$%@Z@y
+z*Iq$f*6^Q_(@@q9fhD@Y5)Fm$jovO#H-;J|?J?4t+M1tgJirt&^M-A+E4gBQ?x)d~
+ziKZ3ZnzNce+Bw{qE6<~77Da6t>>Q1tohQjUBjXp#3@x-YEOK9_x&1AsT>2l6-i9L1
+z=rB{yh*-0GZ}SuBYagWiiZv^}r2I$licbE+I4~+`{+QgdH$Rh~Uhpa_-nh!JqOCJ&
+z-_iVC^FJr0PkO(gxs2zoY1!alS#&3G^GA*6m?_LFDowcpZU#HGXB$4wHhF~FW_{SR
+zyj^!ytT$>X{;n4pZT`E7C^-h(StG)zT@>g|QF@h>zuDus3$H7$uc=yG9>HgQ@L30O
+z7EXLREQq0jfAOlCnuU?ZT2ml0@9YRXp;Mup(N%M}9&+~_uOL+)fhTB@Y1D#V;M>mv
+zmDiKA@}MRuFuBN7LYcN5;5#26GKD(0?fw<HF`1Eyx|&51$TL3O*-rE=7uzsWg1+mq
+zFfa}Kq4pZf=<Qqc%`j|AO6kKk31vV)d4sX67EfPqsitoPiPfor$<{8n(m9ijVj+v&
+z`?b0BKd*BT_5N2LtdrNAPLfPr$-m~oI{6Wt(im>19TO-jZnDGJo0A6}WOpBm7iq!(
+zy#G^Y)>z7nGi!5QVMj{LgLR7I!8+ypwN$b7L!9Dxuuk~_xb;Jv;&`x5`3bmvW+KJ$
+zV4dQ4uuk~}oIG=1JjL~3o#J}1PH{b0r??)hQ(O<$DXs_W6xV}witE8T#r0sF;(D-7
+zaXnb4xE`!i`Z^x0Q(O<$<Sg(!YQkpQ1lNOgitE8TCEMRfH0!}S#r0sF($0f*3VX0l
+ziFvS2aXeV3I3BE1Zaj%3{?{I?I~xzy$t1!H_uWAM=H{9iXb1Evr^5tuQPuT+Za;6I
+zZ17IzKgIla;oCD|9-Co1koP$R-#jrxDkFT&6(rGI_6c7L;T+!xILW%C!(CA0lCGOA
+z-=%jlAt_;u5F;g$TDF%EBPF#0FvsWLL$Do~sSAuzET<CjeQo?qaC+H0Mv+wC$Fu*Y
+z&r(Ca5oHs}zL8}Uos74&44X(Xv|gl8ElI*_{oeV0*PKlx$JEeuIHDXMiFm%n#~^MW
+zz3Dm@@h5Pu>vcUE@nqj7CLuA&x0bk@;>Hqrw&CG!qh2M*i0kHf6z>*z6i12u!C{Z$
+zM!oGxX{T4w`eDkYopBbH5*v3sil@!Phc&H7@wC$OC~jwRTG^i{9<luL9(1s3XL4G_
+z6pH5@fNy!F&Bv4Lqb+9vx^k<HSC$g~w7tHR5{3@eqqsS-PYJIiz+Ac-opzFsYK(=`
+z=KAMQF;2K1#nW7m;%TRvBJe1V_Y;krqO@WkDq1-uuAF%$VLghcxgN#S%1jY>6n{zN
+z<fP5_(L5`s(v{<S6i-`dSnw#`i`d4YB3f+vj6I4sQ2M~-)Ex0Bo>uh%^^f6RBHRf3
+z>NXd&LU>*LU@GAy*$Z4ae)9Y#%mV)}lIJ&JCvfNja$J1@K+@q4MCc7}X!%<F??Zbq
+zBPX=niKfL+tVG`a;O-A$ww@m_S^P=D^3AH=2cN(5P1d1}^r<xe=i{gmUW9(0KhV^V
+zD1~S3hMW!dr9D(%r2K)9j?fS44hB86VaqxF0r}Zbn_TOjlSzk4^o>+hk6?3ikPL0O
+z`J4d;q(9s=-cH&bW<B8s_y>f;k@aEZYH%@fA@eZuOk7V1`uOD*O3Z~MFDUXQ73oP@
+zq6i)P94=Mt!9o^6%Af7F4W|?a-FP4^c(!e`rEQ!vHYE}#r8TDIb8O4kam!D!Enm+q
+zKUKK4<)_(}uWjG*$Bnwi2XN4g6dL<qb2C<<<);19$;Bx(KeS;z8jkh_1<>wPYQev0
+z_w}L-+AGhs`WqXAc3&^;&N3F+EPR{1L6U(@yJLb5#L$*7n<M_l^XWd<pochX@Y5VQ
+z0@FhRMjL{EDL(u@Xp>~MBjKC`!EeD6%`wst3-fAC3B1@IRG6)EheCtkTJ0gEI2p<x
+zPKMowhN=yRkuPmBsbf?Oi8Dwp8#ORCX429a9vCDG28lp~|7Wo!QjPed;BUm^ymlD<
+z8FL>Y6BFn!GA8Xnc^R2W8_IHBdx7k~{59Gc*eXy7Gjl%@4pldlQM>#R)E<9WY=ofE
+zc=|YD!-HlxbLCy^=OxGh@Hcj+eSvMpy8>p`FQ#_9j~s-cf5=oOJWN#|T3k#n!*@Yu
+zW^wUSj+*SCA;U?{kF1(**EszY>ql^@If;0*e&V2FU{BG3YQlXJ1b<^L?Fk0;=d3~5
+z92qu-BB2d0tr#wEjDw96T?D_Aj|XQ5?cuRH=qrhQ$dO=-9b<Kqb!)>)>W*-|7mj3x
+zBZoQmkqhFfan%V1ve1S?zo3%%1DO;J%n8TD{Yf;&#S*<9n$Gq61&(6T#1HXD!Qc1;
+zJ$G{?9QyY25k(k@KR?soOKCFF%Al9Ax*~i}RgFT#&oT$aqn$XSL3^Zt5YqX+pQL42
+z1x<ywWHiF;2Vy-=GRL?*W$HV^Kb92yf9a(qBzt;@+;=&qLyZebPP|$J`(kWe$Rr4v
+zX@msXSR8K*vSZzXj(ghTY88rcP(Pek$E*Kvv=hP1)s!#}NzCyF>}ZZv_R{Fzj}l$b
+zN4BFUwCiY`86x-_d(i2D>F5cnqYHwLw%sx*5YVCHzo4pY$4_-S-o{Z&HvSOWcl=bp
+zeaBBVhvndP=y>e&-Bp0z0dPA$1BEEiqBoJ^|J%;T{`6#$L&o<<wC|I1ENl)!T!n&8
+zN5|d#Yb1;eTtGwb(!>l3V`Si=R#e=6|J0t7Oq~YKu=ZAIKQL^++v8hnp4gk0{zg1&
+zcqDz$6;8h8ed#0X+NW*DR|VZ-SAa!+y4gV$1ZtO)+LsuWW<sUueojo?TFSfAs%wo#
+zlQ@>UoO1utE*A$p(~~w7#5m^@XJ^2P9o1b*c+leOC=uubGaf|kGiHpz5H!rf*w+VT
+zI|xdg)2@mOrHX&o3wEF08;6lyXg=HUwnfb?1qU^^-_wmpY8y2ksd0(Ogp9ZSaS~6x
+zF9yHtj~6(We@77QJ}sc8eHoL`qhA20_VbSx3B61tDBN{=z)E{AR=DR`0i$PgEP75r
+z-nT49-fvg{?|=3GkDX7`m+#4qb<E*)598;WrgG2rj;8l*@1A-;$KQ1)IyJLCtm)ky
+z@zy+=j(B>B)9M4oOEtNjwyuO@ZmHY5oDO^wvs-GPhWDZD(bzbp?yVWtaW%cQE;Z8u
+zYkN*RAIE*!TQa+w?iZ5{Ps^?|YD&Txwc~wyfa}@$Fvqd<;W01ISur2VaKAjTgZt${
+z;-q@8IE;3^P#dSyLt?(B$^SIeC;!u6(@sQGpj&L(SGDy(O==I<ZmmZI2I=T}n!bZz
+z+Q`nON3#CxdU{kW+0hTRqk!?AeN?RN)_?TanBQk|WlrN{Tswe<$oLpQuSUcY@O%!>
+z(Lor-G4f9%(c1!OwnYDjA?xW!Qg_9O68&8O&64P|0VF4V48)!(%MU0;O&q-}21#{y
+z#2}6Zo0mA2E{7`KEQ!)0Vgh;GljyY!+15yEQ;aCldje>dL|+OZT-a|HIw~<!ln{Z|
+zxs;@SAIO?1(dQT<=YqReNkZzhrQ6j>iH_AymultPMdZ#`qS9K(n!ZU=q7e}#DjNCT
+zbcu={#L`L}%6bnBnp9N9(G@XBs=F=*X+ctlJhKD8NqlNAUpyiYR1zJ}S>$#1oK2FD
+zFFFu!Hs{O7LkW^-%;EPet;0vGo>Xl7{<5Sgyd{s69fhCz-$^=6B$WliPm`#q8_)M}
+zEz_3<#b!zLk^q_^(W@A;qh3<C#)uNVtsPNPPsNB5l}{{LiMs7gT;SrMV3EjrEC%UP
+z7phXpUTv?G6p?W$=Z3smFGUiUGnho6#IH<T!!4Y(B{4<xd_17c(0abaS-S(uEQ$UY
+zKt&Rb&_OT)x%iT3UxuvlBsD2Uv?XHyA<jw-C`D3gbPS5|ZS2ecNKaj=hy~6I1kaMF
+zyx(f|mehqYqC|hoQ2fy$pYy2+3etD~ts2+Fpldmb+d>F&T-H@_mI$IzKqp1*!~e(K
+zmjG5#WbJn62Dl+1347Qi!JwcJasgQcH5UQ|46=ny)DS`f8AF0uSQHTrDAy2$5l3`T
+z9Jg`TQO8kqlz<{Sir|8b&OgIAZnz>U_`AUSPSrWxmCC)&IPd@8|K2Oe?NeW!I(2I4
+z>gw+5bLe#rg+@=zbRiS@;UZ=RA(I%=ic74&&!~m@zaoCWC%!<))?Th@LW)2VU$8}D
+zzW8QCO)P1NMZ^S0o({>gSx*&VeU~+X57G^nZjsohzJ5ZAOwH)YVM4?S7aGZC5&bi~
+ziv9~M&8nEqxu<(lrVA<d$8>K<Y@N?2WIL>bC_qUeJ2Mo02>y~~+{?!}C$!~#rbPl_
+zTCD#|Z|NvVJ`769c9fH%j8n;V2eTwP!Ba3_xxwRIyKfOtL?$?kU6s_cS?S+$e!VGx
+z_6tPwB`;iJH8hGs!XkoPM;@i=>ftw?+i#rLw9|!L*raJCw#;V~(zkatO~_%m4Wbae
+zTMn{}qn@nELjK@EGlV?G5M3YRSZ+@~Mj5V~ncdIUynpXup69&MCTo5DUtxKWS(<dF
+zfRAzFPju$<%<?85qj#ooy}?{jI#XCgP?XNh;Z~XHwa#=Q#kMro$U=U?T)K}WCi`Nd
+zxUUxR=Xv4_gxujlGlV<=w_X%Te8Copoy90RPDm+HGwMwKuNW`8*(+hPkpJ+YX`=lQ
+zPy93?Pxqk7LQ09aR{I5Msvi#edWx4QMvyE9q)55=eq~*RWm#bJAL4WSD?Zw%sLg*5
+zCiFPxV=PzyZFiGD)5By_cas$*HTX2ErYYFWx25HS()4mUpr~qbk>l-=FQy94TTV{A
+ziWY0XkNDoJtYX1WxT8eViVsS(hUbHlXtgtp#ek+gXF66^fg{=&y3Z%Kmte+=ZQ6#0
+z2u?EgUJ0t1A2u*xU{NvTm{OOB@-;24D*;ox0L1X})PT6!3OGTVubB<!mb#KGPibAq
+zPB786O+95c@q^jd-4s|BO#d#BuxrD$XOGzML+~$w))USPR0T`nz|alUObB!h&I%-M
+z4dw=xt^W=lBu{h|<M+W&m~o$Ctez0)7T3=W^q$peT_9mXVCk$tLQNp`y~`%92`rj$
+z>-mAC_izj(%nB?m4fHr1SP;xQo0#U+q@T6q^ntgZ-4kvjZ@!HDQNHI)2rRp0F5;Un
+zOIPu%mBF0A8C!F1ngH-`D-Q#_(<MKZ?<l90x4T*Sw?m8gGg=;Q`CPDLZJ_nxiNR${
+z0vGQJo(adB_rulW$lzc&-8{B(J@RgH4-W`j7(5*47_12-UGdQHU?`9}A#hRLsV>ze
+zn1SCwu;;?ys9^hG`%97UwUt*O--GT*MU$h<hup(~1o-3Jw>~&<L!d)epaQkuGU9A_
+zK=mcu2KEP5?gIOp?%@%24+O^q60$aA2QCVx2U6jmGG*6or(C)6$m|gVE{r>=%j}ys
+zJh~*XJTB9n8Jsiy+}gmB2{XU1?H{ZQbeI*_0w<_Ah=gk|?b1=)roeYu8GN&Oo+Q~p
+zq;j^V9rslilDor79!j*WlN{5LyA{Lvqp@q#(f-V^J;(4F={uNYH<8Mx9b{A}PkHRk
+zO}YP?Hfi+Ph38B<XH-52!=t0;5RN>(!J{OdQS2uTWfhViGPTcB+($Oukg3$iUJ{i9
+z&J@XkoAS7(*%rf*rlU%p93Fl4m;!R$_CM@WvZTC(oMg%;Jn*Z=P9;k#s}>c(%b<31
+zhpj8M%4?gq`_^+U>3Nm3-APuLRKaf>e9Rf%Bz>=K(krStrWH&b6Q1ahaLOV3dBxkL
+z??{e({+S*oJs*2;!dG2eUgOl1ELvPh^U=@pI*IOSvWwXEdRbUFzj6_Vuxf(lE-Cd8
+zM%}8HDHnF^d{R|yYVJhe%ODLZ+7XPFnYUaC<C48*<?+PhcVVGoGBy#%@;6ztXfes4
+z?P?^VveNUf8pRXkqN3u3^ue)qmMBjD)Oo=|lsi!6ky2f5oQ3K{U~j9{18rZF%9*3(
+zbP^e3xtm0NR5{Dl*+u>stE$NttLKeS`5zRYl=CZVFd4upUlWIrMdh^^lwJ<ykrVa7
+z2?kxsGb5!o^EOHR$_?XB`Ic1umOFa%WYfK5weE`QB6w|FREF=ttH|%tLUKmApk^UA
+zP@(n!ss<o-%d7VCeNb{=8?zYgN&g9FlwLcjQNY)4b(T;+n;t2tzvz0bx+$guN;TJT
+zTY5e+$%|?ehm^dh+;@z)P+awre@PjTx&tXzSQW*ADmROAT3Oh{qZZ1;>4|hbNopUK
+z1nGIzb7n~e&;-f;NNwj?wkJ!{gj&HH5o$P7%=c)yTrGg;1Tnr%Fh`Z=K$FJKKlO7-
+z!hQdi-pHVOiLXnV6R^-L95hhR`=j$GjhQuOwBZ9&d)(DSZroH%g8!mlOmA$cW~+dk
+zSJgA98+puxGRn+>o`S+N9r!3!{+bmqZOjzD0AUvXY44Z|k^Jv_#`L$O*}gGpA6<7|
+z?5o!&roYFzaks!tBoH`!glEiI;LBrPJo|7Q_>{ahZd7vGHGwh7=?(FtlKZS{k(-=-
+zWy^5#u)0>c$?M&?i;_3FqmplRXX6+KP}n+oSU5R5oZM$rayqg?1RPI>6G`qJEL%N@
+zI6FD@8j{@*fZxe=@yKu`$*yY|SJHY%a-Z-{WPcg?Ux9$#$-%P|$0rAO?0or^-FW8*
+zIfq!5dPIa8)Wu!UIypEcaV&l(Bu-ZjEYrc0M)g2Y+u;=7<mB{~tyPuD{w3bUIU|`z
+zJ+y$E&tk|Jk2Gq#S)8W!aQSVQpZstj?rg8|#w2EgcQx~V2%6f?^v5|a`Qf;WTPLT(
+zLnox5Nya5A`A={jrKc~S*jISsp-e7BzQ?@1=m`1Te&`!+ztPlw<C1gYu4%2h0G>d-
+zE*Ogn{X`&<{}VnvNvoE;(Vx@{(hou>{I%5I45+x^6#1|70h*v>+dlz32a6U0db@kG
+zq}aYe&DW!Tw%EQwvE3v}i012)*kbzzrPga6qWKuj0GsJER9>;t8{B3Ozk$(t91Wiw
+z1D_iMUl0Rd2AuTSgQE&O<|BwiE0?~?R{YE-4>|9S!T&h(%L^|xe*k+f20x~osO7%N
+za^&TWY`1-nae3__4?@3)A?HWtmk0l{SF{c46Rp1F(<d6<4LG%fJpNX55M-0DhG_i5
+zm|vdDs`&@}<hzID$TK)K*8o31hMf5^aC&7Mt=wfXaPsLBjsMyhxN#?CEXj>kHLcEN
+z`Kzwjh2!!kjSA-%P8vIQ+L(gEg7B#PF@@gsx(P2<T5?BiFWOA8YDM5><TW-i7<UCt
+z*JL`kEc5(@Byd_y;9xG8G`Cu7qm-YxnbEh5a;JxEO>eRQcsKc+XswNPNpv5g>ZG4D
+z(ajls^r-Hnux?bX$nMSURid}Pkr@vgYv}2g7bs4Fj(C#g1=&Jo<71h_mLun@%|D0v
+z>G3FC)5VwE{1|dBH~7h3hwwjQ;9U*;DaLJmo;Ucr8T<!h@F!wCQ?T{#9RtrYaI-zn
+zG;p&$#n-Cc4r0s8)_)<(A^sltlXkcxhWy_d{AT++Yw(+TzHIQD?UPOgBG92H{-oSm
+z1E-IW1Q%P&luTDQ!GB}$XBhZnjMJ6eTsx=_&Vf;KFN6QMA&1t>BL7r8fTbXEvUSus
+zjd5Gf=?1^Kx(FNmW;=*4GLldHqU!~g9R9??DK_Nv2EXWexy3JXuC(y>tbctBId2;H
+z$%g!c2HwZO+sA8x(mo4Weh<d&_UUWjW;<MN$f0(iGz#L|h~%7tKdJ9^G5Ezswax#y
+zQSM2Gob3jlZs6iGLF%;$X%zlq@b^Mo^f?$qpRWymQ~!88!lyubHfc`-H``~qft%-@
+z_);J}&33!a;5W;?nQ@!{&KUep#^7&^!N1qQ&3gUaz|*0twA-hK{2=f{_@f}cn5ccs
+zc24KXh4d%>UHGGL3gb5aU;{VXlgy=1Ab$F=K=irEz_ScoJ}V>s0R}EU3<;;XLF9aC
+z$O#$vw+2pYY~h!$d!$}{c;0Nwle=B7Gy^xw%`kAY+&%_wmfN3k84qVcCkjIiep614
+zftzyZ^E3(~CsRkA0)xL7Fsbha25$BXH;<Bo?|Qr-^B>7?hd;5cDR)eQZ{>FD$T<aX
+zpaw*sYdr;GV@SpOs$Z?Y$RtSSdy#V%kJq6FKj}kXD^rjS?ZThN_!yn6>P7tj$#U{7
+zJdgF47seu|g87Rq{!f{|)WSL1#Ahp&Tg45$(&C@U^HhU{(`V2WeyI<h{=FH$*}|nA
+z@3rtJIsQ8fKb`g8Zs9VXUbOJ3T<#tVPhvT5S$K%?zgqZcmh--aFXi~B7XA{C*RL#`
+z<{%2+>4VokH*kNcfrd2c#}Jp>lJye&3m%M855YrR?g<wEZQNg{SokrHn?74rzcc?R
+zi$8~Py6>YP<*sHu&$aNUSRd18E6Jb5`d3-}U$C5&7JiE=&9~(*<-X0h>9dvO|DMky
+z(`PH;vss^qE&0FXa!sGD#D72c%S#qN-7`=yeYO(+bId2t-b7FO$dkgCmYh;<2k8gl
+z@5H$2vz6qpWqr~(UHEBDOrf`hi*HNWwk-Tr%xC&+CHXINJD5IO34fh&(`PH;Z!<3S
+z5cz*+-1ON>{Ngijm8EAZnNKX7EC^6AeYTRE8<_t#i(kH2e$c|j$Iw;_ujPJ`4aK6r
+zJYQ+S>4NX(_D{9&IPTYO7B0Ks%=-e;e=zG2viM~y&`=8(-*snLIDO+rVYG$c&h0kd
+z!e8Kan`Gf~KRMmPd$1hy{(|(sPnC*YDi*)2OD?i-@x^?ph5v)~iCFm6T<%>KF7x;w
+zEIfzXQ*7r;e@$V&S1tZ4x!iXw{B4eZXyJ#M|0@gso^jgKLqW<-W_{XNxZDqPwQ#ZR
+zf3k&N#__=xK0+7g<XQLyJU(R)tLP(N;}=={7jru=vhYWEJTJHKVH{s$;dgVp$j(+N
+z_s`r84_o{nF#fcKf6Q`rS@=1u=erg@h2?x`;prTg`zg`qCFZBSRulwZrD8BpW8w1r
+zNPHFve;Mm(`l6-t;&Gn$vMo7tS)Y*>ejnrFTTkRyu|9Jx{!^sCEc_GZUuogra6d*Y
+zyd%edW#RL=UbkDgd|~jgg>T?;|7hVIxm>xwlX}Ve_^%fK0gj9Bbm13$<o-@@(WeEs
+zx8PE47Ypye?R=7j?`2#z2#XwiL#Ki~*A`sl*IIH4xW4NxoIdoUaI1wM<8gSuh08qt
+zw1tydAPV~}{8t+GuB)Qwdal=37XNPU-(waod!{?Ez9MIkjB^YB2iJG3g-_&mo6I<|
+z$tg#wF0lAT&P4_;&xDD8wSm+5B|bQAHgMu!L(B-b894F3&hg*zQS>QP+^`#D;Ueb;
+z3xAyXJMaQt<jDO-FUF<a$~b>Ni(jr^qb>dqSpGx<r+V#Xe5!#{y%M?q&NFc0pT_-C
+zWZ=Xv&s8rpaN?JBt@t_<{iU66u=po&XKprdvz_l_T-s+G>$Ahc%NhUL!hg?rQUa7i
+z5IOR3URTCNPkCNx`&t$L5f;C+^B4oCcG$%Anqc5muNg8w8#wWI=ksE=ffN6&JpPLf
+zocLv(w2*PBS0<Nxv4zX~#_KIP&vCi8Sol2F^S729`BF`Mxl+5S`ZE8^7XMwW&xe-$
+z@0kBHi~nKfZ%Kj?M1Bu$heXDuzQUhj;qtxPPy^?oq2!J?a4K>+ms@1v^6B4l3ztvt
+zu40@H)L*~l^Js&`FYjsZw)o%TdOc#`)SfwvZ?o`67=PZtsoXr)|1HL)ePrMM-wgg#
+z@JsmIz^UAiSpL_RoB)rLPP~mn<PT>&+rX)v<+_|>;H08_6?hKgR1E3gl>{QpviRja
+zcBREH>xAV7PWqp~?Z4K-S25mT$(L{L{$TOH$ozk__~m22*9@G7usk39n}y4mJ80n4
+z4%c$KeP`e#N8XRLVu92wgo~W+22OJ1zH%tz)SlE1pRxWq7M{=7k*Ss(`97|~;=hmi
+zms<Ef##dRm_!M7b$(Qf$9<cCKo(FbXa`L#suUfcVZ{CO@=VJ?(kNLC>L_PnL=!N*B
+zki-vpWjz0x`z6!D`?H<{8JBVUB%gO@Sp3<{e}TbI{c;W0tJuJ4{L8wf+L9ypKWi<1
+zWj7xAHd=TK)@O@>Q@PsMDfYm{kpFvwpY(a3+hLo5lN`DJJ#XN|e=(Q4$H0mIBA(yh
+zWL(-=z9Ib7z=@Tf#Z&mfz)AEWZqIlUia_m8^O(#t9SoevC%N1n7XCNJPqOeh5{Pgr
+z<DzGf=fiOp-oX0IGjLP?aswy*w=#ddh3{nib_+ki_#X|NhK{@ke8Ip;zI<Qxu7R8S
+z*gkDLbG^F3h7|=F&#;oB!byxvJETiH82nUJZ*I4I12@OB__P)IpK-kw82lvXCYDof
+zl`CI4UT*M{d>Q`@7B1s|lYx``qb&dC81f%9_|5VEq=Azh@qPY`ft%z1MFS`PGkJdB
+z&A7Cue0KT1ft&sHje%4D%2$zX`QlC0A^BIb{H_*$KjXIV-B%g!!~CL;d~KO);bhyE
+z!W;{i_X|r5+|+-Sft&jO+Q3czI}M!p-{*4wXyNj)toUvv{pq|ogg**@xA?R8I{3YT
+z6aOy74gY%lvQ64SKIm=FxQttQ?{b30FZc5~20!)7VQ%Ni7CwcqPty&Y#!nqp8ey)1
+zlN`A&mKZqki*L#r#zp^&xW4Nx{1(O^wD4ycf6c<>x&6l${tfdVweTMpk0<32M4yhl
+zPUvRg-5DQb;k_BpvG9J3Pqgq6jGt@a;`4ohh0kLC%MF~yVW!d=&O!{Fx<tN*y^(Pl
+z5At02PR8kdFN;=^9<ul^;p^#B20u5M;(y-ae}nn=Sa=(rKi{$NUvuGqi-C(TTG9U?
+zpI@I?{DL30aPDsBNDTa#h5w%A$MJ$z$`!noh4<llnZ9mGq~Pr={?6QZonqiUEWD1}
+zCnE-K`n08T<+*2ni(hclr!DdK=KeB$+M0NdB}bmKiSJ@*pI$r<Oo+j6`m`na|3N1j
+zg6Y%N#7&>Jgilc1*uP-O7rfNMM>D_a)0X52Zu+z(d?)vNttChB6&5~=+ig`0{3;7C
+zXMO5p;MZCB93Ce(#K3Q{@JD!@+!h0ubC&vxr*fqcUtYX<kJWUJa{tJDD0n&()ZN_W
+z3dy(dJsiK=##!#y7B0_ux^ue7m*)>T7B2VK=UKSiSFW{ixvzQJ!exE<k%i0k@#p(&
+zB`2<?S60J?D}1(E9$jmco7Woc^40LS8qI;LcFy|$neSG)PVsPPwwImmt7wYN5e7ak
+z9HogIS`;DB{v_%`j%uF=h@ZqbpRS1MAkW7oE=L{)5{>D*^<T{&f+UhD=bs4vSM%p^
+z{(+K_k9YI=F8iJ&S?VwKm=q)bA!eK-8Tlyr<ahyaVh!+hPT0lAvXm#d9iNW`lJ)QA
+zU(ESMz8q)K;s@bgp6_%_mnAeEFT`K8@pCs{IMRD*ZW=!{H;VqUuVn==X$#G%f8%J=
+zH-hX#*0JWiS0f=>{yFJ7$7%e$AXfgHV&q@nU+2h{jC{1qx*mA6`tRZklH{lQ)4JWR
+z|2@ELnSh*aT>e~&7{TU!8fi90?CDuL(*xFtY4iR8Y|-@pmi3o@BK>KtXY0QU7|E1+
+zf>hxZIx!LU^LeCWzOJIj>qv-}|IXn$$7zz0kCIQ0f8qQVoAWm3w{giQ_?MiYu7_qg
+z!1?=F2~vOI{S-vB_Dfx)ISw%+wO=RvNq%WpYE!F=bdCyr_+B5pUt52QTPiBv;7FZC
+z_BV7zG+Oy|nnx>tPma#N$tuu_;>+&^p5NDW1nudSD4{hXzF&tA9zH~;{_DP9_n)A3
+zq2C-u=HPnN$=OPc_zY=ukkIw;oe95^2hbg>;g@h@W)7&l$hyot9P{Deak4tD%bbN{
+zO-@SR)tPfarSx5wxmX=HX0B4l&6(@f@s7+})$#t!ht=`1%x&uUbmkr$4ex-fGwF5&
+z-YFYaXC4AYo?_u7c133T_{gCr9UyA^FM04xC7x^`&k+0q{0gQ*bsUrE3?h!SkEk-_
+zbu~S-Z7b2Lik^=^T^L+bYR{Fm32;hz0J7%nP#JqyJ4IM)13(C>?n+X$@gtiH2>L(f
+z`z@Nox0b<&p+YN~#MOxbpKP>&P+fc2C!3~^t|k^uYoBbI);`%Zt$ng-`g`K<qv;=r
+z&epW{$)@RJgy+yj39AQ}BIGv(5%$TZBkYq+N8(-D?>ARRTDtTx&q5txpKLn9KG}4H
+zeX{8Y`()D*_Q|Fr9bDQnSf?XtF6|#$t0NiOC!3D2Pc|K4pKLn9KG}4HeX{9Dmb(Gf
+zdO}CoC!3ChTw4D>$L_cKs6N0B{v`la8?|yqP>UF}c8k`^xdO264^5|P87+UMWwhK(
+z4W--pX0=CB)3;EQaX)%~-7W>zGWdH)Ou8CBRP{EOfFP7qQRo3d+v~BNFo{NrDlOQ0
+zXe#C~RYGg+H%!x>->^@>noK<GH%vW54fF_%1w`kc6X-D$zf9f>vaNdi=)_GRJWvO|
+z_Ap$5IFl71sZ~{$xCv`TP~3zDkWMlUr(_b;GB_NCcL3$M-RPGBKg5N<iNArnBSCIA
+z;-)~;v<gFT9(Q)92flKrcZL(2P-nOj$P-z-KERVoo|4_oDd5+#`jgfaI4Yvss>_Z$
+zfH>hlYDt$O_^HXJrVVV^w4^IFhZ)>Kcg5q;_ELts(@W8AMI7rkg9%=#!4Vwm3&GGA
+z&OhQwW2ik<)3Z>Mg3jcnYSR+Dk?qC#sYJOPx<g$E=_YTFyJgvBOx9(<VSzMBf+vOw
+zLfQJmJynl6;MT*3?nBdQP+@~~2Bjt3O+!(W_Ym2OPzs5^KT#9%<jzY8q-9Eq1LNww
+zliMc-lDj37nf27p7+jf7V&a*A(40(Se8zWjwBh>kSW34@0Sg8N9Vp)FB!><`&tkr^
+z;+|lb$Om_8j>51y*~U*4fvB46j&Dzf?%OCc`AAIG=JZoMv+b~kpPr~K-KY8n>@mQp
+z$=jK1<J${kd($L-2a~6XLHv%sJTh3{NgJ5IepDASH{aPXa-Zf~cPCT%T@V%9_=t8j
+zjKQnw!>)g*JxT0N1it_DE!Ur5*r!*#J$?K6>EbFN!!J%7lke5kIy{W^HwDOCe5Mb1
+zeT?R08aBFxlyf(_X-_pDAk*!BMj^#yIjk-Unaby`mL)N{JcH3tMUf(YyC=Rt$ag$w
+zmXIPSx@F0?ID>Gz&TJuRRZRglb2ly7qG|tEGWuLN)njsrOf;d8eny<G%`!@=Ji==2
+zFHrv}Z<HqM2gT!*^6FyYRYMxb1DLpxj}P<lk9?GNwrkJH-hp<;#X0mn_5X~;%BaRE
+z)jGYHbX0a72f`2|6olDITE8orY*ke=Tr+=uNhxSFn_+mesg*{^DXOBpU{W$c20Xix
+zxNLaBL1VhrT>vW3&Fv6KJseljE;tYt61$P%!jfPqkz|OlWEN4u39w8!mFyUH4c5eE
+zkZr-r^7)>%H`A(<Wrb-WOn{}6oi(;GNC$1Vtg^JU8kRhLezF;+%-DIh>|j=_R56gP
+zKV?8_Ns-v}VydvFXo2G!&w?f}tu$X52J{TWjXP(0`sh$7{j{vXS=s3WvqM9&hhz^=
+z@4u*~wxZ;W1tk?FRb|D97F885JOlmJf5_nU{tMFkPa2rszf@V{>QB}XVdJ2(sy|E^
+zR8}nbS?26~D|>J<S6#6f_C;$-3yT+C$erS_aX)Rg&8vOsVy}S>lYI+3wC3W%`PDU4
+zOKmxh#tsYyR+BL@YE@-e%`>3LroUiCYcTp^K}E^@bOre>?y*vL!PEnpnrMQNP`0J#
+z+m2L5CWj1Wqm0`Amg*|s=$3SfvKEL4^(L8=t14Nbt$`Jx&m6C1VCxI(Af+6cp;%l}
+zL7Lc2CkDr&m<2<_EGnz0C8Mq-WVDP-hn<FlJ_S_67Z#Q-s)=GJ4L0)Tm6te`Fo9PJ
+zOJ{{Rr|<{u#Fl0h^L-Gg%xO~1V7aY!u^y^)7Q+5nX?f8CSm-NU1e0K@Th#c}Ed(Q*
+zWstm}qPDou8`(>0ilBnm^^mG8rl}ldFe`=%u}#QkrsBM|QiVE@4hx>z?jQ9Xo~2)i
+zesac*9({UxpXu{p!>?AK6#a+Ps#s`cXh>G};H<%Yt&@f347F&+(Y75%7s2ktfFM`n
+zbkNxZAgC3wvZ*yb`A|aK*V?KU42i`EbP@iaurWpI{Ct~H>ei-NO@6*@C|S=m6&3JW
+z)W+#aRr3(r29)$((>wuvU)2PpM}%bCM}qWeYXGv~ku*Be`$XcGG`Rz!XKaEIpM<_3
+zqTxeg;C!((<^rCanoS8!&v46*qO+eBpi3XMhJ0iG9^+I$^S#9(#)+S9+=Ra^Hx1!*
+zb11kBXu_#Y1Q(ek-(2&^b0EUo;O~C?QIMV${5mdA-8>>)aOomyX9~ndWlNxTra=5s
+z7R9sa2SMcA&GLt8*u&*pn=>u^L*^f2;m>p7`4%qU*2?Nx$~~F+iY$Klmblcy53&4<
+zEL_$yD=mB&#~UoXh~@m!!b2RFRjugxBG>mWi+?7^AGdJvXSChIZ^n9z!ft)=+WA!0
+z=WPrB6~{lY@F6Vcu!Xm0Imaw~yu`U4QZE@doh<wp%r7>*gnt;z7h6MuFJyg2SaRAi
+zF7NDwU&i8ei(mR_o`sA1nMw;^!SYvFcpt_i7S7dj%x}i&yj#S4w_E)3uIph7KhAL(
+z*HSO}7EHda5j@NVo8OF6xmR&}n%|5QehuU1H{*m~Fa2xj^Ek)NZ^nuLKITv3qv(^(
+z?bF-BWlzf>3!lLJr(5`CD1*XS3t!IqOttW0#xJn&zjFK+7M{!Tr4}xG9#&fT*DU{P
+z3%{J>;-N{};YQ{+za>}g&-mXhIZJhQolh<NcE)AC6#1K(PrgkTypH9c!0jsdTg-o=
+zg^y+a0T!OianqI*>HjRt8E5fJe=M?a;a_Iq=dqlP7GBEuO^lOz45^m*oyEU|<4+m5
+zxoX;G$&vNO0fV3Fb%5L91B+kQ5<gn}cW_*63{X2$xx<x~xF)JQVgEWfk>z(XaN^&@
+z{M`+l^eJKd492A$Ze)Cn!7pnAN-8jLlK&p_%eP#jXAjorLW_Si<BJ)Wa^*pdd|Pbe
+zvWH#d%e?ujC12J9Z&>obW<BYZ8U>OsYa5Eg=YR@Qt~}AnU|hzzJZSD`;rDQV4YhEw
+znL}<TDTo}wM_KqqJQ&AXct27MA>YD<e~N`a!g8j^z|XVr)vW*A7&zIeq+qw3v?0~Y
+zd_6DYTG~@(#*f(GwDELiAhpf&aj=Dp-2c+OULoxDDk(3@(z~{z?dLL*|KHlwMeS<$
+z88vAR{UFFV*RkgJHr<dwr%aA8@bLiMBp@u)2W9J#%8`47G{#TDk#HVfj5?02pFDsG
+z;x$7*L`depo1fOj(dz%NmY>7<2jXZ3$#3f=`pdBZnS?g;&tkBI&o@c4c_$$uTKmt!
+zy9^3JI`I%X<B!fiyZz?^vt<Hu{>UfpU#&zd3g3Cr^Z%L)`jeHxiaHg@A5H(c{H9OF
+z3F%K&vGuQuQGO}cTkZ$Jrh;8Q-B(2`e;JoA`Kf$b+uP;SeU>c~kn<}pKZhbluzBx9
+znvD_rKF&YWO0=TRt>BHO|J_mAkJcWx{=Wl8GNqm%Rp`$*GP14_T*{Z@(@2Px|07=L
+zoF*ChDEZ|0Jm<IAoF3jp-ZVw>2}<{sgqha_N=xVblPO{ZslPyPf{50B+oJS8Jy((Z
+zGA`Q!v(IsoeTehFM-d~~`bX29*v0Fn><Odts4TmDT4O~ke-qEY<B)C!yZqXkvT}1%
+z)j!))H7GP>&_K1R>R;beHMz#uAV-lou(R9M2^Wlyd_6rc^5e8;2@SoI(sLCNTd6{M
+zk<UM($eL}nXN4o@(PpMg<G0dT5jvt05N{R69;PG{>|c&aZVtg6&JUlrqco*wE=1Ms
+zaP#WEPpWx3uYTlzkkC&yr}WI>@~2@hRpk3;;?T1Bkq^1dWrOlA-?0;%kryJ*=SAKQ
+zZF?p)f-lo4^O|kT#zel*Iz;x*@yk(A{V;XNkGz`~X?%wGL))IE3Mn|W?UUV5YBk{+
+zY0j^>L)#QTmxF9Kl&%lY49^%JIToHCE(k~7nm#Qr@(uQ&J%KLGt3QJTHrXadD_xet
+z$>GRzN@!lg)0ww|9jz4K1bBwdqNWIq`KE|hm%N6Jndww`!(&QZ=(u9c^%^k}pP91y
+z1_;P&sL4zhJg+`CGkwgO<Fx;5E=BqfwUDT6q81Z1jHqQq<>X;E-6|4-NFGJja%3_^
+z)+2(1Ss*uoOj$z@QtIYsmLJV)D9D_vYJ`$Q@8ma>XZBPIuGyBdamObmrRzhlp<Ags
+zqS~5mksT>(&wzx;cEzv0@LaV!ND_31(6~_>?D8X@OSZf<+b;Vg^0s1DoKHalw;Fd~
+z{ff+ZjOe_`cBR7jhOxuOU%vARuu(;Wd6DNo8M%IBo0{^Gt!ozM5C5jRFIuRkM}1P}
+znip$3QEn+z<xhD$H?!y3F&Np;yQ(lrHB?HuhDO<%cNA~!?IYVP{q0sa69uN+zP;+D
+zk!@->qKKVi&}OTz1Y>=N%r&poTt=;yF0H1@qVA<`4!x%Cr8R~o4}Q{@&)2&A%<|yD
+zb;ph$*XJ8I_QB&osJ(E4)vwE>@ra#-Nxl1^w3IbhQ{69rjz%w?LgDkn7laFUsG8C!
+zRA-JVt3EyxJ+`L!`0?X0I_z8|MYc=xqr14TqBKg=ep2!ec0+butGZA7Y<+#=ywuQ(
+z#+ig&lA&#pZ$n4MM-CkQIPz`dw>=xbYuR^uUh(#_*FM7V$&18i_I)e#TG??GE5^uP
+zks0K(fkthbzk#wvUfpwj^ybOZ^>hYf7wHZ)4C+1&DkVb4BhQOA!SRvCyvX0Chl#^^
+zlHQ`IIz2;_oZEHJrRC8yv}64=wR!W|U1&coVGU-s9W@wT`{(RP>8aaPbt32e<b9x}
+zSu!7yIy$3l0F`6?C8>EBk1Zs1&OuTrJcFj9@sS^Re!*1!%{1_(to{b6_3F}(c~Epo
+zS^Ws$ycaO!5JJa4nZn~Iuf7K%`H?U38y=;raejoS_%+*V=H)evL<P?W_^#T=ny1Zv
+ziPW0qdG(hfQI}TVpCmm)mx+9r=V%DIIlu2md3D>|yvP`^ek22quMbL8J*J@@P(jOm
+zp#{mI5IJ>B=(9P<#DjE)-(LB;v^nP^Rgd5u&yxCioExNQ$x7EeniqLN)#Bhk)X9+x
+zD>`2L=VAPXj^sr?v`3$kQupognlnmMzSxGp7Z2y9oPtyEaLNTrQHmyI9!{CnXpOf{
+zYP@kfA5OupEQC+qRsx*~MHNn))=uy2Vdb-WXAho5@5L)hmY$vtUux-<rRj@G7FAX)
+zcgB{?b0!v5IpM`sI4*Z4)K=iH+zHn%aHf?kb|w|qIOkL@adJzFNjmK7Dz_75rQ|H(
+z^z`DQijyG@Z@SZaSD%i*sOe>u#Wm%^pvC+j`aPr;AFEbpg@2EW9r_F*NE3LI_evCZ
+zE;F8B{BP}LZdrE$#Hq4ct|l@rs6=a|-cM{GvPDqi_fw>0@IK;q)%}^ul-lZqw*Uq4
+z=d?<{f)1L_Xi#Lrs$jQI1q}8e68BQ0@bd%y5--6|iq<8l1gXLjdQ+m3k1el5(H=@B
+zZ+X?Ux8=1Rl9Px>Wldak6S68YX+IUim5bAMELsN1PF5SLh2m+GP0#97N&Az({7+0?
+zN_z6)nc!gh=$%Ar{9B?^HT|DNr)l~-qSH0~J<)wM{R7e2n*NdKVVXWhbPmm=*m>tt
+zBu__N6`8CfaVj!PN8(*FZ8}#+TDoM<bfJ#$mTVp2E!jH4Te5Y8w`A)GZ^_n?4(=I{
+zR;MFr?nFe^>IiSi))Ba<g`%5u<P;UTRYy)$k-K%IpNc%JBUvsz{Cz@4cuTg9gxqN;
+z=Q;fvKKWOw57Lr1Qzdm9-Ap9Yw@`Jt4{oErNyS*Cdykeu>cH02p`^ANP=r!fDzsQo
+z-cFq|Xasmw(n?8cqX$E3XPUs(xJXSSE=_hJQmHpGwL3l9R_djmpq}1qx+l@`nocKL
+ztD2fYbdtt<QE__cq@GA(+G;$LEVT~SbZ?@EIjxD69*V2#^mI~d7CFP(uDM^zZhMtK
+zJln1%T9@56LbNWs?bSr<vfI`Zt;=q^j%aOluWbX-dI-0@hUo4}kG9tmt%q~lU($)M
+zhjZKO$m(=9&M9cZuhVzMwYy+=3vQHlbI$~+8>n3oHN94*-Mn1jT7h=OlR)c2+s!94
+z8oHo%C4U303u;%|6;n)hJKAv7Zb3R|ecrTNSOJ+&C?(sKWdq--4Mt(}IWo5lQjzN6
+zQ_J840CWT43~M*jrDD{uYd71?r`bzK&ULAxnL08@Mf&K-c`8dbL{1kuliL-#q@rdh
+zGUd!ukqn(utmNeC$b6M04{~l6Ioa(NxKusOP-e>cg{jYlimMN@k}VK5VyVVzOkAep
+zVZ=Mq9Evxms!Q6HKZ>K`C6DcjH(hVEkL#p_2QCKQ8Ce_v)SY@udY~`0MBp|gs<+pH
+zzLdr!C3V$&@x91^dEgD<i|<8=iZ8wwO%F_}S3YToJ1x#ol3U>n>PBA{v^ayw3XsI6
+za<n)j2@GAGq&tx%iON=)+n+-+1EZ0q*mRspujKaU7{#e+Hc;yo_oH9jk6w-zKVAX`
+zH0?zwDT$c7BkH()=$FC@eZYqc#TadBiRkuG&4q*$a6Y<yD1k!HGRHlIBvVMIW|tt3
+zk=&uJ!J8p2FM3J(2^gv;y3^y9#Gi=I9<oowM+B#1IGQ4e)jfUuPiJpsX7{9%MF%9r
+zEy3>;cM#Q<=9Jz_WG=O{ga?^$H}AnCofE3CPd1k*3MbUmEJswTep2at#~nwt&7^^3
+z26y}sQuBI-Gp=UBQ;1APP<2<3T5w<v?vq8pXry&Rk*Ya#dTIoE<NF7n=^QW(@|cv{
+z7L}iDJoFJsC5U)p$vVSQox>f3QvGizNH#jz%l6YUp86>nUIj@%T>)xrIyrS?FESf@
+zE~Y37?&ejP0aRlzlE&8KY>_lJM`djF#I8rT(u<MPVIztUToy|?eN_P$Z9!4^P-I1u
+z=%E#-sMIPE^wZH(iygO`F0X+N4{^>K$*JYmwxStf!^4;A=n{^uOsC02f_Ez1*e4N#
+zM7*|S$fN#@N9@sZDL1AXEpeBkVeyF#POzv_?_K%dA@$`q{`aJMgKHh?(j?*y&`n4o
+zQ->Hf)P(-Xy&Va?{RBG02R2O|-840~X=+i^)IomggOGfsPNg}gfXYSV;;_<ZdJ;^x
+zXeK&MJbj-B{znhjxmWnfdyxEhGua)eL?1GE-T_Ylulc>HfX>V*ZniIlIMSPN3~ri8
+z#s>ZDM&bv^Ih_-i7-}B|zC`0KHf&t6ktSSBjJ{N2*laV%pz~@^)gyy|e%ZQu4;$5^
+z=KY7}p~_S9uC(e$g{9);hZs+rCNq=S)zlaRHM5>Mqc+#1CLBhKQ1+^(iO`0oRc}BZ
+z0}EgO_RINN!Gyc{D`eIa(SAAaPpw(vxNp+~mADO)y~b&U)z<sEBsH$|1q~x?Dp9lI
+zmfA(?$?;Q}w5UXSqe#Ksd>7u~sLAnDnH)1|(P0Mn^EF_~_>SQWadndMo;{begKE@g
+z)%Y!N&!p}MkzSx?`3-OAmw^o4wBBFm#t7y4{5w&Jv>C)Ixtlv+lIuwq&mSb+Ynx#Z
+z@fDPX5`osc;z)~-UjSXDkfMf*sZKu<?aDV){(CZa^Zh8QKNXeYHY;l!%9@RIU15KS
+zPXm5Y6uc04#K*m1aUt+5uAD;=QXZdZYX4h~+e_V@3PTtd0SfNs6?ps8zZ93FUM?-H
+zDD)?X<%m-fg=|{byO~OWUt!Gd$lqJtG5Y90`nbV8$t!FSEe0h7nQ*h*TD+mk5G&ys
+z;@&D_8gqNSxm49eUHqNFlzkGEQV;OlL8@rNbbPQ^=n%6|VsLZZ&wf^c>N8O~^Jrx`
+zltfSvtp<BK3{|UiO7l8`mL|d|9f1p?0bZ$lM_nZg;#MNb8+pG(QYoa<kUQNM^BbLm
+zzE`ES3ay_9P@(QLmu@p9R5Iai{wrkY4w~*h0@OV7AAm5j(?%n1sVXVk*Ivyot!YW~
+zIat&kNur~d3cUiTncvfGsElD$Vw=0^eqWRK5ILOnaN_>pksYqZVp)ekH#&ML9sANP
+zy9%A=yB^$mpa*x@<a%_wFKN}SLwpxHdP!~04S2cJ-t@_LeDa9L+$q^-?lQ{b=rYzL
+zyZ+K+?r^oQK&Ok`kzBrChlF2vN_A6-Ue-=a<2;FNx5eUWx6?16-G3PLt3Dm~55MLu
+zzG_nQxC4HYRes!Sev`Hy=lmCaAKdiA;9%1agA>}jiHWBtj!<91ww7;!6XjdrB>gRL
+z8~u%Oa?`JfQ~a-pQ&C9J7t~gj*+S&DLq7gmm%cu3-yWYckL-en2%c&!T#VO_^7U;e
+z?|b1ECwHN5iYc`-e=3Ymm~jj1ap2=*|EuFJ{^!KF<xNAo<3nI68dqX7SCj9Md-xgY
+ztKk#;TomnTd~J+qy8Q)lhJ0<@%m2*yMC0S-O#AcX-lihs+c#0=B)>3BHX@K(ppXBd
+za$o=ZWcnQX6e9`+PxVDmYCo?uG-s2t`g1+erc}=?T^fIWJ;2OnDVfbBP)3vx;_^8<
+z&`5>YK}LJ2jvkyy<_J)u(~Nvz9AdPSVjP-?bD&)-Vjae;_~u=Ikv-i1+M33h<DA|U
+zpf9pVG=W+;&PX4Sc>zZ(A5_5i#X=T(&<r8xF{Hn=mKa@hD7elHO*H?-)l3D~DG;*A
+zgU%CD1nMuXCFYAikFzv8h|D-AdyCMrx^SIoBB`7+2ApblOBF{%yaH{>B4nVKb4mOb
+ziJZY8+DynZO+H)LI0mNr`GlP2=WDga&bNwzjeJCTLf+v)(}aAUp?Ify>&h(>d&xtw
+z$l4;YqkeWF<uehTozuO;DyBB@5&bFTiym~IkW!59Pl-thuG6eP*RYHm`55ouK~A&w
+z5H2a%P(m_Bk)4f20);7jL@Nr}LY|s97YNzNP`tBp*UBvtd(USSGL;uJno(lw84cpo
+z{}nBR!@4)Cgs8L7Q>Q@4HeM++gcJpIOG-?1z=<cM6s#F_js4%|g-($|+p)&3Qz)c(
+ze<oQ|wn$7$0HZHhQ`KCTrCyyT3rX)JD4=7S3u-nFR<nS$z91o`_<)03Z7tLPZOtv0
+z;<eypA<y!l8A6JomVmRw-69cbTcb@|d%DkPu6wg7?;ou5H@@yd%BL@J&QeF{f5d6^
+zY3dUCHP)5*gq98_KB4uS5-gX&C$wmY_F2C|BGPEYXb1T|NqjcC&SW9)W!+jii?KyD
+zn6brH2E1draq_)Jnk?jOhP>={(NfMsTn@wu`Bx8`Cgi&wG(}37;}<Gqy$8vh>Xka5
+zdqkSqY;y7Bi>rl@G9u!f(3Z2gNAB`Q(KHz-(ivvQh+jNNlP-{U0^}*g1li4@K-*g=
+zP=T8Ae{CMuIp0szRCAVQ=ap1rjyJ%Xmt^xqDXBS2vy$d=H!S93v^v>5QA%pg(ySyI
+z+pl;XKV8UU4ABHOy;+kwEp)qe;3F;wLW*BBTm&)uON?GEQiyjJ1J$(uiv_a^WBB+}
+z23Ks}IOoiNDlf{wDdnOT@)75ckmVjUO~@4<G+D?x4{A0j*K^V)k7c@$PkGQZA)oc2
+z=|XN}D0<^d>K;F%keBiUHe4!%yn-PuOJcwC8HE&wj+#+oyM0C>#Y3)Ul$guUbD}IC
+zMB(>5g$snd#1lV5NKui*7i^K(wLYVeqM~M$nD|G+MMy|dQ8P;HLr-FXM|yQ=c4^XE
+zYjF4G<(gc|WQ7m;Lt0Z(%}>3WH#-M~Mf^b~(C&%o;b*XlS4i;+?m8DpONt{fK+<Nf
+zc{QLt1x-Q*C(%nY3OG+h&^jN|Y5s2(Cynx0n$_E8!Fn}{4JYC9i^pTmra^{-U$17J
+zN6%~Z1wx)nY7yqvEmNr6ii~1V?mn8G>70HQA0vER$46OGbJRP?9M+46MQ=XJ{O2(;
+z5#(l+-dxM^d-=GHk1z1i&M&?|PvLZF)gc@|gOAc(cK+XBNX99P{y%9^${A2wT{WPr
+zqPV<ve#wAlW}xPk)l~lz7TBxN9I*N{U_o(lb0MdRd?zc*BOUd@LNTcg<1fgo%}A9N
+zSJae~r784%ZABT93~N!0i`6NxkX<2WC|dwSO-z@R!weE=v;lJv#m1^YLaa7cg)1iL
+zvP$q`wIp_{KoVL(B0$%aR4pp2Bs*7riGWM1N=mAV=9kr0_b)ClgUK5(U{JvHQdz}<
+zL7H1fv>3HB5+us^Y6dYSRaF&KK4g={qoQ)n?H5W#QLAXYsX?tKHnRG-xBMm80hX{n
+zbjb+TmX*Pgi2PkeZd<u^cF);P9Du5Qfi$E90*h<Fm6}D=NKhSi1(GKOS_gO4o*5{;
+zKkmf#fi`%%(!Ms(p%m!)z>*pqvSwGGaqg=8*})9_>lIuW481seMBMcDW#_(FJ^NR|
+z+v4L<h8wv4vf$QuSCOANhvz&!<AUIYfz$~oGLU%xRp&kxoE;w@_;Mw90>_-g*AZjO
+z^(_wuQYM_9|EEAoFg<u?;L*$W1<DTxh8_-_nx!ON7}r;c3}!#%74$AuQWtcqdw5Q;
+zaL&Xzfs3=g2~B^$<m~Kz`)dPjg7?p^K0Cfe;I)<eP~3y=1VvMgA9jQ9L7x-fA92Ru
+zOM~qLDetA9IlHcI!|XG929jo7UwJ+_3*Q6d$yfYx^#ipdYF7i8LTx*Ygyc;CHRK9V
+z6R0JJ&$=#9Srh0GyyC$?WiWlq>ie<-ZAJ!`2WMRpn74K21A$ZG`nwaSfAgE*SHXLJ
+zgYS@GpG+BQQl_xTloHGyl~otfCK2qs#n2guy)k4GNf~3JS2v4_%IT|Aw&hf_sBmFr
+zZ51piRW4fW*)E%3R$K!+P35&P<fL;Jm6sJ&J2eZ-s=;4fQ#h}zVt!#6%uUU&a*E3<
+zt4kbc5CZq&qMC(HHQPY*`I%K4L_^t4jh#W&Mf34d?Q#eDTwGaEVwgv3YM2WqwaUtC
+z$|?$rbv23$%c>Wbl+1T3;GIFvGN-h>wt68z-{hAz%;p;dLx~HED(1ri)_;f1G_s)u
+zYgnHBDmoEqH?`jrWEG4I%W3;nNFobyo<X!lMT-ZP&Bx{}bYM+oIosAk>q^7IT9__?
+zOmVT1u|mUkTBVv1oZ`xg(y|4xELKxiSy8QK8;1>lG3ZpNk;5kH^k!`os%HylQDsHV
+zLQKsID;JdvP*#QpOgbk#dBBp<lgA8bHg^rc+}C73H}xh&sQDA4NgY-1E~+jmR$IT-
+zKqEm8k2chY4X>%$lO!xJ!G7~5qW~7$RPCWCy~u=hBnT%PVHo6#bSpODM^Y_HtgM({
+z-Nbquoes!Uys*ll?ddo*RI``klEK#Hq8LGgMrGA7N9WWOlM)c94Aa#VFDR+Oc~_<S
+z*f(Sbl+r6p=hNu6?6r}dG6zFg)rNWk=M8uEK;V^nXqQ3;4F&XEjiXOZ44=v>YHR9Y
+z2Yd5r_+UKIL0P7wG|E?w)<-8`r;=xnkapjzb|sB)xj-INg5+Y56jd$PCw{f6hqiJ@
+zgSD`5zBVx@Cm=VRVQ!5`Wr`2ofz&1<mBNroqZKtPFT*)rtuC>^DySo%FqKeMsgx?g
+zY_yzevqa@o-BY-@5)uq^j5SLN(XEtIom+a~RLiOWjZ^IC4-a&!sop87sVrlmi;>qG
+zC&~&RjOERz5m8aRXtAUFo+b`R(q~(t9&V~b3iXtT!qLoVJ2Fn#)S{hg3$*@%MKw6T
+z9G<agoWgh>8Rsi3Eh;OgF2L+tyr`)9LI*XXk;+E&*!msmtr|e-h#8os6EvGT$H~@R
+z5%nB(=~C)asI$0izN3~3INJ+LiWgQoVnh&%cqR-D`+Vp*HDsx$#cm@hhWVX3K^qY?
+zh6t%tHjfMss^LY&D&vFt3NRm50Lc{LAbl9D52wj^#f+p*`NBeKH98|}D^P3XLKUd?
+z#l-{`R?J(j3ZTgoy-wK|U098(p$TQ!nx-LXE;P&%ViLwk=We3@gRUrV3CSTli&TA_
+z#HgP>ZM{ni#G9ro!Kbg7O<@cZbO6pm8uo@Y$Xbk;K?6|%KAqJ$j3{ZZ=NDD^|7zQW
+zbg$E$7w{|SI4U`HU0iN*+LeLa<n+4uxJj*()5a#Jj!F)W!)q_KA0VIkA8g7WCjQI7
+z4pWATo%oh9?_4ZBN%pmIqmt9E35-cjZ-^h2+-F^j+~n*lTZWT|)wP<Cd?*ljCa!hz
+zuyAsAIJwWL<aF>N4}>XWh<Nws`8%v2xyTzgzqLxGdb~#%!X)~E5?98Blhf(~=Om|3
+zP3|);IeTt$T5fV`IGOJ1NLB|dZz&9-A7y`W4us_<Qkp!!&-T)Oq4Lc|JfHKay)w}6
+z8md!60Q#<rKRdb4l~kv?mT`BsPVR#?@#-)xu^0$i)kDrs%+ow$n$`1RE<^3ypn4WS
+zwLI#9=z-Y(Z?XwVZS3kV2$aHe)vx{u=+7_=M86fK&F^x@El27L-W0F+1*b^B<5o%D
+zPi)(g(c3SetP6VCJtCm@_Iq(50{CntT8L&VlK5iVoa`7)4EXVSI!XxW&Gb!DGF1$(
+z44R;LNzb?it7yPC+3zLOI5%xts<{9d?MsPP+fgy_@hoQ*jug}!fg?R+i6&=G47?}?
+zz90s^ECzmg416tcs;`{qYJLLt%NYEdV&L>JIa<B$ih(~81AjUOzAFa)Y7G3(G4OxH
+zzz@d2KaYWb69fM~2A+h8iP~A-9jJL5ykt``TDy@=FEtMN8JC*N!GBT={s&^<{bS%G
+zS^i{}ujYQpC!1l>^qIi?>zO|rycEbbPc(jd^A!!J4^*Pzg)#6|z^NVNVYuweygCN|
+z`WX1882FYL_+7xM+*E$Ht*$?)?;|nzW!22Ld|13>4H=9LJ9-sE^l463{^*eY9Zbs^
+ztbpk0g127Q_o_(13Y6E~>Rv;yMD<gGW~)|j86~SSl^rPE@Zh$E*T8)DgLR*GXW%bS
+zL3t}^e)!?vj`=G*^#n{W`yii|^7>Y(*@~Q&YWi^m-=YwpR-U}JwpWPy280**V3r#h
+z%4e+kD21M^s0AP*e0wfYzF*U~d$Q_;rgVSGPi>INyW0Ta-&txeIOyNj_~RiC3R`g1
+zuYL~R6|~sum3@kMWa!X_Lc!%cweck^hpxQl)%SYFiN6Q_M9!lIeu9BNW8ggve6NA0
+z8~A<$r@DxIng=ORea&m;7Yfz&?FCx+U5tAQq-Q$*1P>axDZf4ABA@b5=xOkq@@Zb9
+zK=RFcsW0Ier)#{FTVn9{HgNhLngYo=34g+0W8fzL8UsJs;J?AZ`xy8=F>qx$1bkGk
+z$^V+c-`9}ywt>?cMf5yu;HMgRH3>$b1Fi9ezrn!!8~DR9@aGIX%i#Z;ftzwZH1Gii
+z{}BVHYk}w^His$M#Anid4+7z4xwjd(S+B<p+-$cVcwIn2&Qp#$y_m4eJ=4I=dYu;o
+zFE?;g&npbvl(WvjL(ogw;edhDwN>!%4BX^z%aac2f11JH)xd`s_^FIbJMd*n`EmlA
+zYUiN_zu2H8`NIwTB1=wNq*1ukD7P2lqW|><KElB1b6^T2e<c2d|4sv^EsKIbYT)$V
+zQ1F)xoSKT8%Q;}-!vB$h=NNJl`Q04pLo$TFhk=I;e7J#|<(_HaIR^hZ25!oqZsDT;
+zJOdwP$cY$ux`F@7z|Ho#*}z3MvN<~}T+-gL@NZ$Dhk|@lMC~)$DED)VU*w#^1C02`
+z82n=mypw^~7&zU<N&Bnslo2O6=J<cw=tr}@U{isnMP^ZPxn>D|vS#zvmV(n9N`da5
+zDF{w;8HIH9>*KNxra7E~@YA_Of#x&{g3~!bVVFL6_*op!v2bc@3VHhA@sH#9WD7r=
+z<FhPW)*0MgYCcS69y%m3P4h#0{N<3s2y%W4-i{kp?!W~vrVc{rq7O<>h7>|`G6mvq
+zrzrg+?IUu|Wckv5f}hXxJM}dM!9U<a#%S2X+cJN?g`dLpnr7j%x!fWP7aN+T7Ea|;
+zxJVzoa{F-uue9(!d}7pD_*Uk>#=^x`_pdGd6W0Gh8)y9=weZ`yeV(=O?^&NeS@<g~
+z=YWOBaeMw~;a{=-vaXYUk?W|ruA^}!w&P`8C;a!b{8PDpf*)h~Vw+lU*<OB*#Xpht
+zn`7bo7&m<YkUrg+ugc=TiQC~)3%{D%&GZ34a^7RU>n;8hx!m7aINg6!kfYQ~_KG}d
+z@n6pK<MS4-jKo0BUJI9<t^Z-+e^8~uldgsT$Z^>SEc$HVeu?98BzOYrlVahy++W=-
+zJb~M@uZ7EbKE%Q|vp%COd@t)W*}}izemUR5#fOLK1AzLgp7k+(01z%=wIxSvv2L(%
+z@g;DJh0ER{8Sm0=vW@Bqi(jta;_F2C<@)`a#eWC4v#i5~|4pu!=}Um>CD;4!EIF5P
+zySd!1BIgz6lkNS2%O0mL7Qd|5dt3O&EPuX*ujlb|nT5-?!K*F&R^}Jm?4r+d=DXG6
+zr{`xBWL^<|*%SSQ#V_OjISVi5_S|FPUvc~V#lj!u`jR<93Q{gUdQ;(R3qPh|Z{aHZ
+ze`Y?pZV3J|_xoTjNAL`e=UBL0FJ(Wv@ULPy<RhDc;Nn|izJ<#cciAm1{0S^)g~dOF
+z<7+K^G1qIOg>T{Zxz)mVYxSImEIgar|1k^yp5-@MxXeeg@mloX%<}(i@s~6HzJ<%i
+z@-Hp?7u*g%TKG7Q%ls$h-o!Y*N>oAcwOnq03zxl&r(5_?Zilli{0$!eGb~*8K+3q5
+za>sJJEw=byVEJ-?C;Shvo>yD^Wc`G~Ef!v&Vdp*zf0yG=Sh(o(yoHNCuUWX1`+<dj
+z!S(ve!vDtY?{L3Ky#_O18w(ftvUgMXhj4w*xA+IJoC*t<aVgudMNWwIskitWxZULX
+zAp9G-+}kbw;XF@1YT@~;&odVO0GBJ9xJCYc=6loPpThC)Eqp%5+j03KC&2Q1S@;6R
+z`&&4@=b<pn!Y^d~b1nQ`?%!Wnc#v^fH;F!Se{vP`Q#0}qSLNPf$+?d8yxYK26sP`q
+z+`<bvZHI+F!}!aLOSxH$e`xW``uJ0eU*_`^zM&O4f_G+|>MQqdRK!UJPWsDp&r>Zq
+z(})>if`#|iu=5K;4y`M$<;JVA_*XIiMuVTqy+g*Wg%4mkk6UuCVmZ$k{8TTwZ+ykT
+zNxt~F+GpYN>Crou{2N*RQ45!Ka`yzyAnm-J`3GD0n~aAo{4b23W8q&hzR<u~1(mYQ
+zz^Q4(_u(1~mvzoBE&N1o=lczu<fkj?j`OsElYF@^ev5HAU-G$M{%-Nh`(KwB5$Hhe
+z|1tBoG;kUxWAR5J)xe2g)^8mRocK@R`J|_T6aVLYUiY`~iF}@pwD4asKHkE2Gk%VN
+zQ@MZVa?iJL8MoyYeu(F#B?eA<PG$TO11I?>@%g;Qz==PO%e~sbiC@{A#&M&86aS^m
+zf0uz1zwFI<*uaVZQ|AA@ffN68JWigo@YdWuZ!s?8U+!BD8~h}HHP`EV3zvB_J`qd^
+zluZ18V*UiiMZSDt*x$ls-6dOjM9$|dXNo1i9iL3+TKH*<7h3Y=d&4>lpUdrVizR0k
+z%lWN^uVDOP3*W-{?=AVVo_^E9%eY_OweV$(e_`SBJR-;s@}xa~&HN`>xIA~rweV+|
+zf1ZW!WBe)$7auiSEc^)bKV#u?zx}R-%YAix8yY40c_~dLGH+*CxO^ddriFjP^Un+m
+zm;2tO7A`*SZnp5dc%EsraOEEZdc9}iC-FFmOD668=e-O&Z4I1M9K{KPEL_H$Hi7K7
+z!<EcmZSl+gkjojT^Fp21qy)lMG5Bw>_@$k-5o7;6-Ol57t0m_>*5?BYmk(OMw&Z`z
+z^UpDhUmnt*K$8N3oY&uTxhFGD!-?8W?t=yx{InjJi$4ly8aR;?__{UD!j~{U*}`vP
+zTx^U;x$@1}CCpDaP4PVaI9D1t>DiIz|LZJV^#83<F7+3_Em7fj7QgJb*=z6<`A61s
+zpT$3y<$P`7mowfvRhJ|B%NnsG<1&7BasPHV_^Dp9pXUsNpNi^284*TV{5NvB=UVu0
+z7_YMMdl<jk!vDbd4HmwQ@dp?e{X4V%PsHH=v%ydLFJt`=T6kZcXTLY(kZ2yBPCPfD
+zlzSr&h_;MVJF_aFU_sB|r*c1I`B?@(wX=MLI>F*Uk>|~67Cx5o^DO)##)~ZZ@~P|+
+zgP+Lt_@i){fz$YWk>|s!4V?7f%<``_aN<9UDuHm5ffN7x%zr!Ma(>Bk#rq6?BKMFG
+zgr^Lg<aFct_c;rf>%l7)KA-ttV_eFW`}xl;T%O+s_+^#!Z%3|IvVoI6SF!x|jEnpR
+zp7+u%{3gavv+xYYCtJ9D1--z+KVtqm#zoJ|_`JBr;+OqtcUt`Yc-%f_@n<o<*TUtS
+z-Y+aU;@kCmgP(^ub)%C&g9AbI+|TXV!NTSFX-^B6_ZcU~z)!Jo@x7T913%5e<vGl7
+z3-7}1aF&G&f3Ah6alhonz$aPw6}nkqjYAXCK7!A&@Nc<)3uEA=7QT%2|3wVE%EAXS
+z|B@K^N(-0gPFGmCJP%oG;lkfw;qP$0HpIYhwD8w?a=keQeussh%l&e94E!MrZ)ANQ
+zje&2qa31!~GcoX;7Je1at1rdC_geUw+%Ip&!2e?5Gx+>E5Ci|v!oO$!Ph#L-S$JD+
+z|D!SR;}-rfw`ZV3({V0%(89N}{G=FodkYr}sGTi5kK3(>g$sW#3vbKg<fIsQmW5xz
+z{WvfNKHS1(opXkTf5!8`XbTtqJPVim>--pafrW47{+$&ApKIawaXZY9ftOqOsVskS
+z41Ae|%k$e67B2hDuCQ?7zskakxPR+o;MZBWSlGJ3!YgDxv2fwP&BC*}zwU~GKWO1w
+zc$_>E13#bF^|XGVQ-!PL%;t3y;jE%6d9{Vhx|F+3U1xb|qWF0k+iZW%$0Qg*)-5{b
+zKQE+i<*rpplbJ#ARUBVo;qsjDWeb=4){iV)RT@|t>m%~zK4`Fo%l*h?3zz$X$1Ggd
+zKR@3`byem3qMD*CY!DA+!6|hOK7h}vttc<Mu%vuBd{i5$!`NlD#=NxR>KaM;|Ie9q
+zI{J*7TE-nn6>|6}>qU-w`|c!8d*W$a=Lo>ZRbw=<iBAOLqjF@N%Rar680XVVXTtBZ
+zasqjXCU{tQXg^RS)6Tz*^UHZ78KiuPhd_|bfdcSR@=vpHDPN8`NGIBEzxH-PEJyNj
+zRDHWim|ebhG=$GIg^`aUR^$`|C)zy6iFGbB&ZUSE(hZu(3-A}M|I#LE#&j--`j13P
+z`O<$E0wWe#KY>(X8#Bggf01)3xTP+fRUP&)!;?JUN}A2P3<=TnA9jw;aqEftNcz+L
+zjFc<-M}XNfDMy4p(m*J(2A0iB`w(o5@_n36zm9XSIf)}~^WFd~n*RGQqTK%eQPQ6t
+z!P)xX56qSc$k~`hzyA9+9c#|}TO>p)KfOxl$mWbxKJ}$t{!_rBmH!-<pK2vqQD=9I
+z{BI0E0>YjDr2St6Pc;1}v;NZ0q(3cbZT;T{MmkA7L8`EPkUsvwnukPxIld3JX!)~8
+z==`+D-wcvZj-Mk@Xp^sm^P3paHg5m`VfOjIkn``dGD!VJ?lBP2+7I7Ssj#0Jsr{%e
+zCBL*QJ$|veNae_>RtKkzRlXICsypS(rjG~^*7L;L9W?C$u*;`qSG4lCjYa~3ycf~2
+z=IvKi+<(#h(|m8<+39}JwEi73c(6)1ZSYX-$~*mE_vL+n9yD>tQO6v7k=!1>w5N}c
+zyrEoD!>4WCr*myLrnA`Rta6MEN5~(3M7i@KAHcz_CdrMn?<qF{o=fK{=h`Z@6$S<M
+zEm}=AJ1;pEqJHN3q{H4Z<MadVKzs|b=)vwMm5{jX0<brA;i(e_Euw^Yb*6ZJD|O6O
+z-KW?B`)i0T$ZYC<QvJ+|55JBS%{hulrbqt+WU9t<zXF}+w3>$l!NE)LgAeN|PDv{6
+zI<3YNjM}RBS-Sf1V{QXVBL$8}=$FD=^$TS4t6-<cHb^9r0!QC$5+!HmDyZjTZaXR_
+zuwm6@Ub7wma2fvED1Q>()_jNde&6olZIlb2Hrl0zmzUnVH8M{%BovU}nPe`|anX}b
+zN{~7rCHM~5Qi<e8pXg+H+6?k+AD!r5l>bd{2c8Q7<s_hGQ||_?#Gye@92z8eM(yD^
+zpouN~)=gaiB>MK|$-;e-X^6j#VcS31H_D%q;v~X6J*uwVCA9U8&1(zw?R-F*4aW{l
+zlL=NPXL`^yA?GlpZFWj*uFuF+vqK+`r9jA89yCKp5vVO}N^Gvr$W*g~$aI}4LZ0j8
+zI!{OuNaCk#k=R_H(U#i}0F5Y|ChAvy<_cjQuSY!2sm1TVVBiqet^S#9LVOjiX5C^c
+zM}5D{=KnxzV}a0)rsaji(8TawsvGP${F~WtJrH*SltEcA3s^WY_q4HPFz2U?H^GL?
+z&oRUWD?>HPDqCp@Ote+jV%GcbFm=|{fRa~#Wy;J;Q`XlOR#w%dH-Y?G7LG2MMWz$E
+z($g2?*0#hctDujxn`CMBt+sFCtqC7l;TgtOcjli)*5Y7R2-eKVN}Oj2%g;*+D(gzV
+z(I*(&S`2$z=z`Il&$H~~*=Z}QAQoTm@fBqx-ZwM%?^*eg6WYCas^cz8b-N|C3a-cG
+zI2c2Q)(aHo(vPz71KT)k<7YzhDmQLS>*RDm+IEjJw?mv!14QCN^5yYpiGgM-GR+l;
+zx+<YdmcAm}vI6n|#YzY?yR#JeO;26P7SPu@iF(J_He$R>kjG2J&$k8RU3V-w-WAuw
+z>FTO%UNAD3kMv!keZNRay<_0?ooqDzu`zIe+987jGTg0U=|}nO@&P@^G&{AFekf8+
+zsicp5138F51e$88bp)3^pM=vTTJZBgQy?4{IuBPXAjGNN%-a#^Il^g8G6R1Uq$dP_
+zLc>l+J__EM<FdDw#yOQOp)V7}Pk$2RUP<IUO&Jk}>Vx7XeU>vm#=>u5e1e6C8JDZF
+z$iJ8Q=vf5?!C%)=M_on?{CbwNnA3${_FOKt@J5cWwD9v;&Ke7^Vf<<fm$7(*h07kz
+zTP&QMi&3~;AG~^9&G<tWKAPiCS@>j*zhL3C7N!u-@}wO;(6A#O`UD@(d>#2n2Xj31
+zv*grqT=vqF9CKD0Ve$W#<6{h*_~l*W1Oun>(~{!_22T9X;E%#=11J9J9AC&sI*|S{
+zj#pW@j91wsD*U66hr)J?f38BY*OYN-H`$Z-ehmCm3;%}Y9EyP-wQy#4zK?;M-}q5G
+zbYZ@h+<Bs>hqFM!Wo{uz#xG?z`~3<^M6mI6g=$`t|K~rWw;#&G#%)&YXYD$Ltn+47
+z`J6>nMHLHRXwk%!{Y;ibwsNwHD;F(-`DiDrqOztW3k$ve%E}~XDp?4dGi2fPza~)o
+zP@9=;Op<fx2Vt)I^?#)O1?dKYRtq@-@G(dohcH+D>U$h2N6tOmQK@heehClgsP}uT
+zM>Qpg*9>%<Kr;W`{2}CxR{vXpM+<iObltEq%6BXMAS5;!bj^8lz!R<g7IOPd=A{^|
+zBdL$<_L~AMTKV#A=$A-0gUw6xnvD_vW^T|PR-zSkDr4k-lJ(9eVMeg?{{m^z>i+~k
+zSCITve`*rD{&m1?nSh*wT)upRK^O&_m#(ML%KwPVmvKtv(^|$Z|5}zQdLpXA6)p79
+zezqy)%kd_#5pCz6z>BEUv>5MK^2zab&hIfWVZRfTbjc@iT6Ym<4O3?omp@q;`6%@l
+z_)!qi+D}~Sne9hwKFKdQVfML8veS4;zMUdQu=S6oJF)L!{SR;kT33=tyZi)T(aL|A
+z5)fpar(?~>Pm>3;c>4O!p3Q~^4<D#`{`F_GYw2c@LykJ;z#3%-=Y?^p6nlZZ664Uy
+zJ#ox}7ska$?tA5n7sdsT{blQ>7se$mDHxc#qco*wF5c744A01`+v$d<<Eid6Jj}&o
+z+4}h2eULdXlAD<q+LqstpP4g0azOK^Jl=AA-L`mSiElg*jBHPNeC&^n2T~LEq&z<3
+zd-Z#)@!hn9J>f{s4-<zs*1nos-!HSiRc`&b`1-=6`uxoJ`kKt(sD_Pwmfi7-x9Z0Q
+z2aQY0tuM&L&x*{n-1_;M-E%Xx0UXz`F7@->e{6L3G;B<q@rM^as-F~W+}5hTFqrFZ
+z%MCSVG!B{+boVxF9Q4lO^vvAI&c?>1(9ZhvGE?2gjNQ4Ro$kKK_Qu^Qp_km<8HYpL
+zbKRG68`h;gl(OQR$gakhT89pSw}X2)V^3&T!@4e~?7V7RuDdH7`4WYMLwnsl;f%&`
+z=*v+JkDb|mZ1&xxUV5(kVmPuF1%*S6Zeuv(MKGc&z1-`^{+R3T4o4bMU^w(5$c!(+
+zGpb?ru>G4>l~LwQC=iakh>{`IJsi&18;-mV-cb$fhCg&Px1M<VMbTgf*imjSnywE@
+zregmDrILR)=lJo+E8)=VP~h}u-a0Qr0tV;0e+@@=C@ua(T6`7yCLG$4>%N_f+GeA0
+zRQOG(mDa26`U}I6eW6#V{Oc~-^dn^->3$UX2K5iU>F&vRJ{;N^`o=w2U!FOP3*O!E
+zSk^V8m){i*?W0mNf{%@-Z1K77kuW-d>b{#wJ%X&^hSja+^*-SUF{I_9!jU7Yc;pRd
+z><%}qOUZdOXB(yV3x|&6x`&`m<F*!PcjSeHhR23ZIroB-lv>D>>wZZ^G$x<{LMUQi
+zxM5?*dtZ3`AlOy$yBl{VqwLU;aK_Gt)q(R<2kZl*6r2PFq~L^U9dhGhm3jFGzu8Y^
+zrp73<^RDk-|Bx6mqZLe*{@|6rXAnbrwBj4qwb|EdDEc&NjR#)U=FP8T75rI;bH|X}
+z!LbT%aqu7a5JNCp!PMa2-u}f8%}b8FpqqQ}pW`YQ#3;P|)%mA1pj<TUsNvroZ`$Bv
+zGLD8rujabnHNM2n?C!+-o%C?y&iJsquVHoY@*@{r75Or>Hy0zn5lQ_T8xzr?4Xd+z
+z72UijvM)Du1Oo@sJ0=Z#|Hs_O;l`b*bl!#zyL&J<#5e9ra1UX`4b1)cnLEM})yo(q
+z?mi@@>SA^_Y;1kctA9Nk#WYeedoex+&prF8BQ$6dQ2@HeUHtU3&!AkCbvPHpaeFGL
+zmqPoLx`P{cC%72atFw2m{B<8y2nNuRuuCJk&37mN=Htj-Dk}6PB)40W{lyz$_Xw4=
+zi>3^efV1=vriH!GDXp;)vk>%c(PM2qO2Ub>TPd4Kh3ux94Bzv{pD~~zJMjLE?|eXG
+zn#Kf9liiKm<7u?wB-)44(Oe@@ZlZ3<Z&%#b(`?BgO42P^GUNW|BI>Nj?bY{d-J*x6
+zmb(&;?sIn~kP3%KH#|1@hU2G<4o6;Y+}<*L^bL&1-=4VfK6iWM`EbG;N8b#Go`Xii
+zZ@un^$m_Z82S;CT+}YaQm+(#KP1L&mj@ffc!jZ4sgJC2zrnp}w{3-Mm&eVawd^zdb
+zaO5R-fB5KYm}t;piI__hFwXykftPUU*IyjR<cMh~d~`1gcDIKUUJHk|qo}>-uU>;3
+zm|FL#qQVK7IQQy_79~zvd3PmBLN+js#2k=-ITtNW6LrI5gARPq?-<I`$!Sz1W``Gf
+zrlkt*rK0v?D#rAT=|8c<X!mx^(mPu#frC*s3`?l-o3_DoPy!}kJ;PIpQd(GzS&Xw6
+z(Frd$Y)rjk<+P)bLn!{V!>9l8=pN(?<|gb4?Q-`-UTWOd^5|>OFJXHwM)2W=#}c1<
+z?X6RCG4XHLWoEkD6ZVE0$3mG6uV49z`(<QjpcSf!PTHHWJM8WX?TfU6wvj_rF?U;F
+zQZO(xDG$RS&wF8-8^INQQZO<zsWt_#PG`}p)A0G>3&MpvKBCM1`qHeFo~wy+!ZX5n
+zS^K7XW&6Xl`kARu<p3QYIg%UsD1wVuhmRW%2I~HPRycxFDe`Jw-|xf2-&}f87^ApD
+z<3~N*J^8~w31cD9Vd?laFQ%-aM*!pNempDX%FD5c%8z`OANfkHBl04D&5wMTSNB<t
+z(jc#HM@}C2mVP+CVa&GB@o?SyXXVu$*fz1Dre)5=HJ{b?6rE)qf@ML6h8gZBSM$20
+z?#JNxhWwFf(6eg7`1+Q45f|k6`hu3<=0ytJZ}S?a1oP_N{Wh;JPW9Y2&iKB&>kfQd
+z_ieE1P8>roMt0XV2FKTr95TEyFEVmq)fb;Mr1Z>jph$emnm?f$Yqq7VUJ6Td;grWa
+z-5s~KZOZC0#3I|nDSycAbgVRz+xFPOnLxBY;~Q!+)AHP-b>9c8M<3Y%8MK3D%{w(G
+zAb-mvJL1;1s%anDkIV%vk-4DNF`W;MGT!~`_`d(4n&sfOW5<uH_Ck#&Mh@jgT1ECt
+zom!zzGr3N0HN=k?-}hUt(N<lfS5c#h^-05qH|9r@PDhPy3mrfB5G01{J4M<;^ZMLQ
+zKS1vv4sKCkOOlSBZ21H9`QhM2sLXn-@gm>k;kA9_3oQ21nk@E$p>6eJJ4Cjx&BYn~
+zaoXB~%vM-JeVhuSWn_E(*wn_4gX$R;fEHkj&(vH2;fe$CQ2<<Z2hIYIyEO-G)OUO2
+zwY-K2Id$I!^HRp{&8z!3sE0`8i>*PVV_SfZuX!gg@)33j<TXr8t?6H%ny1#8FDO-J
+z9<QJL1F16em?DB}XZ{Fc?aUwYhVQC<J+I-?VBQOK-wk;$j8Qizp>26}A7Xg?*f4Px
+z#`srx_t8ld^iHDMRycLi=A5rj8I=`3tAzMBk7S1v{}E#BT_9ig68`Dlg+Q#m3xU{s
+z7g_{atWqOB%I*dATxV8`@SD&>-4eAJMI_Us-v_C;t+vRe^F7T8&clJ=giG)PbN&>k
+zBo&AI0D59e76VkAcQ3RUa|clM$Rcjw6(9qnz@cg%H_#x-q8g+1;Bu0Pw@q*&;N+xn
+z_|+oLQ6koO%qp()oihSCm{cOveWFXK3a9YV-TW}Jrxw>NbKDU`y3<h*>8&%|#(d73
+ze52@Y4#)9p3HLT4DbU@i<K8xoqwR_u_l|jlA+(!kMvBeId?V5xhOgZ_rb0qs!=aVx
+zPK|Oan?`L^<D&jZ?MUsa;`0zwjhn){PM{1F#2}ixxfu7XomAx}P~|9ST_=dHo#=h5
+zJ3+M(Qaclin;#>ZmdZkii-KGEBeduuPtCiC>AWuK!q_~^1=&#Qr?Pa_vK{Af2ssDL
+z-LMH|1%3<Ss{Oa2DpjXQXDyYCvUA(rJOv|O*LW$B6m)wmmG)4ZBi-dQks7yQvabKd
+zQvVam9QP6$G(D$Dg%F{Kkrdo@Wa_Dlyc_CL!8~1xh1shLbyhlxAcdDuRT7YsLldUa
+zCKEQ!baSV;!@R8@G9C($Rh?mE!$u8)R>~B&<7TUK&=a06g*gA_wi(*0f=7x?ch9tH
+zx_c%lyJr$)_e^VZ_ssbA>4}58xOfei=x?3DNj=n|Juq!#GfXlyYl@k%$+nwR<PFmH
+znDOmtpAC!;2a-98PHTr<IFgEJdm{?w4*uSoj(W>YCqo+eI~$vL5KZghhT2bcr+1!}
+zI9qKOg6XtS`#7X@HMjS4Gq(41mju{EH-w?^6MS7Tjz}`qOC+Z^+3F*Y_u}a)h=8p=
+zLbhN?@9WXY{;y;l#*ph22zf3;0jK7&EfO)M6>Rb4Xlg10!cAVgH!$`(A88Yf&|(Q4
+zE@Oo}i%)?OPHk{wd~MRk_>-48UDdJH*%;sJQm0qa+Bw(v={~eWhs-1_LymXt+({oh
+z^*k}Xcg8ZO*A@{XZ$Tlyk>&Qo2}J==4wGWP0g!xRl*A_jpe!b@^dT|Kcie}>hC&I>
+zD;6*05)Uf8ib=7|1_!&JGc<u8=mMI?<U>9rpM<nh*IUwlijb{6s6Y(Q6nW4TAr~_Q
+zpW9CQmMt6;i-iy;<e$B~vxR)u%ex$TTk!>Lp<LLUDJz*2gHmWUA)oTN3WSu;8seQA
+zh||sG|NfduF>dNQvxJoS658I(z4;v<0i|(oF7`Tj%8g8Z=|k<f%Sybin<8dH|LQ|x
+zK}Ou(L%bLX-0Ah^l)X%5c>Oea2$Nzu9H-N-89MH96(n<mj`!MnvXC>qwqAn9xr}3v
+z`HVt}QOtOUIz>LE9^p0j<QYsp>_M|%WbzF@o`4=0(V+uQ8~aS^ol%9;$nO<RN#DpO
+z0-VZ0p=WtLQLuu^&wNN;&z5*SQLv23Jw9}l$y~1|3dH8(b{{&(<XK)%6f9)&_dfJA
+zlkNRx@57|nV?(dXYn1mruBl>OK&;ui&Qu}K@H%G&+FU+sztQWQsY2fCF<uNtu}|0A
+z>xrqOm=u!>DC7~Va{$F^|3jRB_D>Req}SL}g`CUK{r~P%N;B{>=j4BXBJN6APo~Mc
+z*M_fG;y3BuykVWYkBl*O_oBI5w0_dB(0(R|dqZU^EqEzB<U{W;*~c3yQztPg7IDy~
+zyBMNH6$L<JnEbU5-NvNe39h)r3g-F#P^o58418eT6LPD^b-`XH#f&~?cp)$LhE9Qy
+z*LXwc5)7TEICj`)6!KdSn(dK1g!G)yjbj(_5p$7{)gCli$cw$ai&5^i9DB=SoT8h{
+z|4rp}#aaH6L&yg_=sY1GX|f8Dm{>@29ohHg$rthYo~!~Pt3BufA@A^@X+qxPK^I7I
+zfApXNA%F0o3&dRBulUs*`bo%J7}A@UCHB9XyVlq!swh0W)9BQwffS92Xj-2L-E3=7
+zWS7CJh?V*RZE1;s(w17(f-UPSY7`76*hH#{Q6nj0NKk{1m<Ulw>WhFe5g!qw{xPC4
+z8XrL=n)t)>&75!M_Uu-PfAA)|bIv#Co^$SF?%tU@XK(8LlEiH#=zU$Hem+UMobeWu
+zT$4z(lYCgAD)07DZ-gAnmhsw2ro~*$VxEx{VDSPapG+Z=EJggrG`ZhX!DFJEWtn>F
+zQ5?3#WP^7l1!yBl|1bq4o%-5FU#k;)ZLI$rQi$Ywg{r*)FP`g-(BWtG6zq`xqFnqZ
+zg;+j_lV(9>(oB+Nb`09GU#w+jBWAp7St$PTlt63%+7igx5XkDL0;eU%6RFUFX;V5d
+z&C;eo<0<-3%M*C_$PE3o(@z>9@>|ln3rMorQen1UYJ5St@v>huhK#d;r7qZrY_Y?u
+zv2sOA$`vhPHL!UrR0kEY>m4O?B&m)O@~Nk7G_Xhemh>Nz?19H79d@<oC^z3`TccJl
+zwrR;l*G95Y?x&HYLP$0#6yMvC<72@J9gFIF67|=Sd@h07NY*44+ex0Nknatw8X-f2
+z@$eXXnSMX6ink;N=98o$-@7d+n{6Ia`N@gNpyOYKa9yXSV~UDc1{pm`vIJv_LxYuz
+zgEzwBnTB2#YL1m)t?yB>4l@F=Ggx_czzr(DRgb(Ln2&wf=6_V2%X*sy{>MO-{GAt^
+zzx4d+Ie9&>bZ4%&zm#9rCtHW-OM?UXzW%OTO5Hs%Bkz9yYb*=iQt5&t@`7Pse{Yin
+zt;m!uiE0s#lBgD$epQZYDQ0R)rQTA>|H}I`sFhecKX@PC+4_n8aUIKo6@8oiyE=m2
+z;&4z?414mWT$sy$lMC}L`TfPPm=8LmZ#hSLb|J`v3yZxAJ726<CMV3MLQsS3`C{wk
+zoxvMXmPLg{!P;VH^a<sdmk*A_aI~157b7)tW<)-df>JR2Yf<zDt-)Sccp+?6Hq5nd
+z3_EjSF$}_BI8r<!$4Q0R^$p_w#s+a`Q~m7v&YgvZ0=@=1KP${Gi231-;b1=giVK*N
+z!UuH`Jran@Tqp{9^7|X6iRH$b4fPkU4a1LH!_eP%UvTjA@LIomRxl&qy!rYIuFw0`
+zYl7CBS~^>T^^5%F2dc9E(t}kQ|D5cGOh%Z69l}h_Hf6%FAZ+^qVH>k^aq8;TLci^0
+zr)B)(*7$?7=KT@;i3WLQ=7lq_d~DnBZ)mJ<qZXSoQRL@CRa5q?Om=dGC?$y?80h*x
+z1}W+0^$ZG%B7JVU@%A1kbmuyG%XV=2O4(R_nY@5|a~gFNZ@L}_`mF5l9UH+EhYO8~
+zJVJDl1RkZqLN==D)}C9jr+R-+Pj__HIGfNT45=&(BaKoTV`r)CAn*7eMNr9}>v)1c
+zPJojb?pk%1v#<TqXg_-=!l_%f*Bq39CX^Gtq#+_@kxkcJG-uA`S6$})w+JUEe$m7@
+zO^^YHF-}u4`bfG$J`EA&#Y->g{^N6#{l{gmaovA>&hZ;E{;NlizyJ6w(RIJ-i<U>y
+zy}xBY^Pwu)vz&W>50&lxE%~O%XH@e?s|)EK<yRix;Ab-N-s!SI`S|fyxcfa4u~)eF
+z%Q$Z@HfuR>IC3#r=FcS5C!a5bIzGmJMyogmh5v{;Do>U6`NoQ#8>_{>cB<lI`kP?q
+z$_IVZrb`5X9^M>sxebdlz&SbNDwJOGynM_Rma^%1R6Zcs5hcwPM{>c(jLuLntC5A3
+zB<5<ZgQK<>qs9N3g}jU3s1r6E^eKx_p2z?BhCCK1spmD7xA=6O@L7NKfk(86tFA$P
+z5@Zf_=pCF?v*n3np&03e_z>xVJYw#U4krc-?`Siz-KqZ<)jvZ8h+{bt>C*U+*yUrb
+zc?N%3`Gp4mQhDCOQGZtTM>8;yAwF60RYp&X;&&MQ7v=9W_!BDskimB-KV)#mPVwD%
+z`ombSO-BA1)xX8yyA^-M;1?^u%ivclzt`X`${(fr=+7GECmQ@E<?9Uooa%97z|emt
+zC_cl;k1FrRZb6=_-rYu?`d1qKUghsLIQ6eH_*cpg=@AE9OHA91{9AfrmyvH!{1YS3
+z`se?rqdu#tT#jEG`A_v6*8?a&Q*kch5NAKbe|I1ee^2>I24AiZYwHZo{dA@)4!1yZ
+z4U_vmLO<H&O!d3Z$aB12Z}juY&m#^FJ>Sa*iOWy)|05l=wmR~tH{R)Ob8zTk|K9H4
+zkiP>8CGB)@$cO6xZU=|_ppK^>D9(D|o#}o@UPYna<NlQN{{ubwvm+1v2NnOr;6)uQ
+zv-)E|yS&3aMsete3ida5e>Ujfp?Xep<bh{UXi3uyK2PyRWA`Dgf36D9A3jR#cJ!!<
+zNdF3>r&jC#0VDsR*8jr}4nOy*vZo9_MPq>Yzlu-`QI2EV9C_fws(-tKL;usNhyQcU
+za`Cyx0VDs3%KvEaKNUY@@Kd5!n&fv|aq53w>w*7Q4qQcq@;vVAM)}uOeonH^5?_ye
+za>7+S*27=OC~37L@9Mu-amq9H^?`A4cm9C6EfdFY`bqpHB`jX6IJ&!b`3RYAaQ5d1
+z4bJi89fPx99pTu~IJESC6iHeu^@KKH`)Rd#%}TKU5NCUmKUoNLiDm+NoH8{gwknT#
+zA?)Zd5&hQ}PMxK=+xLLquj5`b7$?;_G{}1SK&Q<=s`(+~Civi{Mqw(I|8VnT-f4A0
+zKl88C>jfB+m2DQRQvL1I`fJt-L;azRZ2ip_%<2@#o2w1A#hf&36dP|b<o`h@_&4kL
+z1PsZ_uB?DTuDuT5>F-X=mFHg}Cn}YHLQ|ZB*E!0MvB;Jm^J(i7a;{VRtH3zP$_~pp
+zi$VO5=6~EBgeu5leqPD{X7yj*HH#Ab$M1~wf1_Zq&vFVGrJ*z8W7RnJ>GM_*tCW8O
+zE-Xps#fRjZ`FMOq&X7)ogm_o;yBKIIyIV2irng7)e`gf1{Dj{WqEh{JX#L%wf~Y^-
+z4>LdO72VWc`^d6G^X~)WB<nwT>pR3>K0D4dK~Lg77PhQ?%n>TtA3Z0|-yI*4Z)^W=
+D0lJ|_
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/plugins/vbng/lib/libfreeradiusclient.so b/src/plugins/vbng/lib/libfreeradiusclient.so
+new file mode 100644
+index 0000000000000000000000000000000000000000..2603f0181c7c43542e59d2907d5bf6c4b0730916
+GIT binary patch
+literal 216320
+zcmd4)dw3K@_6Lmjga89XI$YGKr~{4~5H*8DgMwzr1bTF$Q9w{&LkNjP0*T24K|zBv
+zqqO6&S;f_Lbr;>$MOSxO7ZFe)7f3)?3@C`O%4JvSAtD#$vLNLBe5$&W4w&cn{XNh7
+z$2&ZksdK98oKvSxojP^t=JD*ns04>Yu|A!YTNOgfhDc1NnUR^*$xJCqrjnsJ@qM-8
+z7G*oP=A4@de=2d-ucEjFf;_t5FY{{w;@2e-*01Y4iO(>9t$GPSvtEr^ug0ur{q8oK
+zV*NTL86^?F{8LDPpR<155{nkek0^^|SNt*Ek(?I&WLXV*k)PaegVR`V=}HNo{ril`
+z-}<%q-Hm!|-~aVv@x907*O8nxCO_-fRFi01Uod0uj=po8;#{5c(9yqt8!I)2x$ce4
+zYr1I3{xD_9!r#64WBa<{Pig9%sPxO!?(0(RgzN#O=LLP2O#gGWlKNWri|+ib(kc11
+z0o6*#;Y{6q_29mG=K7br4NzPc`rlN-eUzR_UXtL4G{@ubKK$K}zlr#>K9i7`jK5#u
+zZwmgbPXQ9s@K=Pt2k<u?e-GlX1b;K}SBk$f{P9zcze<r(l-cI*9Q;0lzxnuk41bT~
+zuL^(mPY3`T{-h1L&`j&*?=$%QHU6H(-*fm|j6du1JQ6Qh0DfOI)4#*-OZa;ke}6D>
+zul(`Irl*HKTzAJ`dkh<Yt+P|}1^3=@VQA#v-v93__y4B2Ywv9f4t{gXW#7KO{Yve<
+zBf~cK9(H&}-IWVkemF8_!TY~MUcq%eCj7X?F@N!-9>ctS_1pJ<ez523D_efJW@+YA
+zPsjdNxAwL3|90&cbr~P_ZSaoUTDbnfORnnk#Y-(etco4(dEUXFuIu~H>iA867`nbB
+zy*Yo}yrDNt`bWzT7f%@a`A(GaCw*M@(7rE9>VK_VH0^ZN``e7a4a@rJ*~(Die{++6
+zm;2srul-~0u?=g=Hc!1Xdwl7UcOF@&T(t1sgWts8ePLkFc>^DM^4lBcN9PB&?f-Yy
+z4I{I+e!qVHGhf_y-?NR;If*ZOJ{UXk{-yh>KlsnH^WJgS^}a3Tt-pLdUb$%MQ-7^_
+z=jy(x%YN5wg6Fd@CoSKkpSOF|-v)p6(1d=b%6{>u6D+f4(79QilwPg=#mc2S>umwH
+z-%mTh55u7RrSd5lSHFbcfdTeQ_(K>hzl49b1HSnk;9ux~{<;q6PwhZXX9xHTpc9u(
+zFIKW2^w7%!Y`@tZ=tu3K{FDyL7j=ODsDpOB-GTho9q4BaCaYi4zoP>>r_jb<DnFwG
+z`qy_r|BoHut2=1#jUBZ2nhx+S9nfFWLA$=}z^;DNLA&O5fd735^qV`tkMDqvuLJpq
+zcOd7O4)n0G1NxVBKqtKeIj`uTUqD`Q+3em*KG6Z+i5<{i*nvEM1;JmkxAQxYXLbkp
+z^&RM^yaPEe??C_SJCOg44&>k30iDk~kSDnV`Xf8Q|D^-`Z#%$$*MXehb|7b<1AX4x
+z0sfv2^m%s&_+STo8TYs>W3v73>OlTA9nkr-1N@2(@E>#_=a3HMS=vGQ0Ll-r$!#UC
+z??7*pJD`))ft}3lpnsQvQEw$lSvEm(yxL@ZO3(rRQHk)I_$0wMNy!~15uE4vnPrx*
+zW*~{rbd=-g*FtYe%95ug%vh11k3_#DDai~@@wpc;KN%+dCX@bQiB=vI@+T>oW-xjb
+z{P_8;$+wJwD?ZdaKby?*xiJY}Wy<rU&}WiT#sCu^uZf>*(pmDP#B<)_=V43Ev-GeF
+zdDL5(skaPKT2VTi^qZ<BqRea;<5!kXo+a^?obyb+BKSsDfhiB=V)>?<W%(quho1o^
+zzS`8!B@(S{!mp6$E{T|FmgoAWw{o8H@7K(N){oh)-FHjG?@hk1oBidAO1!22T_#`G
+ztr8zJ=^Qla)I=mgGx4vOdRSrx@m5%Qwb?H<nX(|)Ec}$1<ulDifT<=W$&^Q#C(Fge
+z;z?1Cm~^VfNPG{|9wI`Y=f<&pP5H}Ay<H}&DT7S>G82EPiT{U*-#uI+PMY|yO}<mi
+zMU2_~%BNPpo9*4og)cs5O#PJQOZZyQ<>xiC-*e4|z5%-Y9Kav@v6_oId~T3G%3zaD
+zwW;T;O#BK{o*Gl0xhDQ!mR*^4o^Il~wj=#zCgGkYzR7Cu2#GMwPT6nbmze!-jrWht
+z_SU>A%U^7^i~LEy#-wkOQ*JW*G5JYZ-dYRxwCwN^iMQHym)Wi~Q=ijhw(@{g-c<ZG
+zpv#YL%2~Zg!re`IxW*LiHT}alnXMc#<#Czglzxz(i%q>PnJVE!@<*vM<#CZ9KC~Nt
+zj+uOGO#K`;@qe@Q|Bx(q6JYUyT_h_PD^vEnOoaS-*=*MmE{O55{N!4sh5SB&Rt(er
+z|7_xGek<|pSAOQ3{j$s)N4XNMylvtCC=n{!!%rU}&n3#7v*al-^|RzDS?&U}U11ZS
+zY5H^1OqB?VQBGy3Ebm1*exjxxGEF;7lW65*lTMY{U#f}UW0g1Uf$MyJa!vg-nG9c%
+zXvJriuQ3hEY@YItS$@h{e!HvL-m~?u<mEjuvvgKoMKHfSn3t#I6&24aR`UE~bMmGY
+zmKQ!yToEiRADfd^QaY<}Z2r`eLYeo=Ie7(h@<|}Sr1%jOynS}wJtl>$lKhH_!V0Cl
+zAn$>~U|#VwrlwXFmrN@!e2D4%{Cxftl+G&3E1nf>O;?o9W*U_Wg2ginMbX)1`NidV
+zMdgJ8tSFo{Ew7@me0E{EEf?&HADCrFOcOlwWo6Jq%hBk98F>ZMXXF*-7ng{_mBH!O
+zZ(dn>>72O&Dku;V<>R*vTQI$_U<R|x3-hPt&CD+=Du#NBO3MmoDMesV0S*Phxn+fU
+zQ}aqn3zUjrdBOB@WoCW}A#yLDR#`@Luv9QFDSbdGDkv$ffbQ}N%gbk#vR;0$xO5gv
+z0aGfP2v$R&K|x^_^4S7GeP$WOk=d>KnN|33Ug0dEMXJn7=TDm^k|10Hf$=k|fb|Po
+z#hX=Dj-DtI)Iqj*W?3mrgrxHFW){vYD4Q#?gcue;_S4ey3i3+|6j?@6E)#l$X|#4#
+zMQOndbOI`rK0GULDszg<AXIr_MTJ6;qD)iRyTMYWthA&=DV_z>nH4M*mQq}nH@&nX
+zI4hq<QCKj$sJwJ0snNVD$_q%z0wrA`kJM1B5!ej`dSZoX#pq)Y$qxq0WkY9{&Mvf+
+zVCBw+SPEL%+LKl{fPzWAcovK@sN_$D)=1bym*tnEe=SDTh~OmJRu)80v&%~?TSvDH
+z3C>hz&ae<d0M?qFFAY}Oa}cU1Z&i>mDq4o}z)VpQnMLg=pn>fP(Du-i?YrC*nH^C)
+zOWIqobVgpeLhHten>tsjA6hRhwfav=VbedmsjVdKj-$Nz0V+YJFyf1aj;0kt(o$h7
+z!V|DjLEvmP#9%WCK#VdBgo^U~S<__ivlGp6VVY+f6X7sGu^_*qP?);e*+QG_PZSl@
+zsbh?}{PMY=RSZKNHY~5Aq9A`(5sg_4;@1A76UxgAmQ)DC6Rn0+ZB2%<P_`A-z5t=t
+z0vuf|%i+*!*_D=piESGnX#cE2_$2lN#!+h_xE|S&vn%YQ7aEycfeg!vQLVU0R4Ohl
+z2nstQB`CWh$eyMnn^j7nv@)o`krvJ@3(l>;a77wIn<@Cmf|>ahGnC>A*zjB>SO6-*
+znu7%>B2q;Kv%uit^5UQ{`kB)TOY-MpRF_bEw07o<3OO0jW0uTfi)g5&Mbl8Mq<CsM
+zTx*Um-A@B)1ILwN)D+qfqd4i<;IS}?ilWl;nZy-bS5bQ1jY`S1YfFk}RnEC~PR5Pb
+z-Z+%VAxd5$DCMIIr&d(RNf0R50;<toz`nS$;@X0e;=)-$Sz~m-KQb$C$aOa;R_dnK
+zlxJvbvMn{_y7X4;4cD1*0uPcp;h+3w%KFDMm2>|k{sOM8RA)0cLC_<GF73*96_Cue
+zINB+;@nm=;={f~1hw}f$e~OT*8L?e5<aOb%PjT^iScNJ>5a;mYfCl!M`GjS@Q{=PG
+zg`#{{Ww?loa0c_6-=cIEWt0i`75RzE-6mXlaWNv$PRc|R4qik!L3sc$KibzW@#_@d
+zI2SV40l8=4Gfn)Iv+&AFS#kPV_^VBP*;)8&O#Ga)@YkF8s<ZGnnD~Wf;cqhW)o0;v
+zG4U^+g}=?jFF6aJW#X5fg&%F=mz{;b!^E#V3xAi1SN_{xpBB7im&CIV?Vn{P9-XLI
+zF*Wm7+VJ)|H8#9`-*kfwpJrpwWW)Py`0Y0QT{iq~8{XV%5V<M4UE-H!gHXNo<Ferq
+z+P8jEZFp;K#LP4s-du8sIvF-RbzyxnZFtjUMV4m6TWcC-<l69-O%p%ChBudFL@QHl
+z`0fHDzoy&pJ#6?g8y>5t*3TRp9s|1dQ)R<jYj<WYwBhyE(uz`T!#`%jzi7i(+3-tj
+z_+B>rQX9UH4ZqBW?`y-awBgUU;cIO8unoV#hPU<@nB8Q<zho=F-G;x=hTm<&n@diS
+zYuNB9w(^H;_{lc>2^;<*8(!Jt5)f_YVv&+x&OI)XAih+j<X7?@mq-x*f=J1)lszty
+zAii9r<d<uYOC*S&B~tP$b&pFVh`09qh)CPx;*Ypz(NCo0SH>QfNU;2+A|<~v_qarY
+z_+N>X{L=QgM1pv8X)oa1JudM}{AD5~zb5Q)i3IVNi<JDDvd1M7#LJWbmFasVMEoBl
+zN_>~?afx5ze<M=zYt9~*ND$v&q~urC9+yZEKR~49*TOw6ks$tAk&<84dt4$x{1qZ4
+zzh2zq5((nnA|=0;>~V<%@h^*%{93xlB@)E{QKaP8vOO-5ApS~`l3y$LxI}{Zm`KU5
+znmsO&ApR<ml3yG4xI}{Zt3^tFHSKYU1o5dNCBL@saft-+b3{sh?cU=O3E~Hel>9RG
+zxI}_@YcH0FLwj8O5%yCcQu6D>9+yb4{52wFe(iOM1o4AS6n~sHe6bCmY{Q#dG$J>}
+zhQHQU-etpIXTzu3@Ymb$X*RsM)gy8<Y<Q2Ye5MWmoDHwp@YdcuvvX~DGh`99CfM-5
+zv(cGi!?%XG$e(V*r`yVx+3<xn{2UuT--fTU;cv9z7uxW7Hhi@WKi`Ib(T2athF@aC
+zFR<a4+VB}R{4yJUm<_+uhBvqPL~e}@f3vOp1{?ks8@|bgf6|8EZo?0^;dk5cBW!rX
+zhQHN@KV-w-X2YMb;WKS`<v%U~(f++QywipsX~QSm@L4u|iVZ)*hIiTUQ*HQE8-Ah<
+zpJv1RZ1@Ztex41VX~SpR@R|)j%7)Li;a{=gC)n_#ZTKlRyk^5sx8ZNM;md6J3LAco
+z4Ii=Lt8Dl?Z1{yXe87gUw&Cx$;a{}jpR(bX*zh?v{8AhKP8)ui4bQU=>$B2^&$W>F
+zt+C-lHv9$~{vI2?$%Y?e!*93Y@3rA~+wfy;c*BMtXTxiu@10t-^XcU-MT^t~I~$+C
+zvbE4UXT2=cl0M))m(p^j8{g{XnMe_y&dm7k7JRO}n6QIzlYn~@P9R((;O>Mw5nd+X
+z1i}pM<4Xj560E0pCR{DxBZL{U$EyUqpD>48yiCA*2|Ec-5%3Pe48h~M0^UNHp?5q}
+zz#kK4$Q@4;a2;WW+HseFR}*H49ZweUyM%iZRs{SOVU_TqGeBJV8euM>;=2X>5@CkQ
+z@g@O3OSm`T8Ua5|xDVlF0)B#UU&2cS{0QOm30DiaoG?S+c$I)3Bzz&^G67E|%n&v{
+zMZotHW{4Wk74SWT8Jfm31$;YUhK%tv0goiiP%-Wj@XdrTC7dkaA%q#~#T5Y$B78aF
+zL#NsP0fb$IcMJGp!u<(13Ai`m0fcJ=+@0_hgqI08fiOd^_!0r1{3qZm30DjF2w{ds
+z@hSoDCww*GG6C-;oJx3#fOimPs1wf>@D{=hapIW*{+KXBn0T6i>j*P+iMs^6nlM9<
+zc(Q=sCCtzxt_b)o!VEd$hkh3QPnb*M_-+BeM3^B)yh*^%5*|XhM!-)KX6O)KCg3Ls
+z4<)=rz>g44CtNMya>AV2<5dEFkT9p{c$t8w66O>fpCaJ<33KX==L+~9!kk*;nF79@
+zFsIabnt(?V=9C$C3HWBhoGRnV0v<w`Q)FBb@F2pR8smpfiT)>?NqDz_FDA^XFy18K
+z-h@XIt`Tr|!dZlu2{?f;r>gi80iS#qFsGt;wSbQh<`fjK67YV)qY0M@crRg2E%7M=
+z-a*(;I9I@12y=>wXA1aZ!kjANX#%bz%qb%767XumboKFM0l!O_E<UaZ_$|VB5k7QM
+z^gm&`^!RQ8zeM<M!c78xmhe4<YXtl>;W31l3HS-ZV+k)2@FRrB5v~?+Ibpi=c$I)3
+zBs`vQnSiGfo<MktfbS=KAK_d9-$R&FT|863w-aW_5Kj~ENWzl{y99hQ;mL%P1w4fC
+zuLvsw9z>WSW&F_pME?_>LU^};FD9H%xJkgh2~Q<lBjE0Y3kWY0a020JgqH~T<Uarx
+z60R2T5yC};s|38C@B@U)1iY6pC!qKg0q-DOOgLA-TL?c$I8(qM6P`ghO~7@8O9;CJ
+zyqfS#!pQ=Dm+&mYih$oDTuS)R3DN(A%Lwll@JoarBHSe4X9<@Rt`YFlgewRy6Yvv+
+zgM^m|_z}XDgsTNyPIxxqDgi%8_+i3j0-j2E4&f;RzMn8dk9e+t?;-pM;Y<M!c*ms_
+zRkvI@MEq*85pTYaxjxpJKjXB4Cp7(AEp(#i?DG)@eDk&p1G-Ia*<GYwj!`<fp0j?@
+zb?W6|kVI$@8&NFkr%#pj&#->&nNFI1NUJq&(;N-j<}<+*5L;yuOOnK7{j=#+jkpMO
+zl*+5M(1>570z}fk4JK*P5w9(CDMmIlZfN+L+|c>Z3YX&e@mzT}zX_p3w<(o9;=e*k
+zDL43gO#X3_Y-yS-;sM4x#!YZ+BE~7I9ycaieZNN2fArMoTSYLW-{}nKcc%FCQOQP6
+zXmDYcBkFUzG8bN>XSt9{)wA5JJdsUNyyLz1`t>v3ao(}x#%TIhpZ<xq;QI~Glpb`K
+zXtDHqn3ARk+_?eW=g#m&KNQdWOw*!?SEf>*df2@Zzn&Vy0dqrzS5YCLA4lml;|K5u
+z>Xla1P-7=h-cU;-@&~Ko_Yhd2z%#Od(GwoaudmCA{8tS}krmmg>2JH2l22pUy$rwn
+zsF6{~BM~+HHd00E!T)NFK6fTFkEp$-xl_cq%NtE}M{3kX-4hkX9}Bx*M7|b##$6?T
+zgYG$~G#zQh13o_Y1WjM>kNMmh+w0Vz0Hl2GDSmzZN_0#MElDf*{D@ag4u3&fMe22(
+zn`h!-k}hgEBw=WJ_M;(?b)aT)sNP}hfLgr6`ne&J&z*t}NLCl!fp{~Po1lf(JN=>c
+z38B5GE8mdq`4Ew(7F{gbszsr8P4A^emkS+F({30ll&(e=pxN4jb?m2!lf9F?lfA$4
+z=CMCDbP)BVMOuQrj72mQo94iMs1}Ve5cTONVL91KAevKy?#e}0My?hOx>JnQW3r39
+z_j&IR&eEb|-5Jb)SsgcCKHkz2I^j?wmy!l54bG;9RY2&58Z`KbItbV!>IA3)ZO&GV
+z?d<Ya4LlaGn!OTQP~vYPN^2XRN7Q6!iR?5jI?tWy*>XgkL`s@E7-sHs&oM3nxp<M;
+zAA$x{2^Fg0RUm~*(<3cv_#LFZ(V=e9bCF}}qL+ctV$0oCU>b;)pttcgh4)`!#Auxs
+zgF!Hr+<Z$rdD5Nmw&?U;mGDDshq{Q7s>RfYG@6ZmbfRGiu`w-L!It(m(g^qcNJ6k4
+zjhp0l!D_Zwyx+c~zQt5^c1QVJJIcq7$~m{A9{)*p)cyCV;Ztl!yRJHX)a<GZ=*oKw
+z<bGx>Qt{^y7Q)F`{xHB{zFZ8lY|qAQPt9sBX4uzNumdcr)W~mOMnaGAhfr7eRSep_
+zn50<jK9~dsZG03;Ra?zMPdN=0t%8X-<2Or|K8T1RN9V5?b)*h!<>>ZoS;Gie4iV!;
+zbTIg`w=;tiHBiW;Z9#kUFn}@#!xjbsnsfr?=eb?+^TF7t06A$YG@fM77GXX%v)K!E
+z#CM>xWJ_Wk8nFPnynW*-2U`_FaZ3m_d<OL-f0O5{@Kna*KbqQTvlqDFWbY~()q@U0
+zWfMc|QtI31`}Gab^n(sf->m6JJjaZE<R!{gx79~aJecU&XnbsCO1*<VDzSbdN_aM+
+z`qH)%ra%9Z{@kl?qDwyolG8PPs2g2&4Bn1@+-dXQ@OyCHJ~Rad{)+;dzRRnx(_$rV
+zmvOB?2i*NQIy7k?B7gnrE@&frGZ()ip)mmj9}!ZFEZQcd$kG2tKb8z<(}0?*lUQ2+
+z!KgnBhOpNZAPHxY69(@Tz25i|7B%61=1zdm>nnU-WiM!Gy1w1!?u-`DXj84w59c#;
+zGF$L{2K>IJ&vQd#@N1fW94*Y4kB0{}+w7H!LQp_~Y3$(_(RqQ`G`9<G-*X_K?_a}*
+zBm??BBaI?rJcKVt5p@NIa%jCHyfe7dxBvp@==-#&v$?mNzx|;`hgV&3IkG?0)HU_T
+zd|rpE5=(;a!MCeUT@n1t8W$81&|Ab@V??M8m^?J)49;nQ*s%!?)XQ{)Ybq~n?$<V6
+z;c9^I6s`$&l{62mO|kS13Vyvo4gXD&Hf}r8(z3cc0M9XK*{^poMhGpBbtilEQP?*b
+znG(>;Q~U@O;(g#6)^sx~9y`<~jvASXEZJ4D^Z+7RJ-!yx50$p)U`tCtKWJQq@?uyu
+z_fjvfLLORn&`1W>gElR9Q^&2dSLIO5T<jWKSE6IK6e-GD%zmVMqe*uYekI*iMsH9v
+zzWxCoCBv9aix<WdOD{(~O|P{?I)xIl%9EV0<p@~teTtC4*6n<1)l*Y->-7zZZY9`j
+zC0EFeiSFyC70xcg2uWmEsPBz-*FtrPu>~z>&YU^Ex&MYMtMCcN^;%6oSQ}4%v#JV~
+z;H%YQw<l<-Z?j&jAjeomi_t<mI%xx&v{-cuv}ODW<3Wo~Owl4cEAMDCS~Pqh8UQuv
+z``4nDV%&@dP-~0b6tT_z2SICWg^b%kDjB4LYqjVNkj3~3+KJRu8qq9gbG`8$Xh=I0
+zVO=zjY=fzO{bwzDix!=cZ1@g99FDwZV;GZ>1C{^vWAM_JM90+2`jM8$0^`Q$r`IL}
+z&-l{VVVbI5AG}8^IIY$0>tr-oxGZPTr8Sa<(wN2Opli14*R;i(o|<|zxd7`W(bq;m
+z%3&=3UdC6Rn&vG<)ouC_4lMe((|8UAAn?Ta(@3=C+s3>8BjiifqNNDk<}rTj>kdTc
+zD>;k?z7>)j&xW^L4UT~VgR@I=j{be~g~D(6Lk-S5qw~^b@f9e(W(2-4K#e#naGmiD
+zpujN0uim*%)9Z`{5Cke;uSJKuL9CxKg>9j)<FJmEI1=dBu92$o!CL#N;Y;8-#31+S
+z7=+YkAlA8b8rAfJU;j#r-tD|yPaL8}z0TDr3cp&5!Pjzoba+||ViXLGN1Iz(?)w$V
+zq58U1pWb8}Mn#x^;oSoTQxc;J8yGSi-eK#cM}YQ>kElh+3*Tn^1L>StN#_KP)kN42
+z+{f*@?^`7}DS#;y(TtF8bAh4=Sty?rCjeoiqnwaxw<*=P`x$MGO7utXb!L0E2-Y<Y
+zIGIH4MXfQh4oy)e+#kQ4o+OqY21(idIcSY{HJcc}4qs;S3R!H9RSeB`w-xM++*W_+
+z9Sfr#r^RMD$28x7_*e9raU+|_2%<iCF`a3&@`M)4b<m050+$l0Y3MX!PG82MT6F#i
+z#LAV86FoHur0XXN-@%kQe(dwfLUak{jwEyC^Nf2A5T1>wFXBcGeVU<$8yLc48Ih^Q
+z?(Z9j&2yJQL<}t#l|Zvg<+=;~<o0aT>uUEWN4BVud{kQ4$s3yIb|<Kj+d$V}FxEYI
+zWg6?m9)&5vq(djuH1)2g*hn?B`w$4ZLp2FnWFuC1!34#@*)!Esv#JZK_%U6l{iyv_
+z;8u}{(OXz&i90zu4g-08V(baw)VB0*l1|MKvX~yNPK%98fR|H!`;}Ulw3~L7p@qKg
+zq+J6Nk&S`a^h9;h7nC!Wczx_XOas&0X_$Rt*~zudi5jLU2-r`UqgMN$M9oo;)fMd%
+z!P#nD>*CPz>figWnT9~|0{AO`bez*4#ezh~lKh}wzt_nj!%0g+muay|%;HA1zu*fk
+z1j`DobEqrE_RUPoZPA7`R2tf_Z~XcJHQXX}e6;xmsxq~6AeQA&pW?$vRCp>@{}1Ft
+zp#_OgX^s;uyP>>brz%HpKQhz&;D;vG_rmhc)mziE4r%(B6XtxD6aBM04P>}9jogN4
+zP>ag$hl7^(01_@W@(uYfSVv2-jZ5%p$Z~WcuPzj1FxYe<n=a}GJ?rP@SG`z^3`Qx)
+zn-I%RuzIxMYtfMby;0M57)vk)phq%_`BD?0Usrq@he~9ls2}_cRhu^iqUZ@0V!y?F
+zPFe646l~~pF~!hgcOW)--{-!ny%@qK<FgT~Ytcz=XY&V*AcFQNaTS#VdVTyD8gA%@
+zef%NB^Xo^)jp5v)e~BFgF-eR=8ALE%^k?WqOR!I@Z_0v`yyQ3g0&iosIGB)g0@to$
+z-CA%$-vK8WaO^Wy3TKk7#C)A#BH6H3?pBDB)i!^RN!@!^EawD*b0=aOjF(IfNKN<w
+z7_S;Wj(J$vaaD$*hT{TyEEOvS{pcDF8sl>5HiF$la|U-&!*6zG`N|Y67IxPlpJO*o
+ziyRA{w^|HKz0sKY9hDUT8g`wb#l~X6&Sk6N+ebH}My_!}qAhDMx=oLF35H>$Mz2>F
+zzSEWDQCQ?M<Sb)6U526}o)*ibB1Eob#*<K|r$ybc8X8oJ(6sV^{++%H@&t{O&=xo?
+z{08Kr*%+wvQ&*84xN-vKs&XNI`6<%n-UsRpW}~WrW23k$kqb)<yTia>v6);{yTMrm
+z_zA#<lXl0rcM?>luE@sUILGkBg<&_Zwk%xicHl=1ze<J1Mr2I^?_+S;hlOBXy>ZUO
+zK<sUIHAs0sWCOfwL^H&^8_<tnHt}JaeOG8~&ShFblXu`czhi4QhT5WkqbWHBKQ(`8
+zjzeSTe-Qz~s1k$gLMM6z*BXQ3EiI6g<c-T@dNI?zW%@;?yU6s*NNZ79mH`&?0<q<y
+z8Ppp$vl7vkwhmwHP67-eH65!LbidJz?HpfhPG6sXqR3QI0*U}+4^GMU9AG(DHoA-Z
+zj{&F_+ZkisF3(2qDz-bIAHziKgW-6#h}{c)l6wk6&S^z3*COLB=z%+0VlkYI)B)_M
+z6mlyCo)UWp-#$FLxukXeGd}qbBVxba$nCJmZZI&WgMwHJCu7Nq1qEpA1iS&2KLHtF
+z)F+ptAaXl@h@J8^4k6aQBkFxVxATZPxXE}P2FHQB1l@;?DTf-aM;R~HJKk7!%P`oF
+z`s@C13Ru6>WV|1dgwaA-=DBmDGn26)U{nFbZ12TpJ>sPteRtc!VH~ocg<0Qn_&nq0
+zxNUW$KHX3w$2s;8@FK(JN3s7Bz0H_|-UQu!lLcKX@J}E&a8DBxpr;12Uqe>~OuB)I
+z_ag|~()?WYF`v5#tr<dx7W=c<%M@J{z*fKn&&Jh?3+tO*7+n~N6WCqG#d0Js8VHF(
+zC;B{gk^25K?gX^AsCJ_hJ2P?LFhh;410tG}%$|lDNPh<h7N%g5wNbEFw0IuOH{K20
+zO?#&0PbY2~+%9Y-h=}qcIuoqS_8Hf~O6WyyL<MFFcfnnYv6v52Rc<42!-nG=1~k^#
+z1WFwa&`6%x@{qpFZuWNbPQpr7Odzyz`VNi<e*BH2xOAtX+wI;P?d$f3)}0eg?9=P~
+z1uY0}tboD~--w7Jp!)V=jfBRe`9uHi6mT5(4@5NG5YYD;HIP0l*7s^H_MsTg7%4^o
+z+CO{9whmKW4$t`GY#6#eLtClkmrpC1n_uBw$s-DutidnZu>n7Y1?7cBKH&ZZz<3A-
+z15ZrX7r75RRq-#;1?r0V2&5ogG!1b^V(hmfNZQu_$b!9M>1XKMYJW&RURPDch2J(U
+zR>p;2gT5_O+2)N^ey@eLBSb>|1!uljAwWTs`qXClFt201cfn~|m-_2J0nWVnL$?Dq
+zqehzX%{6kO`2En$C)CyV5eY1JFM*hvzTDglUM`fP=^u*CU~Zk!e=%QHMa0KU*7wJT
+zCyDm?^!>19?q_x4Oa;X*Lme@VP`h`+C?hpqeZ3kvB-n;c%iiF`sX|QqKC)3=^bc}@
+zb~D+9eYxp$%qZl*)w9zuyx!U)m7ivYp4pKDa_Fg%{_GdTVVV-Wo=VlU*d+HPj4U4C
+zDIzeRj|mk!)tIb$17*Ad6TnncnWL`2>;jR7J7@PB-YGbDc(-7s_alTKE%8sV_15bD
+zR=ZJ1Q~y+_KJicBn?E<lmDZS@Mkew5Inptnz&jWE`G($E>|~FGrE9VCR~OPHA4iUn
+zMhwKnqF^Osy?8$AdOt#MDe-$jT#GFh)?_wR4r~NHvbl!$8w}D6V+WfMOHag+CcK{I
+zou(l(-b)ZkpEAMb9M~jd6muU#(()f)-`iTm7|6_9P!;=f!i^a>?LJ4CHZfLzEyNf@
+zF-&jt92nZRNVcOyJOYb{nElR?h4te{PK(?koZGg#F(K*8%>6><^2J^4b01^w3gj9?
+zk&0%R@-||m*_<O!hy8kur5Znq!j7iyLfwOyU5!*U*xH}wZXV)GY-8Y*YK#`W3=3<u
+zMO|}4X4RPi!MiiV$Nc&il~*>Wnf)FZc64?Rbwwwv=N;aKqhNmZ4weohYNJQ(2ih>O
+z;FsQpE)ZgJ>+E8#_tX_x4lOpuF?>MfCCx*Ms!6Y_cVQRO!&VR$9SOq+1TVt&+xf%0
+zSMHHi#<fuyK7c57agDm7Msw8p^>Iq`UfX^K_M<}Ir$qBoL#H~cPxYkn#?EUNGvsM(
+z#}p*4(j2udds^)~bTV0uyw76ME*ciso}G=^gE=p8^lADyELhg1a97lnKib8!Q_sfw
+z!o-G7V)x@SlwWZ2G``heb7i6xV11VZ2Y14$hWJK?r3f83g;O)<t1E6@nvl70ep;}*
+z`hKv>8HAvYGY!7ZX^K9sjj*Zj*vK=X6UpjRccOOaBo0xs)6~%8;B>4GG{*rO*%G`^
+zUD5McUBbegv|y6H8AN-MsPhcy;pEK{Rm4j$$$!8+^c@~)A0J?Nv=~?IM6b0k$03VN
+z3Zt1>7~f94E}nw2*7%S1)byM*?661Y^~B!IJSTPla-gj}C$xbZw1EwdrqJ#aRKOFn
+zQ447g)*2^5jo1ZB>N2eHPCdy{{)6xyQm*K&nhs|bo!5ob9H2HI)b@ee|FnUd&}mw2
+zywi``>+vlZCvE#vXb()l8YZ$e6L!GT??*9Y`p(Y0g_$E{=EG-aUdBvbdy4iHjf)0*
+z{tQL_9DkR%TOnXH*aaBJ&+$8eX+7T+JMn&f>o}jjeoXDR*!|t))9bq(<ysAURO7!9
+zgF+4Gu)lU9c2gstpbyt(05;+npD+w;rl{egz^?9(FU%?$*FRsuL&9aI>NDIvM9GaI
+zI!=BN)nmg+&q_6l|1E=<J;3^+1#avJdf`dGIt8_#?Dp_o(HVmmoaXVB`s9=N_I?Ea
+z(ee?kb+tIuidCdx2V}^qE}-lUeSeja0fN4T1!?+>!Jy?^IK$K6yCw}Aj&2${?8ICx
+znrEU_Kq_MM&iDZ}(G)c@04$*W-;SlJ2}fkqZRfsgbB)~h(f8vl&#ND3u97eczYdQM
+ztK@WGJdeU;<f*Ymr{a7Vp3L}?l;RbVM|beR;rxEdWs=|$ACEj?SGM&m_AhZ{0rKsS
+zCxGzOg#PF7VdBD;OCM;#r>=O=;n%nMhQ-xq7>asBryc5|6OarjzupqOlt;6Px5xSp
+z@(qj|@7sD%6jxVV$Nbve$=%i?pg$8jeKDuS;9P9V=s)DdiV}=0sVXci)bNF1Ar=YJ
+zAZWkBAl9p4?hI=Bi|lpNF0gykXk??dH#*v_XS?x}8amNg&rVgJT7br2&h5kbs37qP
+zILMa0Qoo@Sozz7ypaI_KENn=&sGq_vZ{yhJ!gCtxd1E;z{jqzycy;XEax2!@4JOSu
+zwf4_pTw1c`l%v~_b-p+c|0`wV-sj!GVZWOj@Nx54LMXfSP<=L~!_fqOY`xk_f1{25
+z^Q8YC=wpU;HgKB+n|NWq<Ob?I%}u{#+$8AIDS&-Amk2pbzm%=6NOEJ(w-R&bDlC}g
+z*6JFj&?HX{Vrhr*!d9HyoPyZc3uEjy8gSs2X>Mm_4Z98Tkqh>?3i9OWhkSb6JUYOd
+z`!q_%FNSgHag_KHCDiw~;-Df&Kb)-_;(!6AzGSJN;2==u2qO*14I?ww68~@D5wkgy
+z)$k~4E|xxJOq*g~MiFV}&EoziOD3w}r67QkYiuRUQL=fvnZHKnZ?mcJ9_Ft!^Zy|8
+zXWR0JF#km#T|0bj+A62e$9Mh$gm60yAI4FG@6t5%tl`ru2ge6PY<7m;6fzPpCC$!*
+zJm1;q?fn9c%a&vEUdS2HPg?qDWY!>=bp@`%Sw}H{2Ob_qTnxqTb^^9YFtzGNd@WoQ
+zx5(^*;bw^OH;jCJvMBO0iiqBi`ym;&%M-9S-u>*!8?-7=&`1|*#eRX<OFmKAxA|(*
+z?xIz~elaokiE3{BGtcoNY*!oT(_xz{_xxDT3q|((P0^=i`Hhuxv}jk1o?r>Ltgg1^
+z#bJknI03SVRvy%FCdL|S4>`|apQA1Ju%=6L`fpjLp8L0p1pTw{*IDtJreDYdo=c(l
+zT+6Jce~uRR!51XudE8Nbo2Gy4!}c<!pKN`D@c_N4+^#<lF*8pq4+?)w7mE%MM_$}#
+z5c&za#@Oc9=pQMM5!^x&xW==q^81NDG8mHO>0jX~c_i%F0_F?8=lL!}hg5Y%mjDjA
+zvFigH)-YtTaDUrf1txI7{mec7m)#7QJUh9$lgW~}zQKK+;oXCS5d@|VcLm2{ZIT;0
+ziCqO1MMEbO)G*B%anC)TEeH~~bG*>uNLtwEki^wUBoU%4SVxI$4oCJw>`vSd2vEvV
+zNNj3eWci`<C&PGGWr72yScbG;iIYXN0dul37#1j1sfPJZ9)?D#bkf+g>k=OY8*im^
+z3F(}Xbg1y(fR1$V$6<{iB7A=phzQRv)=rJa40yiim{ec%4tKVGmpgQ_vsWJv*IrNO
+z8S9*jj@JtMR%?!?mfh&@;Um<@9h4(>FPbsdYR|USbUE=A7#dO@e{4L$*&o*OwA$c!
+zq}v~gir&W2BHqo8-sSej7Ko_fM7M`0d!yqA`}Hl}P+dZ{{<%N)aGF2%xC|0}3n#fR
+z=K&io!QnK{aDp5U%u;+joWtaaY;P!jRrbQW(z5mOgR>Xrd9oUO7p9S!h#~yZ3;c~w
+z(XjZ@B3mlE#|J=S*uP$<MV}Bu0B-oOP;WqAO@wC)Rs0_eXSCbXV)O@FuA7Db&oC02
+z0O|*^*U^~iB-zGHbU%Lh1&hRKozat43>TlwIrJZ>FIugS9^BS)^{G5`A|}<r-VeYE
+zM`o>&(g+bmJ#`35_2G7sUI)d*_X2`E?BFU;w+J@BBlT`f<gBQ!S?sQ&6j9}vFW2Ez
+zBR({U!ejXTVC>tBGVGAQ0~^isSw!N6t@Z@vr>&+jp}f@kNTGEo94Ffy9;2UihK_R%
+zoT6tcjq>n(KTK<|c#HwU%JIDBdcotMF^1}-Ovi|b&2e~+iK`CSRq!^9PE(9~&{|m4
+z5X-8(3rBm5nLx5qEh^EndgC|#s^~IFAHM6&JKLtacQ(;?-^x9TBqI~U!r#b~0?yTj
+z19>Z<fR;G-IV}Im@s^|CN>kX52)Fh6#X+MMT5Q$aHRu-bO3!KI<!$4&)c6A0GkG<?
+zgn}h3$T8Er70^|Hnj4YWiUe;CV4x_50s`@=5C|CL=`8du61l9)62KcfKebw<MmXig
+zJ@_)-Lsj8-Z1E_r4SAtW9B0}BQgK@d6N(ys3({2G3YtH{-yx0lIS+seHs|0LWkKAy
+z2aFKzr+Py_W2HM5CEy<X(5+A3+v*{zV>wVmMH;Tzh@qeD`L9v@FVVAJb@4jy@qf4K
+z75lTcE#lp3<TaASogka*EUJ!X4d(U4Cr`ps12}|Dj^&;KgCXKZkJx|b84DNC=)*>)
+zQ<ye>`mCizoReZB5<^t_p<SPtHug5CscW)4oUlR%9EjfzK&LtS9^qNFf}^bm;|I}#
+zT!d0zpehc$8E*)^qSk^(g>O;C4I}JJq`?#Q$PRDxEeyC-HO#2Z_!Rajq6YY0WFw<F
+zN7M()GO%3bg0O<Ad4K3Qcul961zWM9$CLc-=*rN6M0Mdtni#e}Og3tGB@q7Tg}9bf
+zd(1b|kr{kTiqB~JAOti%LzhJkJpOTf5lTw`5PftoTBLqvT)|$6je~7rulAr31kd;b
+zC}#Cf>`@#k@k-PI2Rm^nT}JHue+6iDwL)0N;FCFO3$}^?{-AL^i3}jG*7zY>f#_)m
+zgWjpq41$jfuCcQIU`xs;KSrekV#xYvQ|Wi#A#BPD{h9Cm5Xx+cH;PhKP#McPP|hqQ
+z^Nr6)>NON<<B$Cx^m6@>24AN$*gS-6nCS)!>p>U%2omRX!9H}sw;R!KSQ4`r4jSV@
+z7ox^TgS2r!8reo)#v|f>o`^;!z_M(^E9};QK(G)&3^d%WhPhL%#k{y+`4cXqAzaC%
+zdBCS)xfYKg)6{=JZ;tkX;OA__$Im*}ACrIxPxbA{R2sC<&Q5`W&6=ZGi)CG{-2##o
+zdDuF>9$QjZqNSdi96gQ|hSpd|b&3_B7MpREF&e#SI}i^J(xSuN-c{VM&B5)b{t!!?
+z>wRa?f8rcTjZ6Xotgbr+^b_3dW-Bq8hsvvcy%7Xa5w?+RTmc<o-je%&XT<*BPYmB&
+zm^9ldjCZ1-FsLS(`f+khi}_WK8-1_1zsLEnjN=3W@hnCF$+(%f*O-i9j|oDHCO0RG
+z@*4K})D@Q@bG^K_Hxk$O_Ve1_d%U){433J%`8r5NYUaKQvr6y_{+1JdbOR`I;xu}J
+zHk#bo+){qVE$^V2*9CB$VZk~!#%grEkp?5O`Ct8WxEn;L!?9!X8TYzu&4$~8)#X7)
+zVh-f(kwElO4OcA0b*F7mCJ&>NA>VCq8*KfvpuUFBRUx+E>0EEXsEjKc!Cc(taKP1z
+zY#Q(}HUgR&%-J-ma(YE1m1O+DIt57ib>C+b`~_Y8p?QrH6gB)j7<#K7bKpFqyWl-y
+z)vXvRJp{XNetbg>bKe4|!|$|5N5U)-OaBA?L~O)s_%Xhc%+>H5RLLp0KAI_yqqB5h
+zsm6eJI;6Nm_Z@Va0yrT6-;c^xmNdY}6<o-p&AY)$)0=p6JN)H~;KO?(dRN#==uu6n
+zyd|JNsx_yZ;|Gx;w*C9^l5DZY4)yEX<*fP^D2f`Y_&-d<jL-WKDYiiV8gdV<OSSq^
+z+{Lc~OUQo{6lz8R#u`YD78Ri>4{PFiPVjpTLk(^JBYupp8-?Q4NFv4yO0J%Xa0A81
+zmTGYaP}Oo9W;-Ywo28yalul0|1Ic(|JAVrLuRy8RzSY<3t;R%d06A*xW}q0(48d>w
+zG9bk`0PmHvByVUv9syCCiY^!}NQ$WAY1ETp(03>Ve%IRg%_KiC*}BduREt8!DCktq
+zFXFZ?)@R(`$M}w39*F(*P-nU|S_b_H_8E6+`qxHpG#4Rv7hj|zv$6+VU9NxF*Oj|G
+z2PR@gZaxE1FYbq!>pj2zDQ+&xOMzmEr+?Nu_n$MA`kIOlb0d2#{RhU9@q<*c*!sK=
+z8De7xO>D-P55%rKg&(v|Djxd@#&u}dDo773X32fD``;6aji^OYaWIV>pd;IWZtR3%
+zOY47`E(D!$(l|hUVc=!pic0W?XdmpF2UV+{pctHdtj-af4wAD-va4kF;~SOZLLWQz
+zK7Rc&>btO>zUOQ+{eXqrn`vVwG)sv;Z1sES<3znr^QzW(n@31k9H+0#W?x|6Ob&|Y
+zL7(&aY0M1dcND+E2%4iPWmS3rm74!$LBjxHBlIhI&2<bYNVB<@hKRfARD!v^dZQqJ
+z(D;KzRz|5RtVmdA+kDFXgwwp)Ejrq1e25~jlGNx-^uaFUQ|MFOFl@d0JP%}!Z|8;r
+z&q`Y34HjC;5e}teUqnkW$9FF*`huIIl?rb(`>3{B_y>XQ8^uP@utPlSl^ej~{u0un
+zDyiGfdtlg}Ex141b^{1b-F1%nb%tZ$eTy<3*W|tv=d=2*l{63aQ{10)BO&etiHS`w
+zaVHk(iEg6>g2PHT)baq$7j+qzq4l1c$bn!FMBN1|*|n9I@_rJXRg#=+aqV%Pi;fCn
+zXDYJO{%tIWrp3M<?vmk2u;5V9OE_E8^iPd_(kgkK@)p~I<`B5~^?q)>liUWc*AJr~
+z@5zFw`bo=DW<WTT2{L;L-zxXe?{3YhYwHg=-yeevxJou=HB196{*{eZZoz5_y`+Zw
+zqgkOjK5Qq{tC643#As$_=md6MmLUDub-Wrh7Y93)xFazJGh*B)w@LP*e(j0NEf;N`
+zmtnC`c@1tqtKlb5o2J~Iw#Ut=EG;;{ZGYb^&o-ce*49?62Hq?KUzWcDKg6#l%j-|H
+zv`hp~%R6x$-cBaQ+4ch1UuevNiZ~LQBjB}Xl*!Au0!%_1TH?dSNTt^ZiSdL$OAg5d
+z6cCDzUnB>Ve<aDY=I>o=<^K;{EqR6i6_5U%T1&qR>r6I|TPo-zwT*}Y{0=|tQdX^j
+zY&hit_@5iG5&<XS2hvaC7hb}KV~lYb&}%ta(V4yqssiBU<HZ1SA_o|K1UdFfr4!X+
+z+5~@W9R4Dlv3XaJpEmo@8b|U50|o;J2gI#Iz~?nlw0AjDht*YX%|XnB{@)(ZXKJwd
+z<kp@Sb{<QA$lK;{)~}K6$bpg|RuFq>2MrgHh=H+t3N6CJAg(l$SP(ljxE*byh^F^~
+zlaO{j*QDhDEp%fTz1}AO7<0+>qmh84Znhl9x|!NUZknb*AQ+FNas#Ls-+UxTrM*6P
+z$l&daIv5x0U(NbV;L5ik<B(*m0k|JDV8&!{p^X8;$0p<$kK)Vbuf~YWM5I5}q~9hV
+zZ)vs4_Z%zViZ5!jO+K-|3s$R#vMirHavB*J=uzHs4$JfI^ra$mmvK2W6prch9Vi}4
+zA0T|kF5?ZVkocVvpJw70S@_o_{wkBulfa|+q93T6So&oqy3|A;m*@*j^aP1s$n^?J
+zpTs!fG~hK$ca!LYCi-Hag)B2A{(mOEw^{t8B!0+5H$x?&_@wsKKezBxfoBXVCZcNa
+zKk5|-YXNaH)~;e4H}4ewBK>gt{EJ)jKalya-qx=E$q%ghznA%Mw$I;T<;Ul6@Z!9^
+zeg5j!{0YC9|59sy#xLeS(wd(l^B;r!t$S3HT60gH5!`RG=ib_y%Tp-GR&LLAwdSso
+zxnX;5LTm04nY+-Q`(L=Km5`?;{seN{?A5m3l83M2G{Dnho1w$*)C6kS$Xx@O^m^k2
+zXvK!77*p_Te6k8inriP(Z~%0n@M*?-EXu_dt`Qd@LweA^m)kt3*j$aJFNKFUzFTV+
+zU#Eu0vv>?UDV_uVj~t2ezuaq$$FM!M2Cpj>2D=27AXxv!fjD6WP9bqWbNChNlTQK0
+zK>fe&x^mA|Jh>#ESlZFx>wCE*w{(|0dL7;kcYnbYms*?8lW{xFJkIy)UycOZTO8PC
+z#if~{eU|R3+=tsQPzwa(uF`R%-%qBDCm|DOZ8b7fh>uOUJ7e>1NicS>?T9jy15u?p
+zk<ZQf)iqtc$9$Psc^|^cgvSPWqy|e~;|!I}6DlrkLq9lzH>2#luDIZZTvVBZDwoBp
+zs19@e!2Fw9WLB^j>ta6xPsLPzCstD4hQync=tvnqq_W<kk1?JRL&(UT7epc_IKoAD
+zh3c>X{U3J3pZ`%f9DOE?iA&NeAsCx`9)98TZ*J``zxt>3>Jy_-EdC(As#*913{hNJ
+zVU6FzY`H@sme2tRhwHGkx7L77jXcfnJm*|mNF=3cJSe5vbsB7DLiug>&G-f@U8zLl
+zI&_Ux9s`__ni_c<RWQ!xVy$e&G^^eRm8(I;nkR?1<-LMDL&Miu`dEKdN-&ucG^3%=
+zbo`I_#XX2Yv<7n-vGo>?kL_(2fdgc=nib3v-62W45`$RcMO%qgXVY-9#B7$p#oH0q
+zG<;-*?2<>23n~7LeB%$m;fmf(^u;E>OF+$bH||5TmQU82g<9;TbP48>h>mn?|H}P5
+z@%{v{-oz?a(?9pZrom#t_cSSblvJ@qfz`J2D=El@Uol`0xQL2itBV->>GQAUV(Ylk
+zB7KX9JQyk69ZiYseC!U`kRJ~`@nN<D5Ld%epj95Rhk<1a?QHjZq>CHeTrSVg#oo*X
+zpzjqo+15L~!@jBH?I=DKlYRj>8r5g9yGO7K*w{U0v1?mDanHo$S9T6R{;x2<$Zr_5
+zZq$%kEd32Hb<}9=p>fhK6S42f|1ZNI%N9qn)nbO7#Pe79IAEPjr0^N5451s&bC6?A
+z6$>J8dkQ@y9OIMVUnMUSUlIIwz;wCmMVBAsdV4-akegs1;aaC$_wT}mPO85e?OB~k
+znxPY!*j?AuQBA8LEO_iPvZyQ!9MBR=_lB^$3R#LVsFfsKKdiuS#;}YUU0fVDW*%Ze
+zsveto<{h$7ZJM}0CKz8x#%U}QI+12FW<c8VPizo2;9{$J3bxD0K}pflpHZ4qK&D^c
+zHT?R@zODXGK8M_O`1Qe`a9({i{cH0@ZT?~S^>p59_<PicKgZcXS3GfyHOwyKA<>;k
+zso@pKH5OP}Wq$;sWhs7KNyJ(^CH^>>UtWc8h0jq+e6S>%fpddXhcH=c4qRY*_&+E-
+zp3R0gKVytU2IkGkNDf@=A7gSczCi=!{KC_64v*GNHrzW`BiLZ1C*-KIqIt2^mMOG}
+zUGZ;>X6Xwf&G1Ccf2lS;K`U@?qtPe_zxX5Q5V4;3;@JSSS3LGiKj)9lN6e4?4XeBG
+zo5}{|6kwlRT=Q$~A`$=J9-UM(foggXGPiaX56NLA?5um<H9Jf0^Pz>pR;6n&enPHr
+zLGnxr=fbgccLrLgH^KTWA%xAeGZ^Gk9RI-6xDRETj2Og5IphG5OKu{OTEq$FS%(q-
+z2O9pi(6SutAEJmU#t2qINE1OBIL6C3GsV*Xf@K^Jy0KS-VMrJCI%!O&_lrVs+j>EZ
+zUWlC%HM|Jr+V<-46wDaekGIDX2L+;2G(0yK^oQnTCRS$ftt^Ob5aKu^HIEIn`ui4R
+z*)r<n(OjOkb~auEgm?xUeQ;HS-H(4wmlgw(hx4KJx&8&G8EsX*f>TGMl6ZMEYZ-=o
+z(~cG$?Shd8FTAD9UD>s{@31m=@I0)TaP7RN^2m?%cuoXYXxhdD)-PDHXwf{>+8OlV
+zvP$!LVjhf6M3tSv%XwOWUU!2bC>V_6<qZ|H9e}xMfX$UEsD$@jB)!yg=wZ=Dda+0Q
+zgQoHM-vz;aZ3Km#68uGaLYj8+2@aNgVM*@)w|scc-HL&Eykdyp?4uNh1^Rn@qnvzg
+zf&)Q-ZSKn60Ha8=oX;`%O>9GJu}BRn1Y)n(z)~6`NdTw=@k~^NZ?8iMg@&j{QYFM!
+z+yUa7?2uO_p$z<3{tHfe4cBSx{ADmgbQ>P>#KyF`B0?^FB#9yKVw72P1(>nmP3RnU
+zdZz~1acsm_>DVakCi1@Hmh3`$k=Te7Sh?7&#U3-!d)V~Yh^|C)A~4Z6BLoM!g+#da
+zHqm_~`bVOZ+R*bL8cJ^^8cDNsBprSy5S2QJ#$@Bu$DoiFeV&cyKFvPk*BD#82pK8I
+zwk~p5?*AIZW8)BEyizZ2PFy3ZYN3-Z^{E38!>C*iji_s$uc3ymOCI4Kg3U+l8T0mp
+z(GNOa%c+N}n1fQ`+-M8Wr_!SDQ6%#^P@|D2oLG#;;?pY-2YAyo{XYC<rN*<+Ih>bQ
+zJKS;!BOlV>HNE&4kyiyS(A6tdfaD;FvF8J^_cDQL)t1oD7<i?ASibW}@-S4@5MeFF
+zm<$P_vHO0dF5>@)2Az?_|5a!07CzUAs#0guK+EvbH=d)jIf6|)of#Nw==0y)00H!f
+z0s+LfJSJ|M)w|NH9zm{YRzyes1kYOak!VF@#ECl4FCsMlf4XZi4=6^tG-9#K`GhdG
+z^s8YoR+Qf7ZRiNcHh;x0yf(Xa@`l#gQjPqTa>fd`Pvmp6ya_GeTo#DN*xk@B6$Pz+
+zJcMeKCTX|DPGHYvP^5;u|6j7jd`av7pFTRvu7%XXu4|w`;}u%yIeqj6vb1QsKJxty
+zcAX2o(ylLLhl%@!YWQ_p-&uD36!W9+New;PU)Z}*E|8Y7`(W${>hHr}mL{GKlK#KV
+z>&3mNFjGRcf{aux^gY!>E9Pi_6(VupI`WV-1@s4=l6r;3gLx32&Q}C_#>0Q*E;yF1
+z+qoH;g~5`Geq=r$HsNN0$^nE63S&S$S8Oq^%0y$e(0>lCVFGa`Cav4v6g95ryLC(#
+z|BbQ#EfI(5&z{7{d<!(iyd!NAH7z4m!-dH6b5;NPiJz&TS5kmz?k3xvqkp$%FiJCS
+zUI~g&FE)UKUEzUwr5VHHRd^K)2{APMu~A)rd;=n7sxLIC&(>yUY{G+qhmdW2uvAo5
+z!$&|3QA6eHVmJh%lB*seb7R~)q7()P6ikd7{<jcHbeid)c4@lEGu}t(s2F5sX*j5;
+z*NyA%J;ZS38}Xu|XVI%J^eX<c(!~24A@~MdIkOMw?;se^d}E9`tB7&lTh1zP5zTXN
+zbNHLb;eQ|+L()V?`2Q|S9i#J=_zSQ?p?3^S_A3nK2=s-!-L3og1E83AcQ#c#SB#;*
+z3>d6zI{}AI2!jsIUieEtuCpeA$cgJj_;w?l1g}L!E|OlHQ;ul@#_fMG70wg-Xr@~i
+z^L8A25}3m2nBb9=_%TtVopy~Wpc)mW?V6N|<`l3LjgllV?3MUGK|+GmL;TNzqOf8J
+zIvo1J!-`hCnGT`o-9E*y@NV%-F`CdxR1V6a#yzOf{8>BH-_hFU58I)pL5t0AwnKFz
+z>bLDsi--!fL)8N%_EO9qL06c%1@9l2S%~Htfj6Lo4C7m<0@-HQ9mHzdwx=*1Wn?2J
+zV2rin@+l;acZK&hZa_=LI(9Te({tig1b4p}ukx@C(W;33270;quvOTH8K!;>6G6o;
+zzF`HvU?03Rh(TxNUh`!q<R{;#g>Y5c52)chRfMdMBLr><UTDU((Y!Q6eVwKvE?MK=
+zIG&epm#-NI|J*Jg4YAixH9oWFH)gwF1~|x(>n!VmO><-1lE=2cB0_1+7KCE?55E>0
+zv3-I|G5!htY0+xAg2y{~UKGT+G+~N2gA#d*3uoE5DAYXCqL1poWAz}aGlY#+v7SFF
+zuK>jQK|y%2$RCL`roesr^`|5YJkO51QM<85f~x8DMnXBE69a<pK;LjDKCr^UYewrn
+zUgaP(O|w=fShixH@N0TyogPn*m}KL3(;BV>G0~4AHpjYLyk_GJdxsYqa1*liRaSVc
+zR%l_%cr@c3m|7rOWojW1T}Z)m7&E_)1l}}|L`}G;iN4fCO0#D6FX9&xC;<WCRjXK2
+zi+(^-fmjm!)~0|SB{HBVxs9<9IuK35nl{7|c$^cKhy^sRzxKncC8?19P!|+(|9!#N
+zES2C*2mv>`&^n7A0+mcSOC<sQGr^%8Jt8>>)qsOI`!u@4h}za`Fflb;4GFmT6oX70
+z9iJY9sNnKr^}B)-vHHMWJTL#lbfx)X@d|^`>BMX`=R3RwhwoCGtgu{a)v4=(ULydZ
+zMSwiP;jG-!TEhDwtD{`yc25n?);r-s!SU92(b?9IUQBl2*!(9UOMNvu?38geL}s|L
+zE9f$Ap@K2MufifU1ur*LqKdkq?Rf>`67>8;V9fO+oXtket2}n&L}B!MjXr;3>v$cb
+zpAuK;<-0y`c-zi0uyn+IJIn=%*aE?mL&gDACwCVZvoCO`%<7AQ=!;|$t^yxSaOn%c
+z*JAtntEd<2{3IM(bEEMTs95FTD)2lC_Yikn#cCtI#E)_QpCq3&^YRu)HArWY?z^(w
+z3YIhFsoX9u8#QmQUdanj%}uTI8F~|MmKmcT#oDx*lb62F)<V461UM{33n5XYW{!ui
+zDfEh4nEQ;)OQ<UDr?XI7L$AUP5=qhScq+R28j_Ie{RnkL&!LsCqRrL9zb^Pb8ResS
+z&{pfP3%i|yHP-Ogh*wzHdFb2K$ls{N1?yN-aI(f(x?l9?X`_}pMPFPD8PWyrpz#iH
+zRT+aSwJKbGs~jnozG$*v|F1CwhJz+P$Ix+wXs%wbXFDsOK=oVE1Z(O%`A5VF55kGa
+zc_5bl6*93aN*Z^9ym<MNI0)Hi{0(KXaVb{m&2JcgN9#qcw($jzgZJ!+ww=>-?5!lT
+z0oTx$o)P+J)v_AdC)>}u_UCu>Q}X`LbJ9W(XyHLKIwv&adLij9<1dhdgv)`u#Kb)Z
+z95vIEnh8#5^WW+J8^rcuzY-<vjobVOP{C5sY@e|JjmI|odfbSKrB6d8OJf^Quo-Vj
+zVO)jRw?wl<tIpF?@pRS|LXnvYk|{`{W&&$6CNio~Pu%b}W<!s%e%l@xuKi&52+lfL
+zeg9T*{l{iKm>poXoKF#Fae4hA2o{CrD+%6@`XMP_l*2$r{{e4cQGH(+_XsCa`Isoh
+z%bkgcF!f#8YWBB2yn8FrI1G)7_FV&I^rZ^h4RF3yg&VbEm|Hhes*UI?B7kvoYL2Bx
+z22z*STMIryi(8C0Q34d}(8lJsjft}SPwYOt>{*s?-ehD6Jnrf3kU1soC>hg`9iKsR
+zw?k`f_O&_%B8j88xEB@iK5K*@*oH#H7_QOqf{#q3G`zP+!*2ku?#LCt&$uVxH<+mo
+z47;Zwr4D??T_%1PyQ{?S%kFCN`)BtO@%y%WnfP7qt`WZ<x|{H8>k=IE0>P;iZ=Qg+
+z7iX}1EsWEz9};hLG_P*p<dS95P};m&yo*<klhF|TCLuJ0z&x!?hQZ+u{J0ARS^X=~
+zOzaF#CmydMB0mh6M0qc(JDdfZjlp7E1#Ox3#EVd;;a10_Dhgh*^^*s;0(`i6!`XoQ
+zhNphdUa!2(i^&~w%}=!Mn%;x{0^HRLS&}T|2q3R5!M4vtqWjVVntlln3TUBINqAdn
+ztn=s`7e@5(?ajY~{{zo)W1trO)S3iL^>jZMijg$u25muo1H{l9_4SybJT+^QbqtI9
+zAUqsZHd?v}Nh`vXe2hyVF9PP}LO1DKuVyQ_TWxvZTab^)=wIgiVl=-b%7<n7^{wTt
+z!P^7n!O0CysP?=qUi9i;GG5}$vEgh7wh{==4V^!{6HSf1Y`$V8!<Yx_<lAqfonK-O
+zBz+JVxEE^C_y%0WP^Q1>1(DYD72UAQNF*TpWS4QAgO4UcE~tzrR<W5*lX&NMT)ylx
+zB50L(_ly(o%_0fRTWQRAhP{U1F)f=f6~x=X2#8ZIJkE*Z9lp_~iWLB81Qwb=E&&EY
+z%)!Bg`L=TaQwS_U4${++T#BR`seo*uY3_M=C+=8xnP?RF^FhZF_w~k=5Cc);;`-)d
+z*>9dL=w7yuLVk%>Kzh8xYy_z2b)t@lK&m!5Nu|bEjv}1z#h4Lq_}XVQp{wB5A8*!o
+zh{B@e2cV!B5ftai-KFepE?v3HUS~W8H1-NI{0kaZq8Jr|L!R}`*$^rW1fIh@FIbFc
+zF$?jYj*3ChS@1GCy~xJO3rNP|ZlqHj9FJYUFdGhVy+d%da@nMzQntq)kL(oXD&H7>
+z-oto4#tp7`yG;3};pbJp0QwEtP+oWeIP?4%cSPq>e`%KfjPGgj2!c~QTjV71!3(lO
+zlbf%iK0*QaJZF628Ebr-3Xit{!+aUA&^&EZ>9b%5??5ZI1<OKDnEN532my`U7oj|O
+zBA%)hwO~Bh`|Jv2%08QnEWOU^0rVKUt21(?UtxEc{pCVuoYP;%4m3zyF*K@B3G-X(
+z>d$kgCVMv8d?`$wk*5bQXW4yxzkZ_j#O1Xoy9}(ui${vL7%(GEPjnCb(zB(wML-4U
+zd^|FN6Trdj2Q-2gR!zs)88cRDz0n)o`2QWi5y9^Wb3p8A%z!u^-hzFX(#l=1>#pF6
+zq!ylY*Q%aqkLc(%Orfba|CZ&}r3k-NKSns^wHq*@8&xzyu`L)BXF3R2F)-8j4=^Wu
+zRDK1OoBv}w{}S>2`(zD|koU6u{R<TneH38?53;^`USKE2n~;$AE%~y<=!ipO`9E0b
+zN5_ao%u$FJP5%Noctc|yNpRivF3?yT<D0&u`ED!jj$ZnvD0(mu`=^q~K09Wtl^qtG
+zs^NN)hL_uj+d|0H^v)raHfBkxFj~AAH=w5%kwo;`2k^5-oNYJ`8YihA1YfTN2IBOn
+z2G?x)PENxzJafJ<#-K4#?0(kstn=7n)M@N|3Fz>nUxOvkL{zfEjJEk6-2OMl1v5sj
+z+?lRlOYu>AEAUJjbF6;oya}k_KXExgOtkU;h(Y3OcOMk?$LGcEs{&zt#uI1<f~(*N
+zy#5X^^*FeZuZ_p(IHLZl^Beu~_B(({Zu~z5;%#I$d%Hl`o2h3$Na9Swl4OVR8??Au
+zF2uLe3{Uf}2Og3<oB0ITNhQjPM}_e80_ICVxYkVv_b+x4>>De1%f4|r!+MCZ-WZIc
+zZQ3fTZXC_HLTMb$iAHJc>bN5NfyU8^`d>di*f`pG=HIJdY#g05d+d;8vtKy>@fjxb
+z9q7NXRltxY6XR0)bv&o)$9v9D1#bg!>UDVB{4`$+(xk4q_mucPQ@b~%Ta#DM{5fY>
+zZRKaa=wNrWt1mh_F`AbIUz-SL=NuVZoI2;v4}KXP?Yv=h5}&ok7p^z>@G8=NzWy~p
+zj*dN({KKY?Y8_3n#XatQztM=^<*cpgiba*rQRDN}_OHF+E~jI2Z1D{{%UpPuOhavL
+zlBWUB*(5t^`)~4j8XVj3B-<v{^RZ)7|0A9{pW|a+?3t9mtMiWP8)`r9?m2|AeH};o
+zH+eS1p1EjH!&9SujtyS@Fqn8fn;lKw{<U7u;gPZBxAqy8wv^(ze2$G?eKQz&J++Qn
+zZ~u)bh^7p1JU{BR&#}p?*Mgzfvk}Suhf!u^ES$0Z#j0Xfc0&NKz7d>3)p5kzf3p|&
+zemomT#-17W_v3i|3d#)r1qtd=9DMmGdMY@R?I#eb=RYRGD}U<sd=3F_Ui0N7odkyZ
+z9N&2LdLhLpl;TIvQLm@o=h)#xYtz6S4c-c|QU>&@p5fKEc|Ilo=N@|TG^-DH82VAP
+z-?P=x)PKF#)8IMkh(}A@87AXRvE|n-%9{Iz*RzdW`#YEWSuN4$IOatMu<e`3^%$yp
+zW8tn-ue|IS3#9naVEve2kGkIeo4m1S)XaZo)-ZRl*K^G0I0R{GYdS;ks0#|Q<u~1Z
+z|F5nRVxf-DahNP>yFmdSu)xdn7N7rC<BB+n3-+688+wAb=a{#DLoD2Ba`N@tP|#wW
+z1OY6@-Ny9wC3M7d!FR82C(q;#cwV^S)aUzH!2L^%+34>+-P4~1T))IV_RM+Py5597
+z{lyj!dFs5aKXt_TK;QebNq1;Rj628w^Ck;8e~B>_e&SCDe?FHpmWx8&L%&KWeV_y8
+zeVz^sih(Z_J95~`mi7wI?tk3t`ON1yS^Kf6W=8`&mdjh)kmz-6i-nyFjy?30e%Q0w
+z2g|QT*5KOO9_Y|mIBh`wD>Lz4BE0`~lLOSxPs;fAG~NqU+mOt0>p9|Rf^SHy-O$Z(
+z2o^WQw|~u_@h&R%GOWb04VlT3O+##P_cuTL<_@r_C7aE#kD*iU_~00grUw|HYaC@C
+zu3ZDZ;B~|YbF527>SNC~A@0!HP2C(Y>u_4bW4})oOkhCAybfCOc_*)ab-%uutUQN7
+zxpyS(;1^!UF>=~KmjMnKrH9}aHbbVA+FE!a$lLkSg^A#VfwV~o>n4*;Y{{^uFTR37
+zgLbEHf4B2H+B9tf!(>x!T_UX&P22|VP}gwq?IAUJV%}?)+coI~C#lK8d*5D%=i)Fb
+zd;<plBsGe6{Tzetj&E~p=tdEaWW|;beW7JgmRJ8*ZCw}d@h@PHf4O4uUmbP&dT+Nc
+zj&JpP)<L3SOP>2#|J>*J?)c}m4c#5vx*hdw1?4{V_f0JH>OVT-US!m&j>FwP@%)I9
+zI^@}ZCH>l~f9%-qJ-!8w1|8M|zO)<c{1X^nxA{LE#3HE{ZpeFlGZ;JSyxq2VJ#}EU
+zd2%>{8gQ-K1S@YhIL^(|(SqY$k1Z_)CsaeB;qU?7;B%pAI_lW+8+Ly;_zZZ->=d$u
+zci3opS~hSqS#5?ZhI@wl@6k8Q@h5ochVFvkP&5r@2{B&nh4;8kq63y5o*XT1USYGa
+zvyJG4jj_eaPdql}xPA!i(~sQz(eWnKbNae%@N952=^xkDbUD5S@^!28!Ge#(miPEz
+z%a?<EaQt<Wr`u82ZL_C#6omQB=T9~}4(kn_x}u5bq|Mznc^w-(+w`uGRzJjsIchrH
+z<?J*b|34U(Z>=GKPsfaYms1~~REdM!c01z6B{4)DMXmQO<^IxEb6YezKKX-8#07r+
+z7~YzzWAf^|AJ+&&d$1jVp@at>2cGf{+xqZBURZJ8TH{hjQ(#!LSo%Ng$GbfvM_D;^
+z`Zo2+1ql2DI{v?tAH_NVi&m`kwa|e~<A1+F$P%j0)KKnW+&s;$!K?B@-`=K$cGu*@
+zf?YE4z)a=Y&sBL57WBnCUz(qmaR%N{=Jdw`!|_TMqx^Q>5Y+KTGXw8j=lk@=@_l-D
+zJGIbWyiX59-FKeiAGk@rps)OOzMOBPz6np@`J=;c99FC8!-td~Y>sig1VL~|;S)52
+z!Scgc+TaS~1xpha_EN*eVxhw~onL_W4f=YW5wBg7^7ygfPSG64L#Lb-S;y)@<7Lv=
+z8N3YjyBw=eSlBh#2QR8q-yh32Adc;NM%IH;{Elz@1HU%*R%0DhV@0HB5ucRTyXxDm
+zHg!dt#+z;WGM0FYf8YtTMXP0tK0}LgqDdLUu>X;CGg|bTrzQS(Q1nJG(0l21-l*?_
+zpCR|p;wH5>+J)57lX%15*sedvA42oQdgv&ZM7TkS7fZHVgJEG89o1K_TZo<i+WjdD
+z$GW?UmjNKrMX!sFO0M0{M>{XlTnbQ~Q83Xh%XPBK;UzM)MkkaD?Y<3V9IG>-rGa(&
+z7W|JVnIXLIQ605e3+;CrL!V}di?`c+w;G#7is2^Aqe24<BQ2Jb9K1G)EBlNz8-+0A
+zTcWu?<Nd%3$Da`i=fd%)kytqXXKmPq%FnTLg$KLjvIoDppvkqdxQTf>mNP+KmgO+w
+z5r(-^?8<c=_s_o5dGm~`L14sx1zes#t+=uxFIYUYu(UF$m|%Hfu)Mgi!UCri=1*e@
+zCBHH_y`r#uc44`aUr-P<laxVz4y`RO$SX(byqWoBMa3nBH@gb*XI&k15$C$H;%5BG
+zlIN5IcUNhVYi8lh((<{Aa!&rt{F48Ny?24Gs<{4u&)j>HocqYlgI5v)Tp)q)z99hu
+zh$avq0Y%<|q7X<R(U8O>1eB+O6crV$B4|{K)}qyxTD53vi>)Gms}>(ss#eiji?&sK
+z0lvuh`_1fg?@b8W{{L%z>-*O7taa|}J+t?oJ$v@N&Y3fJac%w5it<o(RZT^xss^G4
+z8aTUL(<95FRpm~Oi>qqNLye7>fsDjR43(EPmMtu6sG#tgiskbwYMMrcTIZYHFa{bT
+zy{x>vz4TT|HMNbQikjMGODaPRb!CexLQoJ9O;z=^HA^dM8bdi%H8@!rIflkhnLU3-
+z>G|XF@Yk{i+}YCNi@A5*(b7^0oN36qp`xZ7KeY0w(6XAch1C_I#@diBkQ42g@f7-+
+zTG+a-`m)gC`r4(T=|#n*vu1=07ww<DY@n%vw)xaoENUVPYiLw9tSC8rC!NWyssSq2
+zh8iks>l;}N>b0n{V$mh=252)1N-e6WYC`R`R;j+Cp{}+D23lU#Sc!USDyyzS4Oi4G
+zX{>BlPK?bLE?c~~qFzi71HoQZi!VD(23pv+=~Yu(GiYg9<D$x{nk6CV0H0}JRU_%N
+z<#Wnl>{4E}q@tm*oys_+;u>lfT~g7g?cUbr3*pMTURWvoBc>tC>dR`%YnPrPq^`EQ
+zI#P8wO#6mH$SP~9E32xXU)Io2wWMZLXdzl+StHu_!exyW5mUEMS30$6c!b2Mk9Oo~
+zx;h*pUbUh%IW=rUzpUnxn%d<xF*->56*{y`x_x^@rvBQan~gS8TR*52oeVmIR&+}$
+zQ0R#JMN8hk$3^vR%{O~SQH;jz^L|^t?eIHgY^D3@@^^@%`e&E3zcft+r5+UuuYh}e
+z7k_I#vdage+0b;5(4M%{$}62R^Z#Uz(y2wo#nZoA#OcaYI(7E&|3t#K@lTyTenRP-
+zZ`T2>Njuc(<P;ap9RKYSv^%!7BL=0)vWAG8H(pj((Uz_X-C{jD1ayhZDne|+p&V3k
+zUB6IG#frvIU1R;=NCXC=DYMQ#yOrP9mDM+3{5{2S+U6s4ORLa7pzDJx0IaLVcvc>&
+zxO7=rb%_0j;nMxOv_Ii%J$}ZN^K|)}0y(`@)UHDB^q;y*!6=LoqQM!A+ACixdg+2%
+zwS&{@L8Cj}MU38!wGE9Jc(uVXtkJGCO2yK;Ml&yw@(bN5_6?mzE~h|M=!&8fnMhj}
+zV^rfs@4T3MAmC?lcf`KY&#?dIW!w+pz6N&@;_k-I+j+Q)aX*Ajv+rU%X8_xi@5lD@
+zm$6B^9QS72PyPZj5Er$z?qgfmT=vkxL+8YpL3e+xNkU%Vn1L342U_#8!+Et<c6GUx
+z-7qA3nU%eCNOt*<Y|OSwMrEHfDtm^NJt%KzLugE>Z+1gpJVNK(Pfy&~Q<cg%Ut8B$
+zRa>K7PEY$ni_5C2m({Z=w4%qPro3Wt*|KW5Jti1>o`pK*)rxLm?UH2;A(5)vjZWvR
+zb$)GqxtULyf#s5l%a$X`al_Nnq2`yNz13ALYD9Zz%Y|<^rcXb2I$Ie=nA#;ZRhNUx
+zC}2d>=9o$@s;yaEwPaMNYH3|9+8L*Gi#RV_h=F`jC7!y2&d|)Ss;NS&uc)s_)`Y7t
+zCAyp~Q)Y4S&SjW->(WQ~=4+pYFLGoxf*d>4qY+~cQeny}`5+f$(wY!`(sJ}koMAOo
+zm|0v@zNY^#<Tun~Zv7w7v;JDIK|*JY357#wc~#Zb6-&yhO+jPmWO4GHbk3@!l`QQq
+zwM(jM=Ia&CDMDh>&64O83ZoC~sMk48#hPVKZCwS|B@wS`<Dad(q_r>Ue7Ue;`zT*l
+zS6#KJ4AV35WwxA%KefvDbPfgmxL}B^BNo*zt1jnCOsi;?X0eK%mR>JATF->diV6*I
+zV90ANE3cDfA_J}pt?JrEs5WUCZOfvIAzoOuM7+IqKSRCH<fDsC%<(H0RV}WnV0UBE
+zBCF4sG}AyD92!Bfa6)T~N+_>d#9pTit4t9Vjfo+vjyj3eP;n`RXnKK7Gl{4r)Ut|}
+z#jmCpxD9<xt>zF7G~9-wt%IFvqDXgYx;?Ir%gh1-U9?p+bLRBYv9o55x3Y)lHMG4g
+z^cUz;EHvwiB^C8nRUL;~1Wm&ufEi3JtePt<Gf5m{%`Q57)_5zcbjrB1XB9&<I{yZ1
+z{FLHBv+;B8bZhMRiKSB<ge}D>M%2dac4B=oni7g}$oBZ0p*}KhhA?=D6*zfqCCN0?
+zcJp`S)RZlC7C_%A>D%-%Gqi8l<=go6gyGxS+bxGP^@v$OVD$TTleDKtYu9SszeR0|
+z!Apj1Q(ipasK4yHvTIjwM^3aJWfk)sx}VOU9C>)!QoXFa0*_$6TeJ4;;K+&E^Sc#l
+zPfqK4fmeU0m2^8<Qqefyw8NMtg6VH<byG#C60=hJt24A9->SO#(b!0vs;;fQB($tf
+zGlUji7GiS-Q@Egdj@S=Vg!UMbeTcIMM`pwiNN@DQR6IsChoN+;&IE~IfnKENBa2w3
+zQ(R2wPA4}i(>yz&Jl!#Yk9KOPUt|gfgilT)rV-m)r)6mUoTZg4jO8_$=V=p9Dyy*)
+zeU`Rcb~s<pjN6$tPpDXEol{nC71h-vyv&-ktOj?rRkUo0HKU@=Iv2y?l-ee%xMESn
+zp2)Lmu~GQcS%WEG>-4JHMUB<5oud(Dt=llTNOg6O-i%E;d=Okv-_o)hu)VUS<siZ|
+zg#2!K4#H$?F50~gTZIuGK)4g(5rq6&(7vLj<uJk=gxqM7b7f1*0)zz{T3Yrnyb9?E
+zS0GG|v#b*c3lXMm1RcXoEiDHSu0UvEoBH-^TUw?fv^OIkgeS0f<0!%d*m+WjJ(dO7
+z$FdXQA?*3E@l^Z>o`23kn1g4abqEh2+=S4^cELRe3lJVeScz@Hm~mJK@QuYfgeR~L
+zI*9NH)<S7mV;sWzrxIZf)<U}xreQ5~0^weS1%B{j9aM+#2*RBR=U{D=hCM6?@DcC|
+zg!aQNE!z=RBHV{?H^RdR=j=tf6H%_;pu7y9fL;g-evfh?tVC#I7u8;bg$V6GKpw(5
+z2=^d7@+{;aOnVOcAgn|fPJ;dj=P-O8`XWp_2szl+vKJx$V=?UoloR20gu4-*KzIP*
+ziWgz$6ofCKTnKl+jB+D9^k?LU@Cd>K2v59%{1C2qwWTE|6?QoUxd^wv4tWUeH$aDQ
+z4#E?RN0`<D_CQ#GFzrp)3E?J$`w*T$Xkoui&Rd{EX#WHGB20T9@(}Wpz*3h_x73Pc
+z)isb{^P_?+q;UiHrdr5C-CM!r3Bj~UN&e;bI_s>A(f#wXdLdTx7b6U>Xla3|u&*+h
+zTpF}B|2&{Mh#$lFqG0kyS5Yu+z5Co?s4AESya;sFNZNqA5OhWGNo#B{`3Be6VA}QW
+z@xjn_p0UB4&2dG+@W%L}V8Qx?bAsz!?%m24EI?dQFlTHq1X}Qn4cf*2%YvI+<AYmV
+zQxT3O<&8>W&P7;+7+t2%kWFZHOG{^j&^N6l7^2GhVwrgcFVnj-#-vY+P0yF~u97}E
+z7@8cLK2y@WMfs;X>9k3sq<_rx_R3ovDeuJKPUTt=+^xn2_o&Md79nCLia+j@;uoQX
+z;MFJYmmz;2^ylCB#K?!OPO<02;8ELsTl@CZ0tZ4w7UZm3+tR`l;$rG?QgDy$+V69!
+zvRLO&dY+L#6@3*CX=eVLS??R&MZwT|PrW8bZ7~fO={JCW0q7eUF+SoaFzaQY{sSCk
+zf6$%?ZudqP>*pcR?*YB8KlsslRJbFr9O*Ah`f=FdJIlYowI^7)G+0*>tSkyHD1~WZ
+z{WhL8&hI)mSXmLQtJFl0YUSfT1ATA_`rh*yq00$p*+{=#?^z4GjMHve<VWczXb@zq
+zpGNT2fv*d~@6>Of+uh&QuD|R0p}Z#{rx1O7Env#Kj_qf&yEquy=s`)=$DI=lSNeiE
+zr~s$}0^L{^w2mMzF3RiZL482p5%ksHso%jXmHQocy9$njM^Iil<XJbgv^<4?@~)?T
+z*U?U!so%ypSbTlF3vNvnBkg&je?^-Zl$h=3A;?<?c}r2xG5!cCu5*pq(X&kSPmaJv
+zehO!OAfd$Xnh-%I_%DiqA&&mj5&h7Xtt~CLwf3KAf27-IG5e!)gN3e_+buk@IS&b^
+zw$t&EcDf4r9JsNi#ZUXdF4FI{*G?w|k9yqe+i#~6DUkj6vyit5V|E^3=VJW3h~I<w
+z+ZpNF9K?{M`{%C_Ux01L1&nXiKbHm5(2ui!W_!!RTwp5b@Xdl{!IRg!=KsNIaID{A
+zq%T1F0LY6eN7P<0g7n`Lg9qKN8{0M51Z@}A?@f?b*xb@G`@7pmG5g0Kw<`~gb|E^<
+zMd&z7q~nBa>iZexW6m<@boCn@Zzcw}xZU3N?XKHjG2|6vd<<dEa}@CD{ToHMUC;S+
+z=MwAYT8!3fGvpkAoDb;N-|i0+gA3dbw69i)w&NKP@do5o;(7GB->O$rFb6$Fq}7oY
+z7wwdZPIU$N-#(q4bUV=F@&xFU)V@BZeAK5J^3pITyonh^{q3A!s2q*ZOb90XU4@Yr
+zS?ouL3WtLuvcJ8b`hfp_^20tdu8d=UI~5J_3ZL%aAP60tX=ZwSc^7;~!Pi7Sj4!Rm
+zBa<^2jGm1k>4<)>5ML=)O1b~z{%T>H{%WGX9x<`jE%wi76T?mt7yW)S@-4vE!i!qx
+zi~d0RN%-aZ__I;cS5I}L@qX9%Q)5k`AUhNHzaYN^bMc{oY5(=?p`_edhzeltU5WHr
+zk#uy9NS_;_GIH`kxAQb|27-4c()S^qr{=}f^R!^doem$7njWhQPCwfK`of>Kw2b)f
+zeh~8&kNb}A7!O~DyfEIeeBN4Kv_Fda?Tp}ImwR^m!<Y6T`fV08J&d(SGhl1VX~(b2
+z{($joKbq3B7-XM=6F!ellKpQv_zSUS=|g_G=+CPVKL_!pjElAh_)86}WIEu9YyxKB
+z(wyXb2z+(z^3_K8CbYx%FYs+@m+$oXu|Bf`sBiFH2mdj8j!TT6dV~9V&vkK|<JTv+
+zUv>MiY|!>%d1r#&`t7OZtwwwr;!BVm(|+~5umPHz`I2t*rVWFPet9?e!r<FPzNnor
+zBXq5Dyy<KtJqx<+p!<q+(f%`9@6mp}IJi!^e%J1}VVVrvV<y&$CBMTw^Sk>$j1$Ur
+zb8x$!pU>9e7B&A{<Wt{OkZ<p6X}Od7PLB8$%GGLKRN-sKu_pVmWckDXXP<kX%*Ia7
+zLf#z6(+`ex`)2!{=Ero$p5#AI581TmXQ0~xI=mj$_T>CIw8kg1BSxBbo{0tB5zw8-
+z2)N@C$dPW<%zu%dgS9ok#*L{@`0sj8X>gC*g&9}~Gfq>P#;)|=M)1{v&sqP(_Qw;0
+zdt8^tvgz54Str~NKCa>Wvp!<|V2^86q+2P4ljADJ{RZi=rtj0bKZQSteK9XtA3qWO
+zDP|;`^T!U$rhC%uHw$b1(3AMEOiMOD0}-5oh&06WXq*^*N`vcsuHzAfOu0#44f+$H
+zZ(}d4bJlxkD_JGz5|h3e^d(Q>83ABpU%kH2?S<<LV^?D!`qQ(ZKLGl=*7K&Q|3~}1
+zNx^j<_x^9`M>$?(VxoBDKub#v^9QdB!?X++dR#pN=>`9TXGctr*2k1!XnHVbaxi?M
+z(}^LO@~S~U2lT^)e!c4g2sG<Prf)|23Z#c4=@&cGOg%5ZAL*NrUevli_4qhBx{knf
+zuvJY?^e<{N=1%sP7@G0Ua;Vif*%8lR>YkDH6w8gp1C|Zc$~psgKGOFgy_^x~XHHpf
+zO=53=(YV!$%Vfd+u@U@7!QY?!a<Tq4Bi{aFOUs`zZ;R=_CbY9|FGddTUnZQsgQ1>p
+zK;CvddrFe|<Z0$Hn@_P9c<Fzcc*a!ua!X4_YyZY-((R6p;}O$=<NND-3w&>Z?=A4X
+z1-`ey_ZIlx0^eKUdkcJTf$uHwy#>Cv!1osT|Fi`>M!R+L@~|-WB_fmdn)JRB4v=t&
+zgn1H<kZ`nwXGu6t!if@2mhfB&`G|qn+juv}%fbICI3DHcD~-=aa0N_Y?URQnc%-SX
+zH+GpYUGS2>hBT!2Y5>BkAbn*>I91X!1$WXvKWSd4=kVDHF2362bpZQnc!^pT_gnG8
+zD+hfwh<@g25uOi9JRiyF>u^X1BG%d@gnTZ<OV}-(wWqIw9wv0+ll7*OXgM7H_-LM&
+zlix{se6>yr)*`r*?@__e5W{>SI36MX|MJ==_1ISVW8xq2158S13HwMmT*3(w&X#bo
+zgiR7|lyIAb_el7Ng!?6YMZ)(aJSJg0AE@E#EMXrBhf6p?!r2lomas{}jS_B?@E!>t
+zk#N6+uSocwgvTU|A0+up*hj+Q5>AkCwuFl%Y?5%Jgxe&%N5V%W+%MrP622$lF$v=b
+zOa2n}k#M+#6C|81;bIA!B-|+BHVN;M@DU03OZbX}?@4$}!uTPQzl41x94_Gm31>^V
+zSi&X=H%hoo!h0lqM8f?Nz9Qj!5+0K<UO&`E{Y%(K!r>B5kZ`tyizRH5aHE9VB)mt$
+zM<m=Y;VTlpC*d&(<8!6_684dBxP%iVoGsyE37aI`DB(5<?~(8k3HM9*iiGb;cuc~0
+z{n8obm#~k7!zG*`;cN*POV}jgMhUk`Xi5|F`)()(ITbYD{oorLd=~P*xi}s<V-oqJ
+z->Cg>q?!IZR$lDqEB_mb?AP0oCm*={_Y&L6b3TCi?<E<Iw)Vr<tIPg(HPODj=*LI@
+zI}JIE$J(#m<1+pW(QV~9-#YylB3hBQwO{l*k5**=G169^@jvrr-+wG5hOn(X=M$_L
+zlK%>9E6@2v>%S5bL)=!Le4omX0;`wC(EX=iTY0U&iTqEcMCsbLH<9NY>=GsX524e@
+zbH1_s52ZxO+R9t#eBco!`LCe1_A~xxzC`@51PO6ld2MB^Ya8)j;uFV>8x_i#wQyNY
+z<Fe4O!TE#3gN85DSnitK;e*5ZgY)~D_|VXB?(p#N@JRg*m3DJx>w9EPmEuh1+vvcl
+zn#)?B<j^0~8>lU7Qe^San!(V2gr$sGwS@4Ov%J1EnHnVK*U;b7D?(pn5?3U~5XFFo
+z{_L?1{mv;S@u;&{iJ>KE=<i<Q&~I5}2+npEGwsq(*x}G0zT6P(^|v7u)X2Z`eusYN
+zMw9T$x7xGsK8JqY^@d)*&lZ`nfsudBQx5&k8%*jA-zvZGHHSWYi=i)%6&eE@`IFyp
+z=ywYJsMC~pEj+<2FKu-XfIvJdb|gH#Jx6jWdlCG^<x1!RQkN&;$H>`bC+uXP;wyAo
+z9RH%r?TN!@q)3b7hAN$bYyCw8KOxZuf?#|YnRzx)*0qd@v*YcXnWEyWLFU<r6!+vS
+z$#xFh&vR(3VY^KSaqAHzd<YST;yxaOz&?f*YTPI1A==_ML{{8!TGzG@5I#XT+5Q@W
+z<GvuAW|zbP{*rLW=Gn$^UlGo+{|sSqUlR`7=aJ?c!UgsR_>DVBxX_zU8cPu=@pd4Q
+z(#TY=4_e2$G&09KjM;hAGEgt@b|QbgS_!1m`ydfpQQJCi1*HWv(&+6;Rf4JlDJ#6k
+zNS3O&r)iyc1EqCP+{|~Sm#gl$j_L}quJ`hLh`2Ph6~QKNHU;!lbs*T{ok?~2sq27j
+z_g+AxzeaX?7ZMquk=@=ZA_FzD$6H5au=)vj_IkMmK5mHCZJ+l#rsS$y5cj0z`x}$C
+zC2U51X>rXgr2Q|dcsoJM{)l?q!Q$F>nDM(<+GH!<E=F9uy$_h56;8DSD*-T;RjFft
+z;>32aJbqX>KFo!lCk0aDb7>F{|9db#Z!|#7aL8duwEX-lL4N3_#U@w@72vWHMkGQF
+z`-k{R7-{^3PhAp55%wT&awL)_;Rxst+2@o24lXTQVcAm*{g*)qIG543{d3Bk%3MqA
+z9r(4UF@BD{m#Nd)4z^o<dI&*L#D4`~-h#Vq5Bmxa|I^T(k%ojMTH}Drz9=2Gwq1;0
+z&>bL>`BU~dbF#VSu@`0`KH26bb9>Pcz-e|KnaY>r7d}nO3jT*kj(wc);x7S*gE%G2
+zvX`*r1@=VBsXTzxz4ljl@MKr<bH4pn^6ya4c$+%J+srcgZBWMB{SlFJCe$pj&r{6C
+zt1U8D4FsFz<)aAueC;e*-c*p;7ic8M`)?xiG)owAhEYx*P*1hzE2`*ykpyKTM+;r3
+zk)B5AA}y!b$SKz>C6Ke4axRB{VS9;U@x1)x#jX-L(}`Rx`e+p{(NsBLeG1gtZ&+eo
+z9cvBV6L>1!5tZWE$`V!6Wi;&>4sFQlunhtVlwG54MWnGqo#b1>d@qf)L%rBx73DQ3
+znslJ|Rn}ai<_~w&>Mc|EK^XoGLFYzTYxWKFW!9aZB}bDYobnLh0(-qW3r`BYKY}v$
+zRf>(q^7cluy-_2|OINmkpgSbn`%@yDv@XeB?X*|xlr--w^q%%LIwj=Y2{HDyqJJqx
+zZ`Rr5c+08(bsAwk?x9lkjJsa_25{%kk%1b-mg)>4a3p=H=5<iC%cC+yNlZd)8VjN_
+z_DP)nj1SSOIfMZ*y}lA@gm`6~g)vNJ3;;TkC=0AI*eb6g%2KKfwze0DvTdpi_7dDW
+znZc5(u1p;Vv@6T1x{}wm)#}Q^I+)$%9nobPltlsiAiqp{M7%v7G2PBatQw;`14_rG
+zzbQnhnuE|#D?NtLDrUSNj-bY{wqGa8Z*bKZR@fPUGT55bn2sQJgD!n(!xBrKNi9bM
+z&Dc%iGnrKb(5`H428GhywKWQ<l6&jAwLRuBpCSt8pYZmmNd`KWtTb?_%2MNqT#fV|
+z=Todk_n>S&`VuY9fDU~zX!g*i8BgNh5Y@JsK=d=BH7JCdNOT}f*n@u>uS(dR@xuZf
+zSFzkur9>O>u(~_`eaKRinnCQ|dSXq_T~u-RHF|5NW%W8&%$E*7xD&E_t68o!_?_u>
+zAK3*SUcDB^5IxzN=y-%^Sq#zpt%>6AGJ>pLHwsZUvI|1lnCv<`L|qn(a=9St@{S;5
+zfb`-&AoHRNPl;vsY~8dbzPFm@!j{`!`9f6+mZtWoJX`m!iMP5`3LW$5^(#SU0lCjG
+zdA9DO(3zgC2efb%wz^z9!f2q?c|s7X^Vjw=((1e=R8%JpH4-VaqqI?{SE#^<E(6`D
+zSUUIC-D^=cHLSOq?%w*ZHNDjw74EI(LZ4m}g^328AIs!*_ly{{Oo*s-mo<XuQg0Vz
+zDN?p+_L(lbA2UN)pNpmZP!QVZ8Iw`eK3g37^y<c50T&Bl!J8w6l|pFgD8-4`QgkU2
+zuFJ?3Z<~hBW)yF4g1>f4p@%<Cho35xodNSw&A&%3y175j=KdmX)7&3tbN2_F=KeUv
+z6%*CX{c$$;)j&;i|LqNs^$5_cGRYtptrE(+KUK5f0tjZpDhQ^r5<XSaQ3(j<uo^H6
+z=(dKf>;-CACjz=tJzT1J2D4!=`T{llh&t#V=mn~jgEg5^=>@9P2-K+b0#(`vH0$bi
+zRiX<}A?QVgpcfT_Ui1sA+ZdYc9V)a%*t=32T&npcN1=D9Pyj=NG1)sb*?6K_zjvtL
+z8lYMCw5x&1+%XFE5x=BCZl^&$V*Y!CSzc%%|FJA24e}B5|5YTzkC@?6W_Y083}cHN
+zlO2n@5^kctVRi?F^<$P5mufx^i8{M)m>oCsXS}Y-Y2i&o^}wXp7b)nn&9L<iyQ(^%
+zraE-$y+BQ$-{SQ7*}9Xr^dS8<lKc25TIs2Ud+XP0vUOMP(&=MTaPE}u%iS8^2)tK7
+z7XR#ldqPvTm<If|>VbR55KU-J6zzd86e700m9a!l2QplDAYaEey<V$@iGA23u}rQe
+zC@~HHRj;OdwjO2!pA)~v@?n=aTugUt*9j{-HhzK;(cG|lwjN<GyF;jS=ktUhx}o>I
+z1wP{4&811-2K;#MC79!b74==Da{i1u;B7yvat_0=yzS>yPA&*}+sc(Q9wBe61ab~T
+zB5(V1mBX)8dE57?oL=DLZQrYM9)mpI_5-TlPY}o3s)T2F^mIU$;8(yNT!OcKHdBY3
+z{!dHrxabl*E_Mmdb@w&U#94Q9u^r#uV%x)|R$xd1i}@6^w3OYOfy@3mN^5!Sy$o#o
+zE=DHXtBHl|_lOnRONp)XRsvJrTk-4ieugNI_ci?5=x-At)<-=&pP-}(;cmeFdVOzy
+zd@EuCT;JPfeII~|mVJB!e**{jdxCIsfa`nv3&LpuuJ7$H35Nn)-`igi&IxdRZ+}fV
+z9N_xi{)TWt-~;^HCkYoOrjy1}L`o95zPFV|rY8D4KwKJ`lgRbG?NKj+dO>0*^2aMK
+z2rCo0zPDw4pUCySE$jP4uJ3JG-zOd;nXK;<xxTk$eV@qnz1>m03D)(AT;JPiiq_ba
+z$o0J~>-$8m@9lo-N>Fc4<oe$3uaTXJT;JORG_pI9>w9~kM)o9feQys|Tfwt8k?VU~
+z*7u2A-`lzBGsHb<1-ZVrxB2z@-fm_g16<$Rw-dAiT;JPwu()=B>w9|_dqJ-6e}uSr
+zn-!SE3Z>e~Tu?EVRjFe=V9~Ky-*YAJ)hl_O)Wb=_N?xzreItqy72q<=XIAb3u3vqT
+zl{-07NFxjCRI`fqU-Sm~xQg~KcpIP<n1LUE88f#7xr7(~18{PHt7!kCZZJSvfU9VK
+zc?EvqIndW%@c`hQ09Voe#r*5Ra0jlU{YyRsTo9N@Ih9F}vp2w1w7=>k;`dt}%_^EY
+z#M{i$|28PoR5G&(aFMH0HXz38P*rZJRHGEvfvO`ZXi8$8^n%-eo}xyHWb@Be87RM%
+zH~>F>S#T$E!R?m?cOn`6^E3+=YQ4eQsSl{9`sXW_CXownf0@Y9LKkYJrx7X(ZX>5$
+zvv9$E3FTZ4JB0m96fKd+1-HLS<Z!|5mj$<By+l)S!Tn26>*}R(bj`0dcoK@zId;MA
+zujYsOnzldEG;PT0Qi@)~-B}M{ZZ__;GfV_KBrClG`xM=j-IpUVWB&XG-~!eFq<41x
+z21%}OuEMXSO&^ce2XHMS(gTp-sosDj_b-5V9jI|i=o+s<##$-NE`0!IGM*ip_DF<w
+zN0fGlmN1iSJJ`^y%u4~Qo_eAnW05{R1xc!z{{+yD^OBx~{)ExFdm(;QPv(`7iltT`
+zAJE?Wkm}yLXL)D}g=JCe=}7Il$WqzV<!3-b+OIU)4ZhfuuBEXV#4Z)&Y9e)(>O)6+
+zkw|q-y`}n6zrh_bX3@YQcKEn3F6v9=euR8`*C1&#XnHRK@N)ul0Q?z1R#-TA*its;
+z6RYq$)9tf7*;pd2hLAq2(6@z(Le=EKobZlD^a)D%RMLJW5^#8<nyJFzS1?=OL`nWV
+zl4pStnRvGDULFr3uY1s5ttOi4Bq4hqWPPs{<S#(h86Hd{z~Qn(R^R6&^$1dLF{!G=
+z>g(wE8KQq4VY2#WoMG~yuxBIj)N!QMcdR6G0di7g<!RN{-DTKN4$*fyCM#CoNx~5T
+zM`zS7jRrgQT@VvLI41tqm>i~?cr{e#ut0LK`tFM1y*SF7^D~L>g1mBmDM*OOV}c9-
+zlJ#dnSO}=2OaTho6o6eC8?J7pFCZ7wg56eTI(@T>o!McL^rcjbYNi`&N3SB(6+>os
+z?XFdH^d&&)lb6sZcLM40JVjL-uRplF*EPt`mWM=W9{N&sbGZQiF_K;ZOYd6&oCIL?
+zc?3{_P=^tr>VHPcHxS(utGM1T0JxmMegMA&khN5(`N1J8VmY0Ji;Zlobl}AJLysqf
+z1Qh!E5F-2MQO#v+=KU$ufLYH9=~R)1>bClBlSmquCzR2^`MUo0L=B9Lt(@0{lC=d}
+z4+OD~1|PsSsIEFJ$<mjg6S>i`?N#hVUO|Cq%pcI0y}AIYaj;8(<$Nvt^C3Pb;Y?i^
+zi-<Llv*U!_9M}hPcARi8!9na_&&Tchl+fU3pbBsIuZD~R&O0Gl4c?59ci`MXTadaD
+zccMjTNE3c|yI)j8o<PVuc+xZE6;Si`f2;=o79sD1e}|n3^56%6^G+H%<gW;LCvR7|
+z_8sy1j}NRtKZ2lJa3@-X2K^g9f72+TAzy%=xBG9(`X!pA$9f$Gk-0YaQgW`{_Pyq_
+zAo)MdwcXLVw)?y0+U>pA!jo0hM8Y-rvE?1tP*j39<{g(8m5g^>8%W|kK-kQIy_^Hb
+zeZlxNFMIJgGY9sXcU+9m@p29vXXe0O^Nx%01>O%R$IO9!oCD(>7ZXZ+@{WthR3GQS
+zc*jL#j!)ikT@304J~lkO<KkMS(#JWl^N!0`L1{7v_Qk&A@*N|Y%z=FysJzU9eVI(@
+zsG7jK-Y4(4_{?#WFZLamPu_7|3F_@WdB;U$r%&E-5!vmNcU(mF_~acI+w5Ln>^m->
+zyyM~#icea8^NtITzhTX|W){+G-f<DMyyhJji)(vZzvCK-xOn?v5CvF^R6B7c0LHQ^
+zb!@W}+X1mOr>&>E@gtr_f|t|Xcr)Ggq9&~P$aHrXl7pm?>24DKW5!BOxJ?DY;=2T1
+zop8IJCt1Ev&?^YyNhVps9g5l7Rto-t#!9$T{RLQRUrYg9`nk6I9LVUPXHR1U#O!Gd
+zE!D9Cl3ims$?IeVsc-N;{B)j-Xw}67uW%YtBcge!X2y1*5~>U57T2TiNkd1J&Uo%6
+zP9H9P&ol`6DI{m0M=Z3`C&fhn(M0>2EIX8Chx+7YS?L=j{X(#PBy2-7I1BjeUCbF*
+z*Udsx1saIO(+ygmHp=Wzl}GFp0`!&oQq6OrRyUeSji835(6IXhF=Bc=5`#b{Mu%Cj
+zz)AEls+a}bC+WxGF}zgs!$>nCiz#w9M0U}GUNMb#nCJi!YV@phSOw4P^)q)n0|-vS
+z#WQ!Be<0A%6e?b_0q8QIJu^_4)n@_2Rfk*6839k}Rfy={BfS?}=Z6IP14!u#qdY9s
+z%d}BuViuBtxm9k4n(p%AL;N{j_wl>5IK<D@CexX8Ei{ok5vYo0CzC}GsWZ8O05f@z
+znM@XHCzI9RnMwLFG28~|^$^5Mg{AiueYYU~MTuXFRLtJSSm|d;>YYeE+A0;5ojz4k
+zDbtH;V1+HW;;r-wNw^OQeN6(UgcOQVI{niaHa;12RB4HcpA#!CAjPE**9pUF2wE@k
+zbW)x<20_X=={I6ytLyzSG|}|5yDhmo4+pbq(!M36=Sz}m9)>jITTS$>!?1l99u}sW
+zm@*3;Xj(;srB={ib^%L&O+?U|8N7`hyM8Y5^nVt26@I6=_}Az0Hr=#0Ck6Iy_H?~D
+zDX{M)nB@%W-WOGtGms~Itg@U@*ZVh>-2vHnar-SoS+nuO+jou1cBTk^Jw@o#3(>rN
+zH)PRbyuF8&wW|k*?GIo-8MZMOGsAWfG{fa=FWL<f=@DfMisxUDVP{PMk?d57+ktV@
+zw)>)btoX&{czBXe5eZi^x<6w*30DvvpeeB3MQ>?oe>NbyUSjsSc-QZwh)>WEyc-D0
+zJ{Q~eOoCMJ{fzV4uQEmUxr{|=ypP|A7|+=t@h#m?kWb<KheYw)NN&fiN8rU1A`nqP
+zoSqp3KE4?>k-(Wj;1g38uv&rRFW}csI6(LW;p7C)3<6&ePD|j-An+yOPy%NLfv*VX
+zByeUB_?mDyfir`^H-rlkKEQ9_B;i6oX9fYhRRB`r=gc6WG&0rCnE@WRFlCOPeNVun
+zo&)s)KW7Gkc=ZyHN<U`?0b6ftsq=GY5C~|b(a)JdAgK4AtnhPY5J*+mB3S3=%plM~
+z?ErG6pEH9%M?G|{_j6_tNK@}4*yQKTAkb4Whb?~23<CYslR&onIWq|K*T_ykX9j@*
+z8rkjV%pfpOBYXUu83YEa&%m?S&zV7Bh}LbNpEH9%uKEaZPg()a3<BHY^vod8%t9t`
+zW)QfYpq0RxLEsJ+*G}NfAh3&dlZ^V~=<CJPJWL2!i&Q)KH~_}7Ds^m&6Dzx462lun
+zpm)C{=F%YgnOS0<cAH{&P_XBlh)w!6+`z-gu4zrkHQ9q1y-I!+1g_-ifZfT@z&kw2
+z7XXe+z7f>%$u7kBQucxd%37(9qRAli{0I?AnanGW%jo3bj(Z?6;TPZu-bUe8!Wobf
+zY-Y5}sQm~)U6@46^AhAFckhIlxX#onxyNgO6JA1Y$vsJkxC@bxyqs??5?SKU0ciFl
+zEAAcUnf%dE7(Jmk$v!rD?k4;RMY$3>5&rZEz@CIHlzWWiwv|X@jRmNMCBU$JEA7>1
+z{CRD9MTa;&(@Gg}IgkX-v{FWz#>1Ib$|%AfaLht-N7BSqL7&d4vz{aUkMNUv9yPY&
+z@q8t94ndVL8YHQ6SsGUYj|5CT|L<BgzN}BZfSesoIsXb!tA-sW_rgr6^R7ZnC-cxU
+z^&&oCN#H}v)CCOyt%Mo)NiCx(?Sx#y3ok=_asnS(rY_n5I4yw>EmO;RLMIwD)Jd)A
+z7|#aHhnA^}&jlQg=R?cXC9?n*Buu27O4i-p1U|G(t*Su$eycMdT6%5j;I)}$=eI%W
+zwfV5Ai+&QBdY)o7eokUi=PJIiu>1ok?tI-+vizxFOT9oNIetEgOr57$!jQv7e3w3;
+zo|-yeQAPiYBq$R(TIfQJ^fW>jX*tD4PPt|&fgH{Sy67j7sY?`#=jW5i)GCoPoyf(a
+zk5=IlO_c-I3{dM<#uDp#SZnYm;Aw1&&eosQYW<9p?R2X{8?w^P)}PcG#kIJxL!IQy
+ztv{)k#@eA??68U!YEU%kK>w?(xkk+&&d};DQ!NmNtv{yyJGp%WeVKLFXUWl|2zSw2
+ze^S@0o8UWs?Tl9`?TvnJ{Yl-Z5#{HmnA9KW-q`kY>rd(?txK|h2c6<-os#C~i^9}v
+zbV|s-lPTAV{-yM(%{rSLe>wHPP9v<xION^6o^jVJ?l;c772fX}`Xpl9hk$qE<5SmA
+z4f64+Yv^AY%SWQFq3m6)j->541$ks9lXr^d?TChBcs1UwJG666VS6;ZQ#5a8fO4ui
+z(6~oOII1<MbE_^ytksbO9r<dh`vb_rJ&0YSyNnFnPhxN@ljqBN^hCgYHPd!MQ%^s#
+zbsGuXB=xW|bI_3Edc98>zb4%h=oZ&Y>&6{0alKfAZcibnxL!uhr66;y)N1~l9NH)=
+zqiU|Cnx<eY4aZ;ziqE1<cMpKwzR|b_sat&3Xy!2^LWQb02QisNNK7bvpL{FGN8J(%
+zBf2FNvL-_F=hq;XId%IyO7I|(5{fiiHxx0UXg$)bj_g6bb_fpJaWx`(c0s|^6Y5#O
+z-3G&C>IoLC+lM-umc^fOVYc~13HU<zLk57fVK2Re`2z{8-ZP=5dRhCIDhFd$M>rfJ
+zG<+HKki;yyC}0Z6VrL5YV$##Y0n^>H{m?|cqJ?Ew6Moge%c#*I#UOhidH<r}K7HrU
+z$I9+aJ);1;!hu;#_Q_tm4lKS6P*e{gR{@jpDCbv{(}(s96|p2}hA<2-)$B%3*slr8
+z+CFTN|HSO1zgE8w?elmypt_WOSjcYO@eGe6h039@)j$Vg!Kabeh}6Mu8f(J5cL0w<
+zHR%0Bd0d^+o*E1R)duL#>g?DPD7zRnfIZA4qHAeFjV=W`=wei@8c1ESXKeMLL6khG
+zgGTqP9>}pl4ekx}Zt`lAYxGaOfqu%G(de`+JpFqI=y^rR4c9^3YQ|F#K7{+Oze4(u
+zZ;&3!2Ji`hVgT0QdjP#EEFlG!nHhM8GKA02t4R3-fSU+B0^nHy;SYtn7p#)Y=ln-j
+z#phzZvMQX5#j1^Gx<lDn)QzPUShkqJQWso8!9$SrG38|e=+_7Gt`WjqBM%EcNb_tx
+zNU77XrhrmfONVYMwVZdWqvhF<p|z|7kVh@8p)6GTIFm6pBj`)r_JYImLx<&81jzCR
+z0Bi7gs8la({4WIcz$avxh3JlbL7?ScDFkjK)>1#~hwUrcU<Dx3s>~xmxf>#EJB2OT
+zVY{ozVY}C1dlrB$L3oc)7iyar+hX14D0xDX_fg4_w@?t3OwVzY^cI_JkfJX&>Uk%(
+zu^`e)E+#-FuP0mnZmEV+WcfLWQMFigvtn5x)8e+ivFav|HEe`Po&_?~8tJOKH4ZU2
+zeO2QvXt*0dHGC8LfI{J`)%rl~=GQ?t<R&Ejl8SJTT~0p$4+FRzz=(YSQu||0bSD5S
+zSsQ<oNQqeSx&4$vZ!H0-F4vC;uv||92yYh-$C514G`qnH;KTS9_-6P5A-G7~4^JAb
+zk+0d%aH2~Uz<W$LH_^p%Wq-_sQWv|3zUUq%83+qjHC2P7w)#M@)YYf2?sMlDu3qGt
+zs|m1+^e}7fFBGvy^416L16R#&p;zk1SB`%n6gL2Ul-^VNm%jr&6KFrZ9rZ8l!QKEm
+zpesecPGOw}qBFUI*}w5QoYS*)=gBpL{s*>Ge>M1?lWPX(4)0BNcn3i~pdQ_W(&(W<
+z;9f>yZ?U8DY+VQL^{}FYZvgkx#1Av?{J|jqC&}ODK!mM}NY-1Q-k~l_k!(7}zY#r7
+zRCliL5*;)I+pe^IH0s&98O+?RsQ%96W+a;~^u5o3o`)V~knXqt@lP1Rv-K!6)BWHP
+zjwIN12>d0M^Zl=M`kt0GgL+ch2ZH}@?Euc7)ITZxa)=wqLE&E<6guQm71rOs&q1PR
+z>lUb@H_(0vgIGUB@&Hc6lt!lyMK8fAM%H*F;yTKzY?+t>k9!-@!}0*U0^ocCe*~}^
+zKzN)`Uu;|~ZtLN1*06Kao#hyI+E)uj7b6x=Wz|{=WzYQxWwGaejR1S@lK`wS?5*w>
+zK9o*hDqa1UeC!PhSlTlw{cWKN(FlFibD+qh<UC5vqeLSueu9w_ZvqT(>QhJB1(bGH
+z2cZD7zWSx2W$V$qpB}xh02OeI;0C{2>%f+Nu5eDJ4pY>_9iZhA#2)}f5hF)@25i|d
+z02UhE3joIY0F3K|pEEf%bR=w{gxRh~koAyNh`)F^fJ*^f4<I~W^0~~|+UwqNk5Lsp
+znL^bU?*sc}<UXQ11V09r5&Z!i1u%vaxpl%1W%Q-yyZTYrpChf$2mp5jm_~q4tQrA?
+zuNRh0(u3#$46ln>!)qX9*uz3_3kbrSN{!%M5o(l=1J-__I?D20>RQWO*|FWi%s31m
+zC%}$vNdcug^gn~3VJ`}^M&67?K8Qh3gCi%J>>);9|3o&X250CRd<n8m4I2Cy^BTiR
+z^4G$N`HsF+g*vYzH0prnk&aE4Lu>%tTsq_%P(K79+_l7zJ|<;d#qmVt!Z2O7?)_%X
+zF?-NwgFuT5|A5~8c>Zxfx;;EEjHqLMscLlt^P<<js<VLpUlXABhDL$t%xq-;mGBj!
+zPf}N^PI$aEgfq|ypcqmHU>$+k0PZ0$8Nf3H3IQA?FbqH+Oy$FUN=?rHBdRx0bv%EC
+z?wFH=Fx63*@63tYdO)}3xw;30ee;A569;`wh6={MTeW@XLAbH6!T-p0gKo>e5l&RU
+zzSMAaDfMStE<J-(Y|GsynN(OqUuuH79aL@G^I5q<2Nr$36w#wt>ro4dMh}DUW)9j9
+zFA&Z;+OS0Bb%qY~!#6>p{ZNeoKtJpYAiPD$%>X;gzgFG`t+9H+V$r^C73AxQ;q$_P
+z@kd|kcp0<c#BeSpb7FV}0P9SyXgW?dRC}n+4%Isi6z?N`H%SwH_~?~@0&vfn0JwVk
+ziU9ZDpK})a7BY@VNBTBkBeDSuD8vTQTmYD4o?J72jD`-MT%$|BP4YX+{Jv0WT_B64
+z_Y?tOD;xsAOw!&GQkhzqqKXmkm9(%2VooT239H4-a>QIlfJWR2z{>x(&~x@x2V%~?
+z)<j*7n@{pxXB$&|0GgW(4R+$5Ttmks?KD+r<zK^L4A<u%deji9JWzPuhkk5Qto+VX
+z3`Cm0wxS8$<Iv>C&?p!k3W=Oej-2rH7@BB$p_7i*kSHoUtzj-CnbvTd_QI!8c;kfz
+z|A5BOW7Y)WTtEZft*&Fev-S5G3xMO+WCCpcwEzsyKq>nc@}#OK9G;sUp2r-XH_4;h
+z)1$%zT79YR>I;W2ZJgvah5+*_1At?|Wjs~r3Ol9KHZ#?5+COaN&y%!7q)pOkv*NZM
+z)qMmS!x1y^>)92$5OJCOWx|vWrb`Ty8cM17(Ngadf-DehjFoET@0X-7lI}H0SSZjZ
+zbZ14M$dMs{`aY#eW~zLVJZz#VH`mnfnY3t|U4z1|5`xiS4rLh6H1f62#ce&P%haYj
+zM7G1W3FicG4tq)vj)B7t#imRvF&a!K*#bc>1d_i}5c=s>lePHZ?z;^SSDc*D&p~0W
+z{40f?L+iZ}RjpxrCBBM6ouP$7Uuz}wo{01RBSz3CQ9=1jOHH=q?a?*1QP@9r6v9f0
+zwQS`#3Nf`AVTiec%iksO%b?91iPr<88B47E7lq&o5Nt675f^eb<*?#Vd)S4KDLIPH
+zafsh|<aeB8bYNBfLi5FRziW{5-9o@l<~1W&&z|WlrZU%BtE^sDev1%Z2Ms=VG%%$a
+zE$wm#l0uo<1QF$^$u!rhj#?=z-)X`$K!G9E2Kb?fpgYdg@iWy}amSOA)(`Wq)xu-?
+zLHgXZ1Wp^`d!w+)(r!t(`&2@&`*#l-Ygoh16;kbbvjx$<P%Q}S^F1R(9IPzj3qOgW
+z>Ci2<&R0a7FjD7EZ^9xEFvKkKuvcPL_-m{RCt}3cw-UcfR6w!CrH0Lu4p*0?N)TO=
+z9|*#dJlaak;ZwD|UWlpX3o%-5m-tzT$J(8b-M#j$3G!5)iz&UX51VJ<0Z^Hz@;$5x
+zd=K4WH{YvG;Ctu}_Y$1A){7}U?v56riTBwU?r?Xs2$k^3H1E=8B=SxTxJsN2W~H-{
+zFYiv*sEK@ByGSz<nph0Qj)T$DmC!^!{=FWQap{C6J%BjgorjkG4gv2j<*L;Aj3li{
+zP2|JeWYETE5Sqwmw0Qs$@(4{%z9U#tR$pFySy@BHA{@kGO}Yk|@$OVq`U=GHPW@Pw
+zJ_a-KPJKX?4uUw|sn4rPw?P@+>6ezi1+lzS-&d335%Nx7IcW-n@lL<1)cJHJRk<e3
+zLKN?eVWq_&<emC=RqAZ8>$Dv(<nm7arz&;6VoAMMm7aj+yi@<CO8L(kyi@O2*34|!
+z37e@b=Pmtj0_H7!+e1D6jrjIor`riTQONH+OCo;#MIh7f*yCe2*Xgq);;&_5duK@`
+zM9-424~=C;cEW8s&@a{#ZU%f1x4jZSJuI*O+$D9$AUK@QeD31wjry=$KJ&SY&wTFU
+zyNi*@KJ&SY?>%CLzNK*p*7^14E`I&Fi(h~4;(rYZ{M;oEVgt<5^9dZ-8|H_}iTZ`U
+z@8f-l3G#)$&wTEp|D(ibj<X0J0FTccXA$HJecu;1ASNxy7y3SPoJEi?^nK<yiy&X<
+z`^<3`LB7!U=?}^Zf*(+hInE*}oiuWsMG{}=`{X!_B)-u1$#E7*!<d~%odETMBuw)y
+zU%WaAq%w(Jpie$`N#YBApKSF@;tPGBeD0ETjAXLaFNrVoeX`Xr34NmF>!`SEczqII
+z==;)CM<AP$_(C5W2J1kuC5f+YeR7;d5?|>1<T#5YzR>r{aTZB@q3@I9ERy&_-zUde
+zB=Lp5Pd;}^;tPFWuF60@Pg==*q3_$4xEcAS`I=eCAYbVFZYO93`9j}!2a9Xt?@0hh
+zK6l|pym*@xsC|fPYae1Pt5U~uYm|<a7y5p4oCUvp@#`;NG}TmxO5UFby3^)~`u%yJ
+z2mjVH$oJ=go+N~1N~ImO<Rs*G4Um*X{cbyP#2z3)zS~YTy9k38a!ZWtBD@wUsif)9
+zxD+phubK>V1TRj6*dLrn>A|PaQWG{2_5^pMnI~LL*be@JG}jOg1oKF9E#c(gS%fze
+z?ik!en(GLs1^KsG3D*<O3@#>o1L08ceA3*=_L>uXjPifT#ui4y)Td%}H1ETM7agKv
+zd><ZMz_&D3a0Y+MXc{}1OL*bm5T6_*dvFmy%1I0IeR!~ZI7%D}@_l%)Vh!M&Am4`v
+z7e5L(+==fzf=hk}xF9%@aw@r=-y7un@L<)S5HIh;<8A7Ib1RUn--pNB?<2yz4-cNF
+zm`xI2T?gl?e*(6W22h-QnUlo#;X(N_Cy8%+gYz^Czs&iJa{7RJYH+@yib;GQ9xM|%
+zTIfQJ^fW@{%N!%8T(j`Y9DeC<-iHU5C>Ae?@27%QB8Tt8gYspLVZB6C@yi@;Akgl|
+z5^GmlYw*Ls)7Tw4@56)D)1j`W{mP*YS?Tjoslf{si;_N#aD_giBE!5V57wwl(JLDJ
+z)QLWPPac#bGK_uXh>WCFv|NLtsRt(UJ$bNE^M|`?%PrF{+VP%TYr)M2T4NrO!HwzZ
+z&yu4_5stTifM0nreI3NQ{|H=OOl#1*m_Eo@^J4lZpu$^j{;*wTavI=T$sX37fWc7S
+z-)d0vt_(0%^R6_!q)nwGW<CY?c8%2ej*IYWyqo47$s7#tNX?sh8*JygQRjAXgyY6&
+zZZ|SFE0ddbJ!Z4+?TF~k&AOg3Bm-Cj@F$?^#?88(G33CTYxBBXOMVhDrX1B#$<;=(
+zc@M8uJ{BRHLR{X%v*8+*r~Cw<6*8~YM+0=H!dCKHow(JLA8f_R2U}qz_TmRyh@f?>
+zOnyS;+M!iiNKXA~d`DEJ9Z}Qn(0OI91c#>wRd8Pe4pZ(PnnM@1hZL4|@6p4Yo2OV9
+zx^JTP(Vv2K<ELPrZ+;H~I7$IjN+ogcM^S6)cgmTyJcVRls`-2j$XNlCO091j2mH9f
+znRb3L@J6TzZkF&J;Mw}s_wV$6w)4j0p+a3FzOs5kr{4v<ub=z|?=%73(`Pa>{%LQ#
+zfzkUgsU5}j=O@KVcjR^FYLzSwX1rAMQB1oA@Lj{mAEN9xLDIl<O4crR%S0q<MKt%;
+zQoiN@*`p$c7T~33zKdcE<~;VXNdO)K@FszK0jSBK7(%wsg>4^NyBg0u0h*-`2sFzz
+z1jy3qY=`CSsg#e4MYwR1!?Fnkn&o{0WNADHMB)2{{4p4z2E;Ig%In8ROC{P7Nb{7?
+z><7&c42^p$Hsyv_Ok+kU0up}Oiuve0CdCTh97FS`Rx}43nw$q?Xrc<FISN?)pQC{<
+zrM(Xess1}><e{4Rrgi||u3bv#A1Kwpm+2Xo(s^r9$EJENWe+eE_B7R_Q~w5ZAbV>=
+zd<n{#%bIOqPM;F1D=)KDV?G35i;M^T8S#13P0^C2glhet{4nWPND3io@KFHc3H%*E
+zC4ii9!to-^L`Q4DFQ4S}<J+R1sA}%%*(F4UthepGQG&rE5Pb(F4FvE<0zCnwVMNZ^
+zE7Wg0B8O6BL%1Kmo{EPHhrL2^6cj~}#*EkMjGK_!S5m)5>iH(s?L)&1FOh@=aL+Zu
+zX7pXH^<4wzPlU$K!V<5Q=mw<f83SxXr`T^&#iO?W#F&ibCgo_9gcm745K5NA>wfuu
+zlVXME2u(-i<w7+W`&l`SF}zWisf)=0#YA%+0-gZJ)_9wvXn!uD)T6B5bs|CkVK-=1
+z^Xv}dNsrQ#Dv&;~nGH{qpEVPSx=VSKbk(zvs^5M-MnAi1w&O_}{RhyY9Cp=jn0gC-
+zhQ1G(2JJKl=s6MeHKHFAeVmeq%mvDUS^bvd@~?=Fqp07}4PPhPfyDb*i1p{gA@v8V
+zPn3ZdAFQs-udKkUx<Axwbmz)paj>j9TMg&%H5rBA74h9vwH`C6!F%af7XWwwz-RzD
+z7YJntcBjpowCm7;#Ai8XZ55(A`s{mmQ&K#7xJx0x8p2Vv4p!o|lLRLcl0d-S@HaE7
+zs{lMf;Bo+eXP!HRdWhty-IczBZzkZ_gz(A4$Bu7UgE-VXOpzjeF`L<3gd}?&fEfS=
+z0LZylq@O9$*F;O?_I-sWGn_r{PShN)OcPitO+8F`?5U?v9((E=2(S-*nu32LEay0;
+zLMwEdH=7Pxq)qX(SU<W0F7WD0^;fS`Jk9nm2s29PWdo4N^Xt)S9LlGaNWM^%s3kxp
+zZUT@qT?DtIgn#Syl{b0J=R6T@MzF9;gy|rwXQ*24<ngGJ$6uX1TwFPX-=CqCwnoAK
+zegWcWpTcrZi(6x@wt69pc$`tQ+R8+A#cjO_d0XLb;wkKn{?v-I333Z0bsjAEZ<EU2
+z2xi2&JK-NmD!UthN^Gv=-6yHkX>_Ypt&?j_JQQ-Rz8uQHiLLPKLeEZTzM+@yY2Qyw
+z>8$WaLc>mHxyWn)?`Ux$^4`{p_e6yEr5KtQgeG5iYAbdd`D{XLPS6U!bMTbb3V#v9
+z)ge`vQ5mkiQLgwVeKZR=Jxx|&HhC#wu9lD@UP#?Why>G_9(Ni{I6sEw0--U3{ib`J
+zvR@QKv$hpY@_i1?ni!h9TG5n5<lGTM^K>g3J3{ke49#b)XbuPsy-K?;1~hS27O*=y
+zH}?9*L{mjE8g?y=slWV(uB0q!MOhFvCY_-`FQ!3x2`U;R#5@oO1_9LT9rmDlMfRmE
+zfUZP@UI4kQk$gm`<}3EWTST!uMDbG12SJ$4iG(5Oi^elb&q?O%F9p@iQF_uL*feYO
+zF80w4>Yzxv-3WrDs*aF^DM*7NbRh&~bAF=p-9~JogPj1@cOvC1)2X@hF$Ja$O&a|l
+zpy5i4G`wh-3m}gsG(NJzsoR33LepqW!UFc^Gf5R9SSP6kS`N#4b|)D$LmV{ES%7h{
+z7R6T~D!h@XE_sMWdy%M~EQdH7>s|&{Jz3VN7Xvl3F^xU~RL{nGG2@Sbg|C*}IRzhx
+ze4#%-3PkHdFb&m@U^<!yf;ng%2<BQjcL)<Jg&me2$rSo%v-fWFc+Bk8Zna0q`a(}$
+zs(Cwd$kG#l-P(i&3t?fdi`9J^zXEu{v%<!%!W!8fCQzT~N<J(JTuSg#&GRx)U!16Z
+zqG+nS!Jegu?oad@<qhII=nUz!T?@0TaRL8K3%qC%b~O!S2A?a6a&JAl>I@I@V|vYw
+zv43?R)b}xc%H-#u?yIK_#}(%d1ImH(k9P3lx*FV15Z8tKLKo&Z@lj0wQsb9Zz<uzn
+zN`0m3LEa4Xj2|-jYt@X>xUoT0&nU9b*QJZjD2BQI+!+HCXB01kNzW*b1IQUBl+KL8
+zOh!#7%~|kp&Vrv7BH;Q`yIh02KnkbAgBAneRQP-XoC@CvAm@m%I8))Z^k~=G=u}wi
+zS;D~;7j)B?8sl0`!PN5^%Hz!E-;{TeP)79B!#TYMGoO>}TrpPf7a|Vi*w^zbit3H{
+z>?M%!rX;R|PjC#Qukl2U;pAL^A(a=rQD3Uq^_9b2LT--hybO1&zfwl{X-oilJq=j{
+z(~L`VDKS%z1=GCljt>|D4ls716@FP5u7x&d8wMOkxC+A}Cn;7qN$f{~t3{xh?dci6
+z*PRh7@T3(^7Y42!wiyPqcGw{aw;-oSO@bQ5Y>e^NhOv{2Q$t+4Kypw>5M3kD4<Pyj
+z6RkH3Tj3ieWiL{E=`k%BFF99X33{ibKZ*1#lP)PoCFM^@IU~Yp6~syHypH&AKSACD
+zQsuCVaWFuHAD47KBltl?2+L#-vBIB9Dhqs{No`f&p;oxJ)F!*!=Y_-!x%+-<Okov-
+zg@#>e_$)!#p?oSiVo)o%Ax2O^b1cWfn3SvxZ6cLtg+Gspp5jD9bFaHVa;8Uf6!c^0
+z;H5`FJ@m1M&?DVh7!?!X<MH;d-RR#^*aJN8IuFFj!ZaK4yj1hcA?e?qcd>uF1kP-_
+z&*xq2!N*qu=Ob1KxB(1TRe`)3A6y%GUjoe<KtU#X-o;GDCj=%r@e-&1I_RQyBdSrW
+zy7zp+wGUi8nsrPq)qBx(0aP+ie_nD?simMD&ZYZQ(HTnUOTFRxVOO+VuHD}OkzTv^
+zTnd0|_wxYcTqG>Ab~ob;R@&?iycliFv>JO=!r*u%6We2|&<Cfw`ThVs^qR98S2S9x
+zgZnk;K^;f%k>DF5bOCr&7xzch;RD2PVb*T}c!<Eu01g4L^j!UI;n_)^H1{}UrPl)~
+zH2}CM$tS?|0Bni_v@qWDlJx*pq1QH`bDXXUA(P9q{zAk@7An*I2xW48_G60T`s@V)
+zT%V1vh0J+E?yS$)Kg_h9lLFYuahZls+cEZf-TfZW3V>!V3l9FC!v6_en^O<;4cJ)#
+z(0pMqoGSfLXoeYP?C*6Ib`!NKp@dfJCIVFJQL1&Ijap`5XNMvR5rjfLL?Ji>pO89i
+zK_{nwx$a<2vyt`&GnfouSRDX<H#7%8&MT7BH>Lo($K@^y<P<RjOiSq}g){^$)hDix
+z9my*xkdp6oB>$e0Qx+I4T1(bmh9!_Sf@{Z+&`hOB+ufl%ByrvNcL*^4JxD0vPx?|`
+zcLk~F-`-0Bu%d?(pnuN=kaLExIM1eZpYLi~i#*w4rb+TT=Goi*Ye*}kG%abBBk4{`
+zx}qIP(okZJL#cNO=^jcw>GJjv9e+=O)bS%na^HGLexx1A=((Vyc9~w78uIFA0!z8v
+z4U|Yvo&<jFGED^NGPhCUWMOeU*$kkkx=eP|WvI8q7I7K3`vph$mze=|AJhPV_FW7h
+zXRhQFYhQUd5M!0_Ez-K#G`@sLX&&a09*^^4BSDD^oc6)dtH7!6KsE-Bc?(SWy8syy
+z(jww`a_m4W+#pH4kaWIDl82DG$X@plr<~zCgme%{R|u(gaQ(#Y6-ni2w#%f-;yLYp
+zOJAl*<J(FpH!1hGqC6_2k5#Z(Xk_&@2m<t5)(=3hN1q|q$k!9$A_eXnkX9$;`jrN7
+z)jXz`j5q~ujyPAt;AX@raC5|YA9%L@*2)Oz)rj<e`?bKIK)@Bi`{?z@C^zw!fcKr+
+z3F!v!woH~#qqVq;fu5lUuru6z@yIW`&KN*N&Tvx`PQXX-^-9V@MB+LOcT?lt$9uvd
+zRwI5V1PrbR@GO9wkwP^RmPS9yzH^%HJEwcyMN%JJ;?w$b;Q^@PMZ&TI1K<$k$n_7-
+z*kH$Qo+gtPooP?<(P!rBPpt}W7ry8Ke-5~{iCe6Zm(s*DbrE+8;ZdzWqMJ9M{`8_{
+zrZ#Z`<_lTnhJmke76U(vtIXM&-@SG3ax*HQ=O(9n>%QfEa1P#ix&og9@o>IPIxN{F
+zJK4;2cLep|JxKcsM1y|}p!;$Fw*n{zkaJX6O0>0PR*cel#Nn(0_aY-r&+A4D!ZqAk
+z5Y2_3abp-VJWEpPoK+@O+_)shjiE@ve4*sjtYC{EQ8V5QX7ke4Z5465ly^6GEfjIP
+zl=ohOW1Vw1lJ&V8<G9U;ckp91ZZ`abchWU#tg{;`*&;M{BfNAK?qrM5xG}Ie@8GLy
+zoO2FH+>2`5`T!mQ;|{*A#(e>)yyO0+#yXp_lJ%ynu{;cf$ATp5V?oB=4N14+PPPb*
+zbvAS*>kVCFUqyz`>8uGAJA1drT?ty=ac<Xm=R~r&UyXYm+4Bw_Qsei4fp^NN@jTOs
+zcf!8$cOZs$!l&bILclxtg&IEtvUn#vJ<i$Z6#SbSzZpf~oqF!L&q2vM_!l*P3n+P~
+z6prP~%$~TDEkfg+{Z%Q$#t#Mo?}U%W{}M^O6P_FQCPeTKzM;k*L)5=;CtHNZc0fiv
+zXw9P!TC?uR1!!G`?p;nl*^y-SRXH`!E#JIe>43Kp|Cj&hNm$PgU+=3*h}~D!-T}ew
+z?x4~;rZWEDIUv{@b3m{!dO)!3m<qsOE#L7C_%#Ov`%Vxx2L$`RAZ!i@_Qf0!?29=d
+z*k=w$(+33mz9GFiAlP@3usI+YJEn-31A?(*iikNN7(1qjm;-{bW9mgXojD*F@4*fM
+zF$V-YJErsj!Oo5;eL%3YV@e+o?ChA*2LwAirt|^9*fI4cq?rSPv15w+$IJo2&W<U4
+zKrnVpT?uu}0m0ZYMZ_Esj2%-%%mKmJF-6225R4sDTY;DZf}I^x`hZ~UnEK4c9aH*%
+zV4oZi?28@{?29=d*cWp^aCFDie|<nO|MkZo{nsC}V=6@-b}|}Tc1^2rqc`!OK`F03
+z?8K`NJMlgPKk#_<VJBXF*ooJL7+<P$*ohr`*hwHWAF}+<<3V0>;*OgkF~Gx45^tk$
+zE5O4}5}O(AGN)et7@$6zRyJz|yYmQOzuv4B?D0Q<1Kg|?>`6lC!NX31%RNAn`13Aq
+z&7NTS^<gK$k9vB*!^2L3ADcXR*h%mcigE=y5&o3>wLF0>lzWWiwv{vp!gB$NFmsZe
+zp9iCdlFHXn<O#q@i#Je<z(T@HNN)%FpesqL)GOyeJmD(B9Rt^p=3>&MSsfa*Af<i}
+zG_jZ|ZtdMx;xlCNC@m}TXYh%nIQ>*GIgzKpC&g>BG_2DpHQs(60y^sRLf-<UwJnqb
+zo|8v-FnQ4jJSUsIYWjfZ<j7t%a&#h%KGfn+$~io8wln{lDP;<!o8y#I&SkV6_&MAq
+zW$Mc?RY`y!bf!#W{G7mE#H38G1ial!+5j$sVz#6efO!ipo6z)MGo{Sn$(vowezcT}
+zlF>WsL#0y|oCDAtDxFfs+Bb(vr!1U-cyp+9%A$(^n?t2j%I^Ve4wX)+_z<u;R61pG
+zKa7Oo&YTyfEExjW94ehsNp~}cN~ctvh4}rJpXakoO-*Oc`V8sR3?BH0gOWg+s{hrd
+zFwg=T0~dF0Dyz0qGug7aO^mwZ<W|t8y^W}NdoCh6=yP3C&QnxRpD>*=S6x7<`Y`B}
+z*b}BxVo#V(nWtH}kFA_?`haC>%6!G5=@X_?%0v$5s3{9IVosP&i9KODrChU6!TTvk
+zpX-vcMA0nzgz1zjk;9i1DX}L^r(B|`xR32KuxkIJrF1pQ3DaDirmuu<&OWx3Y92$Q
+zX=yx78#4Gx2S3a5@C9dTH<~Qt*U(>eKZHcZpRRmn-u+ELnY+*mRCgX=o5?Cr-Pt2`
+z!#CUdjY0Pwd0<yr>`Z&;(_uA8%QL5V`(6C{s9?q-3K~vtR{S(AvoM9Y7Tna)Ny^+u
+zMTTn~FvZo$R;UztxMZi*Sn&4bPAf!^*~++&g7u&Js7(>U<D-Igk`X-K5v-GY@V{Er
+zM7DgZ7x#vFrqGYvJYY7H`?U<7$un9!x*cZD)UhnB75V_G#;^9Up}D^XOK)yelZc-0
+zn#606*z;v%gLrl%S=F$4{94UqWqgf^liI6I@-*@=CfOU+TqhaL_d1&EWTW|G)VxP7
+zE%s|_(Zf&hHyWIceAMFvv$sLCsiwE0)uh4hJw77YTg<!%HB)ct-o}z@eLG68L7{&;
+zO8>T@M@2se89w&a88Lh2cz$r^ldz3@5Z%V=vyB>V(oZuLw{rCSrHNpN(z8>lPGtGB
+z9)ioLYh7%~Sw-Mfn_aYD-%5DJbuO|Z&k=~}#ZMnRLv_XRkC{xx4b>p`A$o?cV63jV
+zp}OKak+#zT@P-PQ`@6a$R}X@$H~s!yMaS={9sgbJV_DiO-_uRQ3jLYte5!{6^$&;X
+z(-@{tW0*b{ro(JI39d|z;r!7#CAgwFCAf6CbxvLvYa0dRsZ^nQy3a4&)ZIOYtlH0h
+z=_Y;8ZuF;Lx>*gzw;tAnR%k7`ervdHjd1<eaE&*K<m!2D6gCp}iG<Bec*aOL5|Qvs
+zjD%-&zD9z;bIJ6_7=4~I(t2^;AE&39Zk~+Nm4%4=M!*_?R3?+V7URCj27%Ry&T9^^
+z@6-bky|_yAtYoa4J914$ucU-bUC}Fbtgh&lrlM(~oZ-+&&82i_N%4UT2rkt;0@mxN
+zJEFOyU9udg?u<13(?oTJ%w>JF0PPR=)1-|n@PhAAioSr=`2bPf{N_=?A(sKw4f8^x
+z*8&}=TjWJr{jGb}4#E<BK9SJn`uUYwK%`0|T-=vYwTFNXo?VUvT*ymb)6i*{=DdZa
+z9H4t$4SoZ1Yw*%G^jAdaZ;sMy@IsCmgYOc0dK|BZK|e^JMX-Yt#(O~o6#JVr`Yd_$
+zx5bMpNR1K11eUt~1USRPP)kQalv^+9?l87b;aR|H{NlyjQ1fCg?}<f*FNow6G((W^
+zRkD@$p(JD=VT?(@D--Z~-Pyk|JdlAWKWnYLlS11Ev=<2ND$=^_QC41tl#HpDNvhU@
+zsrf@Cl?vqDBFHcx4;oUhJ3o>g^6n>ymA5yB@tH`bR^H1JUj!NNNIV{B<n<9loP+pG
+z)FMi%@^pFDJrFGq9x4sxm#n+j-sBmIXGwUFmiI&9q*f({6MqBHzE-~z+PR>uFtjfF
+z5KW$I<$W5X!quX}P_4p-2c`P*;ujl;>i<XtQ2k&`JRP2OxfbygB%a0kx5zZbntGaI
+zS$T_Mc=(r4G(}rIE{VynpP}I^v;4~?z7qMNU*ODt*hV<*I*C753Zj}H0ath@k~*vc
+z@KXTu0Sw;;ApT4K-Z|nC{QeY?1v`Zs^`)<o`;ap7kNC;`nIv6`3|Z&~{Ob3&$e82(
+zK}mlbJqIt<{0Fp!Z~$Z8pO|qM0115dH3+~e0K<C$i2stmca9j2U$q9${EGn85jY#b
+zrvOHs2Y~)P`0gb}GCCN2v8Nizlg~!f<7YW)0dLcV1~s6sa?;#FnqBz$Icf3&LPJ+y
+zg>;q%`sDSJ_;rZ?p@~-o*ljD(Y=OTO@>5%&c7h+qkRA~UXyUEgs-}EhDCu78GpGaI
+zYjma2n{L#_#N$<J-Z+US`4Ayzlb9S6KQTtk>KHMXiI{w?$nK~&;=d`@vX$w^b!!aA
+z?ZVO47k9<v_HZ<}{9j1C_QheG<?NG~n@nlo4F7`%R^b*Ty@Wal`!P|tbRDXOJIY7)
+z=FbrPjD8UWe-mCAmMr|!aW<LXL0Zxk5O_wijr|~uqL`tG(t>XSFosDZDD)Vx5fnTa
+z^P3SAJ`I4*Aiv6Jg(jmfwbQlH$)FKLR<11+n_+I_>xj*JSrprj*oVL%DY=fqcgIkl
+zxjz{W{h*%OEf8t<o9tkW1U?kjbG--koNhaEE&Mw<9?~4|0xzoPVa^86Sda9l(I^F<
+z3Vdus6<%FG?BbIJ*Ve*uob2ByIZXwu9&^=TArbx=;0Dl#?*ecOf$ac(4Zv9AN5bQB
+zwEK-~3;2p@ZY%FvN&Pv>_6tO#%({!>56=+DdqM~v1HsFNK)QzIAl8RR91xPHK$7>O
+zAP0eb5uvy80~ee8jSq2IlPoc47Wz`nC7q%DbR@mWVq6Gd#s&Zl01f~cUI`%nOa9(D
+zVikU;UL}Kbu84Aa1vTSl)PNqG?*~n8p`<&5vu@sz!Fh1CBxi^wE=P|)fm!SEIRWa?
+zbt6ni4GP*ajig4oYef{>w_{7MJ2LFRK>dV*y-+$bB2~VXThWHmj4d&(8PkPXXv_#^
+z;+gdGbe1plG*1{Sm1D+-u)n20r}keEIujcAo0Lp)PWqM;{dEML_5+~Yp>0wJYyzsM
+zgj#mo)tGVVDdAU~621j=-1`9HE-`tnLy?tVHFkk@zCiq~*8uP!@;w4c0ES)*AOk=p
+zfWghehptm!^TAlm3NL157t_GTxNQlIaUT%&(;7Fovrw?>XY-|R<^4=7GzO*Kg&dJ!
+zjLA3a@L{|Yo4|3Bk(iJPHHXzd8*04!;#kPZ)HHX)0R%ihVnQ!3T4n<>7#E}07luW~
+z`I4VWN%KpD<_&0;S0+dqX7gdx5mk-JLpLz}mqK}03MG4#MW<56XhWye+B_el4G%z}
+zgBfoc`wOED%Z!mX_rn;<C{>Q=EL50$@PWp}U9g85qUcgqwUM(Z;&M-+>6Fmr48bq1
+zMgN9}Cb@dqIC3+3w_|9V*a6Pf!-d2-;a7PYzlV4s`X`mImyfRNfa@dYhG~2<@X<v+
+ztnDRV3{Cn{XR1rFfhoKMX*Yo=JP*KQ1f~Ia4}g`IE<9{**MOLn?>icYp;Z#-6_1+)
+zZFdajJ?}E|V|+tfc3}+5(bg=TPs36hlRf_df;DX)vhr5N#PfU<C*Hr*WK9<@Hu2(0
+zb&f0Lbr6~(py57E^3n}M63<CQqr`LGlOGemS>jRsdE9=)i+Sy7mDfe$C|2(Ln7kw(
+zYuIX7w@wm<8W|Y$ZtV)gUymg3^#FDN7z<#;j{*D$z~HNe1BTOA9q5OX-h*~`=WsHp
+z83k>rMv_18_83*mzz0>tEW5=ltScBHf0t0Qox#P|2+CRplhf`wxy5FpXtTG5@qx%5
+zp`K+lM4@(MqAY(v(yJ_#ew%Ou3iTRdwgVXafp9=4eT@hGaMGJXkpYEjOEr@Gc~*_#
+zq5X%0FIp)3=O)D|RGd(nLgoE7rcm{Uv30>lMGKbuo)9~ors)a}wKkhIjE{DbC7WoS
+z)^tOuPax@e6gKQe<4xFt;wJ%E3}A3S;c)7-81%zQZ;DR_6u&LiNb={65nd`b41Cez
+z7qlt<SfP|U?Jj7$b($Y7x;1fIGV<@Pr(9Eo=^mK}spbVerO)cFpG!5PJZI^LBi;40
+zsjq<NRSFla^Rm$qUZyA7PK&qlu81M}qBW7zlURAT3K82*_wKs1j--d2)|U5R4AHpO
+zM6X4No)IECY-MYrBfE^>Sb1;95M9@r=y-(aL=4e`t%)Lkww{+%Yh*IJS6dV5KW1QR
+zULPT1>Ar4Fr2jqj|Do<p;G?RpKk)bFPKK9-Asf3u2!ybhjj&~75m1vrK-m&phLD9s
+zvXM-}9yCEktChGf7!a#<!M&{(wc14sF4fwK)~#BhTD8?uwc6JD|9<Z>^Cn<xYyZE`
+z|39D1<Syr)d+xdCo^$Sb_q`{9X1Xwq9u>iYtov0bR_-zvCO!fRQepU16as2=0j-S$
+z3WR{J)<Bf6s}zv7gIip75FSGA4_uIsML=HL2l9{$@(&S^b@!+daLE$qr!L5(6eZni
+z>Fw+TIjBXoB%MVOkPr2NoaTaD69M^hAIRk{$eswu&-y?HU62n)KpyEc_RC$6M<O5}
+z=>vJM3vvKf8CSL%`#?QAhD*P2LFPq3&X0u5`M?Dk#<wOC$~xtp0a)>M%1c>i$q&Qk
+z{NM#U>1K)7$(Z%Z9yl5U*y0?UG1tqHFP2As*V?@5gs8;kIfzcKl_B%w%K<H&;RflJ
+z+{wK3l^dm-6L%$?9{GIQCV92Jj(Pe-&61qKS7|S1jixJ6k!9Ii?dhq|uJmFq0Fd-z
+z_Ax;(=4B+T0tTe-)$QU<y9@1|Z085%e<!#=V&v6Gd<N)wNaQ@On|z$@T1X<s@{s>q
+zfG2ZEtHPG2kq#V#K^;OD_T~1)C|d(GvtJG8A3%QWo8f#3L-c)-pzXZ#NJBe+>hUw9
+zFUa&uQR=xy_FBL##Ss{9ehSn-%YMLq8nno5MF4PeTd|!9ZY#da1h*B>Ad%?}szxw{
+z^78{UJnpulFQD314A#w!h3pd+0UwWQ;>@;U8@kEO*31<-2!NtTN+ljKHbWQlSte6v
+z>&!4_=IhKjWOC2Y8TzHEV`XdQmtL$ZCIhNiRd{iO8Ui`+OhYe4&8^lGM<dv-z~pX*
+z2Vyz9dQU??f64_Kb|yQ%UuTMuxn4KKcybH$7`gBHb!5L#Xh7-f*|XU<=2UKewyDjJ
+zmnHC|b<1VI_<_a<;mTd2%ju_j)06~)oZJmA_!D$F;m_CQbUF${@EErozm<DX*K^mj
+zTGboQND4`pm7D9D%?lKib``I^SIftg85)KTMQ*9iaEtZqanSY|IQLn4;M-kYMU7Ju
+zp!D3Sx+}0vlgRCy33T7;YF8A|Zuk9)#N)R+;A+<%(XQoR_V<RX-F3R167utOe^&1A
+zH4G=~J_RFX=cq1caA(TrI<ty`l-#ap<+Ax}1T`srsIhWS(6Gcl09u$<ouV+wRh}L$
+zpE6yS*8$!dH`Wh*^n!Hb>@Gm5OQ$cWONjE)>91XvPG1aPIz1#Wou<o3+e@;&bxH;l
+zkNuI%%+|ep;#DKT6|yYt6MiIp!VjTcX8j!62@M!Lx%FBT*ZauBYq(L@Auk^?{*h-p
+za6E!M_q|6Y`jyusCr|(W#nXe@r;(p6pLYJStlxSA@|VT~`zIcnpM%KHfxY-t;!59z
+z93q5&mASK!Q>N)N508|<G<6o=M816Pc@E@@o;SA^|A?mSZxUYgyu5WbuQ}L%m-$=K
+zUhTpEA+O55#=P8ve<Ab9HzKsN1EPIfhvLQKNZT{TFULdCGQ?O302yMufC+{e??6IX
+zrUSZ7f@+F`3}WI0K+!TiOK@7IKQlqgG^iIE^*6eSu}m@|=W))3;0wOg&nlRRHYw{B
+z#t{bbJkdqOi&2*cG}-f!*v3RY5_^fbNH=MKh*HYbWemo7aBO)F@N$r=H4tW7e(Vyl
+zpLjXYCy0)*)c2U+K>fP`B<Z<Mw_^;1AA7Ngn+Pb<lLIJ8&w3_E&-F;;+^3st*7T?=
+za-C>Amj^GN(bXRzZJ#Ah0k(N>BR%gW{ABZ4@Q(sZ5v!+vh@TVpu;01#WCm|w5=@Fl
+z)3e32Noa5~%B%L!k3`}0(~-Llx#?#k@hB7LAn_&>?MR55Ff2yo&(xUoGO+A7Jr8nN
+zze8OafE3h`zEH1tUN=y!gvuSIAs9ga1XYUvR&JIqXSkhbkaYPJJVru(c<o?{LC+}r
+zls~y@v|u_L74TvXca%7X!{vNkg|6j%?Pr4X^@b#w@^i9oGekAD>@@KR+i|{ZY=h){
+zox%j?>l`F<&elyL=Zls{E{`p``dm`cCO$G$TuLOAn){g`6^D>e(ss3OlWC|3it#4`
+ziqwB@+Ks$fw>t?5D|d%hO&3FKW&@Zk+k*0&bU8PqHM*R_4c{QVA^oWaqKV(?YW$`y
+zzZ&JcLgi-3<;LqZN!&kG)!v>1Tb1V#-pNkZV8s4v2#b}wSeFy~-$Laf?C0ugZV^Xk
+z$PtCHhqu6&X)wA!vn5!B+XLkwKfGACR$-Bb6+n-MZKreujPf9z-5M0@E_b;L#a*hL
+zmjaH1!7O)Tc*2F@ry2vVw7;#(m7c*po4K7@c6pslV9qghUfj4rHcGlK*Y$LlPEhqy
+z<>kKUYFOB(Ap|hjNHfV<s_LQM5KGkZMTC5X20By-f1xYL@+%EOGofLYzoWru$bY23
+z^mgr|dlk1aiBkH+CY2|`BVUPdN~{KxK0~6;NS|Sn&akTq(7qs5clCIvD|x+g%2W+0
+zJ%G}Iek`~1#cW*&<0U`#t^>wkpD!4h-i*bQ4g-9lJd!i#9FzJv%E!v{D?0>3&{KA5
+zOpKLI>2+mtA8=*%D-t>ODNnn~tpPml_cChbVZ%i0#8MELIEvIni<HADlDY-zehnTG
+zU!d;SU~-|kwZZdX*^i@epFF<4e|pPa8-Tk4@l86*USw|RNS3#Blnp^KzXMY3GIJA#
+z=WV;p-0G3=XM2&ksUq28YO%SgV$mOg{%w4dEvCxMy&awx?6Pt3@U8Goc*`z33;+2|
+zIBYMx5C8ccn7Z%=43pnM>lT{l&<@(X@GjVAeg{u3<5O$+9a3$V@!k!7J;GCV8~DL*
+z!k6|Uo`vE)5K;0Th=u0HjiHa1H2{L&A?rP5(ddz1&pf-#!~ggu{L?O*i<bOG$J-0d
+ztsBD@l`RKV{3cy&FXUV1`HlW#nR)1K(zW)YZNSiuFP<Ze-$mvIm}GeaOxb79zWgS<
+zZ7)m(B7T!Dvu3~+d97y>ar)Q36$UZxbF}4a<=@ov{}9;A&#S{g<2SiOBdYssppkcI
+zME$!vG<?T<#;v?V!~cJChekiw9U4yf4h=^=(^lT0;kfS5a9nq2IIcT19M>Hh&fn=W
+zkB{RsZ5`Jg8jd_Rr|!^jTz6<V?mILb_Z=FJ`wk7qeTRnQzC**&&$N|yXgK<rw(<@Q
+zM?ce6-l5^>XWGg;H1LAnVo=#7@6d4EcWB_Hui-m19Q{mNd54DMzC*)t-=X2S@6d4E
+zcW5~7J2V{qOj~(}h7)mzhNJJ$aKd+JIIcT19M>Hh&fXQEJRaBY{^L6|s-Y^P<%4YH
+zsp?TeE4u#rgn!KRc_@-6{A2Ri3!eLdCNZHC{%nyz7=7?QQJuDrJ^MAb<I`VbSG|R#
+zI&B|Y=|x(dwvS!?4$|theQecHq}6Hr*y?<&Ms?agwx$bdb=p3*_EDs>lX%)bcFj+b
+zR;TS_>v)(}owkpy{}sxgw32z+-sg}8pTjPb-vS9fhmTwtC{NADuCUpSJT)I%VSk9U
+zIyE2bJ~bcfJ~bbErfkAf^PdsVI5b%t8?Z^DJT)I%sqygCeC%qOQK#l(-KXYbt7Q|O
+znxBoP1Ldjt*flnXCr{1C)@wXGH6QCfH6OcHLh;o64nWH}<A~j-<_{x3XftRtr{-fD
+z_+SMI`=x<Ru?F*0Y3x}xhccK?e~qoNNzUM!1f&~m;vd2T>Ovn-pM!ZH$^+^s;1<~$
+z7Ke<tVLOt7cVrBgN6Q;zQXX7wkdM<&AV30J4C50}J?aUlx1hlZJS*!dVgn?bkn92I
+za6S~&Q^d9-tYI`M9(BC-rBIVE!cFAy+TlE2>-pk!{DL!y=qiE0BYB@AV#L|NVU+qf
+zfbe7QV(BPGZR_l5NZQL%<Wu(QWQf;ZI$A#Q<{a7hpEsk0&ms5l#9jc$kjW!?ucCdf
+zgpd;eAgU04>|HdQsYHLSL_g&_IN<yOc#S-H(TKe2qDvz9A@XAjIc@l?fKf`5TiP_Z
+zlJt{D^5#Xn-)1Oyvr0pS`(ml=>pIz&=N9zUAJd2i?5hCzalD_zzCj|m5c#o}_U&u5
+z>C5NDl6eD(;C}mCz<uvAJ+f5xc)#rNdG^Q$7o!1tjJ_448%+e?lL(d}KlZi0Jz|V%
+zbUtS=dQ9KQ1|y}Gfgi@trSPozv3Iq?IFBbgM>5q5eCm9&yo2L?WG5E0bqeRb^t(9B
+zGLG5N8vu+5%BD$YF`KHgA8nfCrDTlJwVNl&XCaN%wVNm1L*O)ByJgaHX2<E;Ehkpt
+zLP7d=P_-ZZOq|6^nZ4mQWWUSoc#h#$%t|4eKvAo^9a;I*q=}ramzYf<@FeoG{~aV5
+z&bEEx4n^|Tj7c1L22o9vcc^4C`4#{tX0csX0kZS&L{yw>X^-X@8q1HJHyXUldKy)q
+z119TnBu?0e#P^Xn35l`y>K0X6*tT#waLK?<!yaH8kYtYmD35aTb1$&jC3Y2&PC<Dc
+zQ6%fiR)xabaqlJ{kl5Kk!6yvmP-kRlpk##z_lMixBbGB!cPS}44T<}SZjOfB>K1=*
+z$8AKa9u+y6Buyo8_`FGy*7A)`lA?Es;#6JtRTSm&b{M|xDI*tiVmI~x&qR6BTqgV9
+zh5VFSjRcOk{1k`a*M;F_vXSt)vr+#lzT@zSnL$$C-$MD+Cp4N%FdW{i!4-|7sdslP
+zwAY~gGF6U~p;O<}#e53hBN}{59M~BxUcFzn02}ZI!c9JFtdH`C&nU<a@Z#-alJlz8
+zl5G0Txe~(K30(Hu+zUxI4Za&}`astiHuda@oVZL*T-13AL1^MWXdn{KTOp9hd8;J0
+zp&Br9-g>SL&zr<&zy>O`c%|Ya2H!OX-y_7A*%u#G6VAAX@nyGyh=(-T;~b#RW*8{z
+zT9ilMgT$psOl6`AiIqr<{j&yt0Q?OrS7$b5H7AWhLnQHRmvIj$`qFH?wC!9l+sd^-
+z=VqYC($BH%o#g#ipqyIXr9giIl&errw4M0HG5r&*u~+F@JxAEVvxYK0ne6?AuFeK>
+z`%b=IL$dY*63rzs?q2lp2Mt8lKBaq*c--t5J6lUbp9yd=Y)Xojt^tZ-YXlUaS_AE2
+znU={e^lMF--Upt~m{sr_!|*csI|*Ob2Yzb^erp(BCNu9N{+d4UcZJ~33&YFgCc;mh
+zt+mxJ!H8c2mO|fwr6AWw=wjK_-)Jz-$WaA`J-wWfG1k<ct!ngKVp)DQU$Qn@{OW#H
+z#U<7uR|B4mDH&KU)tWW!eckwVG@d$ItEzXAS*kHP+1Avb>T>pQO=J&GAFqdpI0DrJ
+z<c-2HZIo6UvY%d^VLy+Uer8xxAJyg5A#bX3d$Q!k%imK2!AYBQ!=p{Zyi+>$XrFV@
+zLWKhH$JHxEi&|%peQ*IMoHP<i&F4BpYDzRlXE7AAURoSA@6U4e^wRNq0$;7Ex9diH
+zTIX)nNUk?ISy|RppBDWdsJO>W{SG<f42Dg8Sl5%7mkcpr&Es0KsCGZp<y5;j=tV-7
+z`CukNB-QTCx|rZ2RWY^nw0Y+%?pg3zr<LkVEHYE;bcTqk4I;_=Q$wl)dYY<Z+NBzH
+zFdD*lq}wPRaT<B)GtN@^Yfb)3Yb2k-VLu`5$WGmSoTkOz^?LwHuk{JzwQ`dHa5@L@
+zTBXzVbJ_TQE}W5kTm@dLPM_m(jqTJBwo4MU8~3ur_AXkCnM6b{%XhkrzTY^lFH5)X
+zYUGt8`HDmsi}6l>Sz|>%@-stP*5AsL5i_J|Rq3&BYrqunf)b+ip^O6OSs(-ttBk)u
+z;n<;Z*}LX|$<on0YSZysiXN5Q{IPVK_b|VhjaB{+$SVpzkrc*ZHH`ik4e_K)vS1nW
+zl1HCP9&KR$LAF=<A0t04M^ljnLZ_YP&a87~tb9iO`rXD*Up}LL{cdNnU>C6Q8<*fI
+zGyyS>42Tt(fS`D=&^%V9zkIApkqK<|`(uHL^~L_#p2_*S3g3Q@+e{Xkr?2#vPhTlC
+z(Zl{SdRSlrX#L{tA`?LKFDfvRK=FcIunt)G#m>CQ1os9^E-=BgxNGfMCZJfzFd_qr
+z{bfM0z{DfP+qQKRIODZu55itv#m=4wPR7pmXa*euulad;BsON>BzEQv$IiU}Dt2}f
+zoB;2mbcwwS9r!L^8AeOU;{MQi!Us^>8N+`b=N=5x@;VRkpX1!j!gyyZb1Ba6nVap%
+zz3jQs^3_n$*Q3l6{V@Q%(dN}qLx48sV!*~STJ*9n96R&5VrM>A?9Atio%vj`GoLGV
+z=5xi)e6HA;&lNlKxngHNckImPj-C13u`{1LcII=(&V26Jna>?N^SNVZK6mWQ=Z>BE
+z+_5vCJ9g%C$IkGmsV*=}J>A6Tj-C13u`{1LcIL~JPmEPhH}Sb+XLwz<>**#w9Xs=d
+zV`n~B?9Atio%z05?5v-Roq6X$`kc`{7*F`=CWHScPdABnJ>A3!Ki$M}J>A6lS5G&I
+z8OiXM`{5$7)nB4SK3pWWRvJI~aFN(Gd`5|SxJaz);UclFhl|9XLm2aLkyzWF1A8VP
+zE)wg0xJazmmbm1@MPl6#7l{o&T%-k<lAEF3FR<gXcLPrxy@$A5Cat(fn4ZS;oVWwj
+zS9wf##g((Xfa#wOoXYe}roHw+o0<8{%(s<Ey$5M&VrT1EX8-BGMv;tV>Nji2SZ4Um
+zT5K_hFn!--)qsUAW10R{>!=jsmf*+lie>s&uSdCxW%{eQ<xsIqe>GLUie>t15}`Fz
+zEYn}R5b5l}>P=QlkXErwzw5~%{`xAEKWPn7u}spSVww60AXHE42_Sfr6}yqKOuWfz
+z8=9$Drg@W9f5s2Yo2>fF_c5I*n=qESgLuZF3EyNz5@jqCZ?aN&7|ZmpmKhbx^t)r3
+z{%YBTvCQX*N5(SoCMyn4#xn6HD}{${ig}ZjB4MqBVk~nApru>H5z9H#PXGxbAMpeb
+zf5Y!FKN9vb1Dm2A&ES!bVi0$tcsL);pz_uUy!2zA&sAXml69{#bv}*22tIV-LKcFC
+zAE0<7uN;ZZ+fg8*VZmfXQ*4$=Ml{7{KTDU&<Ssy2g9tl_$WHJ>0@aOL_IyIgr#?un
+zK1v=9lJ{ASXb<9~&p%GVAgmN#lCvkUe`7ZPPMrAIyGDW%b^2)nu^)zCl1g$X5nS}_
+z*fu7E{biDD(X(^gSb6j*i(cT|@55_*g0<Pqik|J;(y}ikTHNP^;sc;=9Co5@aKp-U
+z`CBOeOqO#8%i0e7@&fHR+_Sv}zw)_(X%}kv4*(wz630nD&Pu;Qmw$$GE9Fl7+RNp@
+zbon5RfggKUGU7F(<x#HX9M~lwcC>u?$#OFEeP&<5g148G_EkU7!!C~;_8F1GK9jJI
+z0agwBtkAFvcc20v4x8tkFfe(+JT0IrY&bH1)Z>ujj_UbG=at@ZG6Y5jVAGe@tAROa
+zUL3`sC6@Fb=n6UN@w}>P_p<NDb@^`DIY-?R8g(y6?L3J1<tlP%58*Fic0IE<F?$Hv
+z^yG_F<2X=gO{7$>(k11p0$9(3*_re(s-`@I;KY+iynsXoS4Nixrl9d-U;Y!2Fljfc
+zoF5`Dfv(m-@K@x={?<DN=o|uN?$H2n^yFu*>F`oiXZ5YkCIva)(`~rr0jKO-Fg;qd
+zV0QQ+XCZjtYQ2V|K%4=*T9ne-bvYLipLSwI>?&P8h71`$53TIy$jird`9@;J2X~iZ
+zD>8ZmX4QU<%l=-_I+knamlUGZ{ScFPC}A(K($iBtnf!W7V_C)R(hGm$ILWJWKwD{l
+z(Un}3d@n3X>Z!)K>?s(JJ=sc|bg}H);-K>tgdX^w$bqNlX-FkAkCKqLr=am{T}}bu
+z$KDl(ec)&r`F)#(-v%jT+d43gBdqxd+00eC5m+TZ52EW4@);NJ6X#g@d<&V(dl>n&
+zGc<fA$b4Io8Gi7BoTt#^Aac50uo!Uou@RAQP@VKACUR@CM>o;I35?-H#9$_kLDgC4
+ze^MqAk06nohlJ>Pe#?}Xz~kq1D=Z)Rv7_woVt|vrK;7_1kT{CO$xOV1L<15zztv6h
+zF%C`!6%<zXkMYm__~cCMTMFecjoN3(xs2#Y&izPa^##i&eK|?Gaik!>tmhLL)1KC3
+z6oU-DuYshj$J!mGTgo|}`Vr?iRc@$Lbj6=FJ@&4TVP2>4x<;za<clC@y0jc)ZCYM1
+zX=~<o-6~nPVqi<{vd2q*I8W}fRl4L+jHhpdybr0G#@jInhjalTuR-N0Ru3VcbA|3<
+zspcn@KNjud59%Hv)SRjJG}z8qpgYl?0|MnNSwGUVG>!?*QZW)ao=a47GfV3^J-osI
+z)@^h3SPML4UEf~Q?$$t*Ej~(9@t0FgBx(C~HI?Iyp=vAbkS^!M{aBUj#Ynv?KWRr@
+z{r~<e`cF^L1CaCRbLfpo*MoeNZpxRC{&-~M1EQw#Mb7p~YNB<^i5M$C_AXwJlM{WC
+zoahEHNKN#-&_w5*LlZDxB6th+nY|i|nfUk7m74f6*Tk#z%*QbCeH*BWFOw6$8USkI
+z%Ve<VeB^WP(mj}or@fDyc(p_|SZIl!X3s=gPX4pNBbVr3nBe3OdK{R4tD78e^0(?b
+z8q{ULgL$>5SZUX}h}ooyr32z7DD62H(C)7S`cMN=G9J`GSeR+frE)f;n&!PO>{!{S
+zRUyfk?SlDI!%UW3nPFhkOEipH;IBhGabwX6;9jgN#)ann3XE}DLp@%+bB^3D<$*cV
+zTEqEkk<XJ)jA)P;`u`Y$aRUXR(dNMhPtUxx^EB2~5a^2`N1(<ANqlTW+TFTtE$VKQ
+zb&RY5g4d1Hp3}7*sC_1)mfp^3KyIbIreV$l%;6A>l^*qN#jHzFo*t(&*CLaat}|R<
+zR92FWR$8VmCL(&LT&`_sJJpS-(1j>{p}S_et0t{MXV}I0rVBX>2Sc;ap<(1Kj42||
+zM(zU5F@8ljLgQm5vUC)^^cX*^xBR?Wz{uSI8M!N9<ZghB+!daMdE__#O}pq@Xvc5t
+z1BE7j7XN}h(*(zgPDLHRvHL=ywuD86CU%EMG8dV{b&08k=2%~Bsy)jbP8%W*rxm>g
+zhVvVDS|K0W#;^ZryT}~JOIladjb8Xox~OO*{_&f%t?)5OHowW$;XvNN$%Q76H|Sd1
+z3SdL#wZ1<T9-j)*C4!d>(w(dMHcSiYhE#~z|3#4Qt0Hqg=Uz-qKUz~q2hS#BTB1LN
+zLe;^uXilCEo<$#ES_RLd`7(7KJc~XRBi6yQXueEc2hXB;@Jt8KqE`?`1<#`2BOVnz
+zi{Z=EP4Fy+FH<+cvzQq8&?a~mGnL(WZ9X=2RSd6WB6#*aWa?t>XGRClVrqy@2hZ?O
+zUu1OfEap>!>EKz+c4E`PvzQZDlZ>amV7_CP62TDrDg4_JlSTwOcowsi<mlj8%o)t+
+z;91OSW_0i@hA&e$!Lt~?OdY|q9`x`~4BtO%f@d*&nL2`J&!g;Th?77<obk?ckg*~C
+ztPT`LJ1FX>Zq|$bC(2dY8@*7LcLAdlJtUNlw_^E1cHh;Gd?CAU7a0}J7qa_qWYUV}
+z3)y|WWSJA4&GJwHZYvu)*Z^8_lmrgF|7IjuN>XI$o2C>mWN$#X(TgZ4P7Sa+G1KFL
+zF!~Do=)-E!7A7)$SnYj)`U#^0JOloU0f`afWE8~*fK7~`5|8HzBr)O+BonN}aVYnc
+zuv~NlE=e9*D$z+CS}Gw|WfM=y4kF5y4K78}@^9x45&4`vbe=pFb@p(x0AbGM$KLf@
+zKo1PcN<we>F|6oidYSUL#bEVBgTYYzIfJ42PX#V28#`mChKd0P_<^SZ_<@^<OCBEi
+zK5z|`Tj~s=PW}l-HRLG_+|DAT=-JaTv=Y0DY_b-Sg^pol$FR#JHtX?N0OsBTDH*;V
+z#jDWzga#yrSK{Y7<c9Nb*<(nISf!iHQuIRggIsuOUJ?wd@$yQh`7X7kgZU<x9k5U%
+z`9e6;66d<*$DaNrJIq7X@7P5q68@i}iw(MqGTlW7yO11-7LVMj8lxjx9c$F}8n^<$
+zN_a*hl|qrij%BnuvrR!9t<G#SnaWea{KkHN%sb!_FMIa0m`a_EQhvpdvBnBm_ro*u
+zT2~B*@F^AhE2wgL9Ypti86=6H=f-?P73&LM2l2VDgLt=d0e|ak^x+)@YJ8V68Rd9O
+zpfG*=nDIGx;@4yQIB)&<=C$~KBVR(1^KCTfm(qo#<=oBmXu1N96@9KV`~#-qQRs|d
+z63gf${QLvoSaNWH<^3ZoB_i*KNJgizvY%dw(;<$IYb837E0G)bIKp@rfX>*)>(NwR
+zxQRQ?g&UvK0LcCvh4&~Xsekqs<oiiW;s5jJC~;^h{OU4`1B90UueadWaSky38Po9&
+zErtJcriVDR6#l<4o#N0^`2WuIc!!q4{|~0K9a;+i7fjD^-ovl|pG?p8(^B{?o0(Jn
+zv=n|@W)}NtDf}LpDfiP-`0<!+{9EOxrSSXg>B!Xi?`K9^3O_A{Ut0=4ErnlO3O_A{
+zUt0=4ErnlO3O_A{KiMuqS+}2-!au}bh|CT@Ed{W&0AQz|mcl>5z80Bl{j?PRi88at
+zPfOvSBr~`9X({|C%FMlfS_*%ry%2aF^3ziI^<@@6ErmbFUV?spW(}a0_g~#lYI*-I
+z4$`5P_ut5*<xtD}dpTUkp_ccDw7i9!&*22da6(D86eyN*DrISvDTS7=28Rd8%Pg|0
+z(^TQ{?S~+C@q;sf#_NE?@k0uj9Lv(7O!nJ@^;#HzLL5kU=COF>m1u4`PoX@16w_Yk
+zdX}d!?Klq8qnVC#f=s8fyLjg+rpFLXf^!Yqj=c!wQ=FwNPh)z96+_Sy03wGo%8JJ;
+z4`(EtzmI*N(;qD_qz%E9M=ZdE9ZY+j+n`+&E@Iko?jy{_OvgF7gpqF)jdx}-eF@8x
+zogIX^l<6VPGc5l$(<eB!Okc)yinEe1mviBdclHzi6}4b?wy}8$>VS6Q*?HhA&eP*=
+zmQ^#6w45dQNvtI69VdtB)$>puFJEJyShWc0Ax<tvlURKX(pWc`t;Cw&B0b*uE7P^Z
+zV3D#Dc~K*AO$yR8oKuLWt_e6Fa{dm+CD!vS<dasCx~M@Kd=9%zdJB*~rvwGb@_=^Y
+z3Y*>d83jqKuos{iM3(6E0c}4+V~P5Jwx1U@63>)Pcu`{+@r(oX;>3VW68$d_pi<+J
+zNLS0uXoXZ?)KGY;WfNZ1xRH3|MUBKYHizfuDc8h$jfWRC67>OX)pV_d;zf-kXeuR^
+zBbG9;P37kxKae`q9MDc|cmQmbuxA?B6l;+C>EJj^Vh!fWV>}(4(`gNvhm4rODHnT@
+z9J-f2%LLX9&4UJ1Rl}?y;~@gx)RRyyeoZ(&X49L>c0(_bNvemTPsFg4tKJ&IQ`%AL
+zly*NLRZlc7(n&ngxQJjw=_5rI#o>3D6?Y5T#j)=pJYShqMx27L)E>$+;VM6rj~h>t
+zj~gG#D=0~2sym*Mh>~hnw1>L;BHW!k;XU*Va5L%)-i!s-u0v081U`XpfU(E#(bjew
+zYWcBuRe=Q~<RRbjBrE5q@HF@e(($a=iQFjMJ2sJA_z;;CvYih;;s;xP`LU<R0CsdE
+zsuuqY_WuoCKOF2C!)TRv41AC5F>r435o#q010s+4<`<jhH?sL(`Zn+9Zl3ytuBNw%
+z3T)nqIG3ZPPD%R&<@P-CIc2A!k6R{w@Qz?Gb|hnn^O$-Oy^Rb8HzLcSuX+L-@!D!U
+z51ykPOF>H47_y-??BY*J=2a+u43MKQM&bw(sd*YGM-O)k$r3RhK&P+Jb##Y@qf5yS
+zRUdy5=$5<w)f%W2K)E3xYka#dUxD)RTXbeMGU-?8OcOHeRSP>8y+(`jhvZPn6U2J0
+z@wd2f>~rII!i9q`8Ubk<$A(B8sn2Lg(x(PMW^-|-y@4XTk<5Nx1GQkG^JDMY3VkG*
+z-AHB+e-d(bfdnVB?_l<4FbZ}fxjpLV6f`{CvzfV0=9=5_4o8{&IkWJ)TiDN+$V_;Z
+z4cF~PS2(i1Wx~BgtFs?%nfL?Nwh~eI0mR$?ir!VW|3PGbNMKpJ1KCMcxM%rJfQp`b
+zwoJT@bwRfLE9xfvl-YJ3(?>U3C!9sR9Xi{YLS?e*a=_vfum0ga0&0=b2T*m{Q%F3D
+z!~;y+kHjG)Qd@KjZac_KDJ{5oMj?hRky!uH7wa9J2J7br>xic{*4ap;#$BNZ_*Yot
+zuT(H0TA%r~!CFORr1e6B^$uc9(Jj6L>-c1D=<vA+V;Mirl}T66*~gJA)cCM?IMOx<
+z?ko*NcVkSboa=kCmA=4LIXj|qo|RtVsyr*AGS^CP)0KAuZI`N~zTuTy@D&F(xA?5|
+z%^K(j0J>gdz!FKnQkVY(<v$FSa}7hbtn}e}GM+{C>+WiMGH~;S&{le$hItt<Uq--S
+zRWkUPex?iJ1o$1HsYf_B{adceyuOuJ=*qW&n@@h%D=>YpF8>hat*Sh#=aMZ~QrR-1
+znf|^D;M%?bM&QzyUZLiY!+Rv6Z#6u!phm-xy>BWQ4xSI8+2Yd!d|tzloc>t(ATvZx
+zwD5*i3TOI{8kqdz@!~Ky48LNv=n-N;1O)gs%~jbPSqW+=Xya#V5V}&<2@K5IFPpL^
+zHDai!kI;C8Cz+L8^v^=*Ck1hD!YlV9=jmCTex*j^1q`3)4nn11DQgB1JDsU=UdtMP
+zx4X-<!^HXlHP*eld~vATn+Isk_yIMe?-^JddK|ydfIJ{?|EUW=qyL8DWvCzhArj{?
+zaTtkPkVyShLk~bl<R3+SsXdd^kwdzW!WsR3n(?6T3Ef~M8l;-OCaTsDQ7etN7u$a$
+zN!C@0)~O+q6Hq5l)Bc0?2S7l2ya57=k3cMl5HSZlq$0;k&DFIuQREusC0Zne$T^X>
+zLfZrE*%}T6$dA42c660NBR#-oUt^y|U&R_~9{O62dNp7x{WM*^80CD7j47|s<!7S&
+zf^hlxHM+bG<(Vz642kEnZmq0yP=#xZoH+w92Nr-Idlw%po>2>1lnT25`vTfB<e8OJ
+zn^jYO0k@uBy**YUz}5WsQe@Mdg+!Ysw~NuDPM1z@3AS4HI0^e1+UC*|yi$_||3QB2
+zOuID!GhdIo%;%6e8;R4HSc1eBBvN<jCftc}1wgIge*QQt9S}8j0lUtXU4IwQQ-8zN
+zFhzFy5%Sa6=^>5bc{H+T+wYkU$33q*EM|foHY1UGG@?TpyE6SwpK-OKJ5~L&a!A7q
+z>~p%jZgV*hj4#qa^leg0bcVCS8N^W%EA^MUi|$Y%B#7t!t@J?}{xVcm0Xs!5-%7n!
+z7x$_b45HCdq4S)TgKd|+#O5CJaShh2>9cpe3LH6~p%vuxew1?MzoDV-K=HG(4_>im
+zPubS^tZP(Tsa;~|&%6&1xpj%PCj5zGO||eFEmpmrB0>AJj~R@l^}mgq{TYm;^}n6T
+zJagFD^I)F2>puCid~RF*8Uxp3I8%8)0v-GgoKRq{Xbh^h^UTrY!QrFH$=BMUqtS_f
+zw)5$cd>a$z9m-U}1E7cB{wqaZ7ZCD0<i)&a@Q>diujcK=KYoXNTCfd+;CGN;<Yl0U
+z-=Qbv{S*KA9eQ%!yQt-N*yRQ0`2)!p+XdCA<#*6JyU+vy^ERV^-{^Dld7)aK7L(_*
+z3(Qjw2CetxnTH`HJf8m&2!0md;qnO%1yq9kCO&BwSddVD6JNIr_$Um16Q8p~hp+K4
+zh<tOXTs>u>z+AQRylLl~1L4EffpBx>3eSMZn+^*3jXA~Yhe`5UACJUFUqvm)4OCIf
+zY%KuQa&mE#YC5FG_VJ~59#7OdI;P&J`lcXa2~j%$<K>N_p6sPaMqWRXK^sqQBP+c9
+zsB}C|zdh>T_tCo!M#_kvcsZylZjk??y74cn8Wfd#=llw3UkcLRlbE!80g^uVZ6xD;
+zyj{{e?=MIXvHGpXKNib3(F&DkmCV~#zha~X<W%PIj<75uoxc~Q(Yv6I?E!tqZtr>y
+z;4x<b&K|(z_p!iZs^KTt171Wn`IpEpVr~3Iz|w|n>@sE(*$rQk9(RUj=bI?lhHrl;
+z0hrXddR_iL%5Dyo_lF+X0vNuc*@_Elm`_pvV-3@R+NH$czf#xQV23rp;RFnDUIkb@
+zlL^hBgI{k+!c6?**ISwpkAM7n7bY6nwYs1=yw;IXAyJqB02#p6J@7CSKfdvD*8a69
+zh_4a_@ztUbg&35KOiN+#9!D5_QW&D<ya+P-Q5d35V$$kIVThW01j+b*6o#mIpCCQN
+zawrTej%Jias64A=-nJYHLln3r^I909=6?sJF?{QmN4<56F_T!vFFccFk|#htlgn7j
+z_=Sg0yvIy+;itb;$NsoeP#MDzh^LIj;`|T_nU7@%#8bx5q(V_9Q4HW**#&zv%O|3m
+zAA8rmXdYjMS2EcJOu~@&cS!euZZ_Eayl(I!w2o>p2OLQti|oBjz5t<2xJG7AK{oaU
+zC=(n+_|9rTS1_|$XLkJ>8SEKl&5T3HAYdRf550s)4Y#o0IUN`%*2%Z*R^4rZ?0_I5
+z!}w7<kbIT-)yPTa4zLDL`s|W>b)x~O;RhiasFOi*a3vhv{8vD$TwW!l^*hK8l0HZY
+zd9?af#J@U;X#umvuOWM5C_DdkOnW?#)a^kfKJi?p&0he|&}k^X3H3uKA@MUNQjqBX
+z2B2h<FZQqj;`(fIHe=PY$;AMWO@74$o1E}lKn+XZLtxAL0ZPgMJREC!3x4Hs+7o8p
+z6s}b@m@KY2d;R0O%3O4}cbx|QC2WGQ*z1|R0r(X^){`H9Lv{ou+}^kXwJ_d;_Y%=2
+zj=$+mxY~$dZKf!VS_1HE_o|-9segE{+}}Brji|a6z(bpmc$$eSBtAsK8n!?;;bf(t
+z3liMHq2R$r@1+0&pJ8XZfabb^pofOTDW72_zoJ33JWvD46}AT8QV9B4BW@?@*`J^)
+zj65Zzh3o`7&7Tx2{KNeTc4EKy!5HsYD>il}iXe143D40x$P)hi*n(J|xQiM95NIa;
+zW4>RKE&Q>uthSML`iEd=04!Q(ql%N5jWL+8ENr_ti7nzrTg6FPsO&!-38+~#aa3<?
+zGC<;wGWg?@fWHu@D-uHeMiEP*!~(;Z6oQxK$u0s=J5Un<dNA*q_N<|1WMskYA=jKV
+zl-LGe)MZ-<HluJu!a(UmBY=iRg$VV4cf*j?Tw->(D?0>oJWdX7gd1CNQUtz{Q^E+)
+zVw5Wjd@0Ckwh;a37!Ay~{icFk%w~?{=a`E@yJtwxNx(7IRA5J@(P89lKhBi}V0yT-
+zSwqR*@tGDAO@28haBf1l0P^%dk{z#2Au@C8jK`QxKwr@^L3vSJiw(`Sl(D!-8SC$w
+zVzlvxWo&?vv3Mh62};HiLqZ}ECPj)|vXQZYp?;+-4Kgw|I5dk<=|hW?QY4Zgdcvh>
+z4GlrWDu^jkt|%jV5+fu8@)6k}LNG>zTXE`eJ>4y6ZaKkBQchfAI2u`(*rbktln{A&
+zY=xv6k9NqB0^t@FmjsPtgVXJ0gH3~UBT`%^<HPG@LM&t=u^&q(hDksS#67TxVVxKT
+zQ!<wk7BPxM6SPofWDz!B5e1Ny>~H}#Ueh4?|2y$i(uZeMxiy?oX%Jkg(juiVHY|N{
+zM*8|2>GLb;qe^q6%9LUSvni)Y>&OIP;EYK*N_2CNlBVPc*T2oI!Y2;P0~8#G?^0}(
+zz6h=l4ntFzhD6H8Q1|Q(bIHMQQ_)9MBXIW>)Ub4nQq8YAX()ASUm5KyW2r_c$MhAE
+zvEkV!i=fsb3Z%@8i!A!@#UXOuaf;pWob%pK&$|`_N14TFV-}6(ij<DHuyph{(&0DK
+zfwzNG&cgaI-l)L@nSl43Xf&j}bu3wllhRTl3pvPWufZYurI-yd+H0sRC%h~l<{}Xc
+z9j-}~;@3wj8S&#hha7^DnIN0%HLMCpQ3zAqGCDd8q_kyfSnd#W(X}pZI#zcf$#B^&
+zSgu%DJld<!A{ie>-bdIcglV9#PYlz|?4+=CF-v{qQk5C5T8t;NuaIULA<YgijU3mC
+zncP>^=CT1|X$G9Ca%y;qOv}`&Ipl>*$9v19Zl1xGG>my+MkzMtYc~LO1(B*EVqq4#
+zhK8{exk!^TFw-?SSuiWC&1dVjm<e)ePArT89%e+^aMxRm{5Ow<9M617GP*c9%sr*t
+zPl;TWRPLvSi?F!}XVl6ri73E|EB)UpceDN+v;LwZy^$ER)?&>vj8pcYe`sAv3rc@g
+zF9zwax|S1&jt{T+1nv?N)taT3s!V{yksMl*GCL4Bv?LPczhBYrH9IVXOU~qQ7d?=Y
+zueGAXs|IeUT+8kirX&w5T076KRSU%}c_CM=YgI=GqibnXpwe`2TE6I*>Xpq}<CyAN
+zIvmo|g+uCEYZF7nNG%l6-K6kn<SN%BLeDar;aUok_nBr{XSvpdtO>1i3VM!fMFGv^
+zu(%Uzt}6@vO>qGuJ2kv$r@6Y9(>2}It1Ori)(}|zZk9)kGC$0DdO%@ifZ2%vq$;4e
+zlA!=B3TF|rGRt_DCRhW_R+?*$h6U@?nm#FViE>TPjVOY^%?lSmJ%lr~82`O#?z;(%
+zT)O`k8;QQgTA60pXte?5hFH#@JP$Qct@=Tc>slG;kl`L;4EIoDsfQiA?6|GessW2R
+zEXxR6=sCmeV2?l}>Dn2<97hU|Uc_Ok!7efc5wT~%4#6x)Y$)C0l7>Az`WhEDN@g$g
+zADCyYI=O0So?Qm`IOf>^LvU%HUBH=PgC!R(W!`LAvdxmt32TqZF71(Pia8pZXT9~G
+zdW=P$CNZJ+uxVEP!Za&`m~RYVLEn{KXckwIvY<2FY>QZ;ILaMbqF@URuvxLlauvE1
+zBn)vV3&Q61)gSZJ+MORcxe@)HOkU(9$%w%zAvmelBj9j+H`EmfDR$9?o=e;VhP8Gh
+zia@hKw+pF}g?+U`SwsPp$fAe>>E$mD7ybWPjVQ(NP2&-6`yUQixePO7Ra%A+sR~U^
+z#6ovPtdwdA>6sCjUJHKyS6ZJ@F3A8aU4J97$T9|DvXC1(2`&MqesR@)RUE=4=D?92
+zBIa0wKVIY47M^<m;@4SMaDqC=tz<yzSMLGz4uFzu^h$UK(09@0xYq);irfsi!zj5%
+z8%zl+E^Y=wVZ3Q!Jv80um>FS4%Dq5%J|Y$vbdVXbveO0OwL-Im)7cRPay=DA7Qq>a
+zD2SqQpA|0p|MQyr+NL|?Nr$|0ElAjqS%cKl9UN)XzqS$An2zI-Q(hvCd8DwLUAS3v
+z(%^^9yK6yQt)khZBUgZH>rD^P6=PwR7T#r7)7&yS&Sf+i2h?^F`)@6YuD*37eL`3k
+zrHMbrq{2N{n_MhCl{nTV4=<4{vlOzGxpiA~*CLej1t%N`F{CMdS0fC2c<J;B8NkH5
+zwG#||NIL;l<O+1vL6zjY2#~H{L3r$H9Y!uY$k4x9bP>yq`im>@e-(KDe=D*XVk{)V
+z$Z337{BYR@OtijMRMU+rLcI+P<D*CoQWB~|i-TPv%GjpS{OEQlvPQCz9p;)YDKD^p
+zN&w+jGqy3ph(2teOM)aU<C$9eQ;fH6%v{K?Ne!z@&L87k?u#mNLR|sP|K03Lz4eus
+z<dSgFh4fI*#F!{ZtcileDYe#LNr(w<U?V7l8{ue1JUVejFx2I^&|W4nQY$8zt&IwF
+zgf>S54e!DcYnRhvLe=QJ&vm$PB-}VQQV9;Da7FHrzEX-@F-%GkFRB>fK$cr4S2m^Z
+z{6nQGSqWWw!|b|5Z){)TN^=v^N9CB1haAIKUSEk6=Hs|AhF&n?#87X2xBnTD>Mb*3
+z@npH1^&t`pH>4NQ1LGfDTRK9(_y_xE7VOJ)@k^>gcsVLSIMvk-fHMA}{UQmdeI3fC
+z(Y2xVloz>tpm8G$s38B9tMlJ4u*e0)D*?t4z^d+N)=)T-7~&(;V1(|9iPT-Onj07*
+z4ON`cI2?X|mpJ*u>IU!ARTtjl)e23B<N=jyNXh*71J?1C$Z_|*<YC4gZFEPBd)(nQ
+zit}oQUl^m-FJ>5iMnwm>8%8jU#=|Ap31L)}vqUX+<R7w0t}NJ@9Ol|U#jHUtY=9r^
+zVn4D&`Yu{17q!ZVxhH10Yhq3?70P9ESsPx>*MvizxYmQzyD1Tq)PS=f9*a+Fv+ch_
+z<=Xgg?(mn@-qxB`-&EDmUR{&5VaBw;v?&=4^-b*?GS)P;XRWRewpnfvm1(G7owcT_
+z>R9-x2316(W8vC1w&Bui2-sTPUf)pNTC*;*3S?QqjV(28nK)F9WPM`|QlP&rSY2IH
+zi!=_vp#S>jP%(}!s<Z~i0hQX;nwr+i>iYJ!jH-tE8VLY*2sm8rfJL>#fdJ3Fx$GIo
+zQZnq)3egbEIc4_5HKnDc-3#)II>hi^XXj$EDd<TXQgLG`{?3}eXpJ-W>Pg*?i0E2T
+z-zzqhTw5bftQB!i;f12P9RF+263qv$z)4Bl=j``wzvR5q8e}}aUZ0qHboXasf#*c~
+zV8tVzi34wTMmuZ7+7dCaP^@(lSCrO>c;~>HAO1x&9}+{#iNe_+Vx2_M?xcv=^0S<?
+z#M+}8nNzR2*ysC^!uFUmS~TnwrA|<+_e`+g60ciM&>1MczwK~O#oKEt3M!_G9M3rW
+zt{?6eOL|3nuk-u-m38807Vr;n3Ktv{@rO%h0*ODk0KYN4$Rvr_E~mDv#VM<}QN$FA
+z_2nYET&#C8MRcLqSniDLUg;e9czO29EYCPdSGkn8)&Jj>HzgGH)k@x^SWJd2fMBFU
+za?uuSt#4YBt14VV=@vzoNd31`Sw+-J5(~Kyf*JKqGbxLze@$3TYiko_UeZXqR13=P
+z^SD!yA2Hf?5}y+rgU(d1N4#M>LF`2D=sbG$(%Fy^;d5#!Gy8pa-{jogu1X43$wudF
+zuMoe$8;opme`l{u7b5+=&hizdrNyOyvMJRAonEJ>`}OTvqRx|MJ6YXgP*9YWd(xA{
+z%zgWv+=5cCHv`f-$m<mookM7}yig`<ne1Y+1gY}FPL8uOi+zht&fy-S_Z{|~CF1ri
+zL|Qz?p921{XHmhQ+t2FpL_xM*1_M0S=x-uhn5h3mef@{Jtfr~sSg|^u^k9(~k%3P8
+z+R6*CAt9A%EeuFUiVsC2MG6u`W3WB&6lk#W#ZNn@b*#_N5ly`!F;ldsI7ttSq@yWC
+zJw>BL>|tl{{HvVbgWsNAPO4|Z5NC8jg>wd`>6~87+aM=#JJNNW!wgTVEgGFd=Vqtd
+zNki!w<tR;a_A^O<^ur4lPQP1ha1x<DTK7HRWQpNU;XNz&<j<Ts(@D)2ZM9<P&QV!P
+znRvXITi&MWv3QvDo7$=4n;dD$zR~PA)dcJDbsI0YdCaP8ZK=fk)HGGM)wFihv>Hip
+zDU#J2gEejID_hiBuB~bcHs~eZ-c*m7Rpl+s4W_uQxoT}qP{XiXt$deAndDcPNf<<`
+zDQN|nmiSaROjlM{x2jxy6aK?ahOO@L3@IkbXgy$ylsTocfCV)!jTIW1A_Y^RKtiN|
+za`F|WIQ6Vb16nO&rAtYk!~c-vaZqwFhLGJt5!(xC8&Bm@?j$lv1$IW)iYyU*Ap6I+
+zet1(+K@o)6_GQBGikM7s#(t4jF3zBC8-3U_ExCBb<r$@DILI@_7N<BnQ9hvy`4z-D
+zp@b>Q@&xKh@jQQ8`LlpO=Zavtm<nR<+g2-{vr0sNrx)e6uiW<(abCNPE27&zEdJKn
+zB`&geiglh0yFe;a5F~t}dm9Nk*Df!G#{IIh-0PWw{6DNh5y)Iwu$#z4d}bDKT`nO%
+zw2l@%ytIJ&5JU2bQ+q!aCFL_uMeB_uGp?41+BBYF2gJ&t7<fQ@VRgOsNPfrmEAF}o
+zsE%|}FJEULeMH3U2la!%%5zG@;9iZl*7qBU9}h+p(d6%W+lc#1>wrviOc&Y*M2vIP
+zNy-4DYgeHBCm`MyKeC<LiVBc$Rc9u$AJ~~IDwZ#JUc|ylC<y>;Unfn{v-bW@WFG7+
+z0qC*=DEZv3ZU3tnaHw>_r1lP2iBGnY|2KJ$BK_OV#C4Om&>JNVZFcq{^F8mO(xQSH
+z&S`M7IPFhtX73Msga0<Y%j48~W+aPl{1+E=9(C@^SW#M0QBk~xV|LzgPW%$)uEy&V
+zPfHRW@;HY?OxG<=>c&b>)<E%$6%;pb^W@m*>BFrKmEsj1CxzD3zTDeSytb9}ec$68
+zK<4SKUC8YBl*4<HEG_pzSDv|gWrz5cy<a@J^+30C5m@lqR?f%{Pv)JaXG;#$dBzT2
+zf*!5~hivhl?MO5Ij@JV$9`PsHuS{O<DGV1L_2OJE>fMEqFIje_XP>xdn<tNSe=6td
+zVjKRaxXE_P#gkTvXU4!&uBe*T_&MsI*aGTp@oNFxV&4{^McOmX79$Udk2{^i&ggDu
+z6RIBE%E^4jLyiBvt(4?vJhgS*0a%&yW|poL(N5yy7m1)#DC*#g#vj1g;Z({AyI!(s
+zzkL`@pX}sZ|Ips)Nlk*&QvOm6#HSZxxj&~0)sISQpMWz%FXL(t>%YIP7rz_%bIZ2g
+z6_Zzc#w2%$!gA>#9Fa!kx^Lnj=>5=tx7jf!BEl{lv$N{61Bw7vMx?T%rLz9t8xX0A
+zwQ)dNsaB{{V-vuKusR1oXcJ|0IADz%qU=X#KPAlpG`4OJ!|;{nAncGv+JmrCcX_!~
+z=X=VuI)6;qzbUE^i94O-in~sRu-d*Z-!DoRh`PhYrQ0joPZlwUOGW<@(Xuo9)GNe0
+zTb#r?k?fghi-AW)3-r2JMKR3j5^D~NA(^5sQw%K>6+16SO>jSI5<IzhEZL|+(RLI?
+zXR>Gl7VzAx7yh#1OtJD13fu7tA6uN@*<sr+t*8(!<@_DYUsSH7ZYjb}>fIS*XPh%}
+z(O>WLdYolm`)|u<<=<UX^fb480J~+I^mpHoYI3hsnQvI-rL*#}og9FB>wsjjQ|@HL
+z4VvKWbS9rXS*$<YEtUnHQt@MJKUPT$6mbXsm9On~rgl5Y`7_r(wJ>j?NXDSb#gLMU
+zf+CSzd!(SK5#7BZHR&z((e?%TGers1q7ct@(tbT;Q>`B8<br(2&iovv@c^FIbb(#o
+ze#co^;@jIiSvK;?<)^OndO?>E2Rl9Kwp0{CJZOU#rWp250{j|x?NN^i@wRnzL$~uT
+zo)`i%oF!7r?-G}8gDTx_cijb~t26n#p1+{+N@)cS+s?j~1*Kwm`AewlU+%0FH*EtW
+zfbD0URFHqSYl{GVvCLfPae~Z!w$({N-9ND<@rW)t*e~raF{(@S?@cNw+KpF?($eA=
+z8=6fpy@`V!zgYC&e<pV6V4-MnQr3y2^7f7!+B?MReMMqp3TnnZEN<P}<qX`OKQsGT
+z@egS3fy?e|U$%oYAY%84_RO7PdY33J7Z>A+c6V(n7sXv-Fy`eiR=Mcfwr~3mGN@eq
+zxHD7y)b7d>k9T@9?SuDY`yS&Q!1gH9sRO+~+2T-W4vM1%=jSgFtDLU$MeG3)EEI9&
+zV#Yq_LXpj3eRs1|w14p8HOwokyGu*gT$q3N`_7>C;-mxZD=N;cYHwe&7kly&5qDHP
+zOsn%3QQPI*kI}-!i|bS`&kLvAGcQR@ICKye@}8}ffkU2sGm*J%E6I4(Q~uC`XS+qh
+z0c_YRL|w33%m9KY@!l31t9>4fuVkl43<`gFyQu7{5F>Vq)<fdg)=tsjbcwb5og(p9
+zh6mz$Ujq~WCRx9e9u-EwS$flZNMvz8km4C{i#7NGc~5TIul58-qG*?I*i<fEubm>T
+zP@F*`k3^Njyx+P>GU0<L%Ai+VxruW7MpT!WyMN}-7op@go19v-f6ektg^-FDyoat8
+z>q?$N(F2=lH(&DZL;Cj3Z1=La9AfqGCNAeMq6(4jmiS(YqN4a@6WQ^dD5tj=xz}ax
+z?x;d6I=V2gvmZ3`I{RNjwoCdHcSjNV3lhogQHPxhaql)K<)xYm?3GH3LEUSc=pxO8
+zdO+K|qYib8xWm{KO%a<47q4x8>`TwgBtX5sk(|EO2NmHJuSj35*H?bfGcNhGA`uI(
+z5OdrgMlwi_+$V?if|n5<`%K><{1XQ#==-p9KjKvEF01g2#}3JctL(v(>Hf`b>ECQ$
+z!y&%^aATD9Um3d0NOF{^t7>kltzTpIO4^3OaJjZh(lnV}l(tjNG<%^6oiTP#!5m}l
+zfYn$#BxwWXwutHQR)}rQCJAX{2QlF4)#wty|JEcnw*>2(n;6C9hDHXGRLkSqN8AJ#
+z>JVnu?3~bdXy+8}6e(j&HQ6;mvspq5TGyRb+PeP6;%+IrM654_KUTQ%s&)~#)0wqx
+z)>Fl^ozXL$9$43VC|k~2XN_}@h&_7ngY8cH+DYxA?tpVpH0~1_<)R$s7E*q(%{BIE
+zr;~DzbC)>7DTFO*5R;t}Sc1U5ZUik;#3HD`-M2C_^n}$b-tFAyyyx7xDob2qA8^V8
+z`QQ3{<yFqbkFLwFJ0GTSO_P(n+ga(fBbqp~J4;mIfgHkr^iyYdceiK`Li;2-J$s34
+zT(7uZIE80pS#7!;%er?n7u4^(nPOnCXmt{wJ>?9PUal1CpS>lEVP1p1RJZ*P&z?B@
+z`jSs8u(I}UrmJw+TeuFuA7lM{#UySne&=-(ix;+6WE8E;SWvnm$N6Eq_;S<EK{Lv7
+zG3=*QAnlRP!^JsS*j+j88^oQqXRQ63W%aN9LL@l*=<15v!{VOK@}6#(x_9l&tT(}w
+z_5<{HMQaLfDHM%|MbaVBm?Dx2#V$CwZ^NA3)mb7Q<qU1y2i3B%7eCof$^!_go(5|V
+z^1hI}kZ-|IIYn<5RjlCON*MguAa2HlUU1U*+s&W5LaFZtRu(K^BpIATAvdJkGgLzU
+zibPD**$14YZgD$0AG2)M%4;S%Ma~qaDj*V>Vne1=F?FI-@tLW_Kr+Go;HEz~7djiA
+zO^}zhVx&`x{~P6ZQ<k`6TbEO@7h@QJf#5%rBRHmL{+!YaGqQ<4)A@t4qP_V4(N?I-
+z#8vEZnzNwdii2|8kIHdBg>j4i;53ZY-#Z;n)w%Z3tCr0=9~-p$y`EY2L1#^V-MJ`#
+zc{9S)7rnoGckv^*OvXWbG83Id-^(k-U?7kZHRpi%xpj0q%<mfLYtaH9M(o&Hju=;|
+z7+8z_yt5CJc1}5ME$mo21L!bn@%&kiA24haHX+^OS5~lly|~762qF(xqc$i8l#6wR
+zFxA0#*|&4I?|{!?kN~lN8FcmCArh&>ZRaUgt&FT1bO2L*$0lyiZ1GkU1{x)v+00GY
+zJ&?@H0qngA5W6=?7xPFI!5`byh5Cb0&i;qCBYVXrY^-eY=O}o0$UY!ze--5fSAtdd
+zc;I;!6`#N0<F^6x%Pn2I3+i9S68PmN^41pjMU_-AO0WRqDbd;@W}j&CWZU9sC&I`=
+zyeO^Zolzw~cb_<XD*E{4div5&Mmdb@?w2O=$tdpF-`FI*g4@u0g*a%HUn4fwqWHay
+zG`~0aNd1wGT!}aM5O%@d4Gb@TxW<!_g!#dxlcR%v;LLl9EUI%#l?3lZ&f{DD3;q-B
+zhlPJ<ce@9#i?I24Qjc{S6yY}w8UA;>y??i{v#RT>f+5RRFHIJ;wri*Me{`84WQ1TN
+zB8`x-Ca5r$2PD#tytzr+k#{}zz|xgJ5}Qi4WQo{A^`&qGOIE(`6lB3E)Va?cgoBWi
+zQ{|-idfs96kuAO0+h8e*rl3eX438ekQ#~_jP_TL+1^0Izy=vXUiw>@wCH`b#FHwLm
+z9)9YaBZlC&9(#=}TSR*n;0+pLxeU2X#R?Ikl#QnrDn+?RMiCe)S+}sXSp0tLekkU{
+zp6T%&kSEWAVSxX>EgQc`MIxZVDS<C`a%<-Kl&VZr2gL~pJk+8N%X+z!*)67*W2Z$u
+z(Vqbj5@9GQlE}&=uF0gNj8{5#Y?I5d+lGRXgp58cYK~$E<L%atEGKU^ca)FFu+9^9
+zkZ$NBGQROM^cbr7xqY}EVLIoiNa^)V7zmA+RkYwpadv)tyIc)o{Z4G(&|9%*5|{5R
+zr?-CHtoQDsMevBnw#mifoWq>?b?U&(La_t<5qVBwH&)zHjARTpao37x5fSuaHwsiU
+zp^Qh1vP18RvkyCubVDihici2W@dq0}+qdB-AK#}f`~<+Ho=#`~3eVVN@d5x}BHP}z
+zx(4!sj^~H>KpGA$Ed3Z6Ufo%X7$A0L2>9dL=v62bNBASJ@GQUJ-{rfzyFLA|#&4JF
+z{k?Cp-v2{CH_~DKubkfFM0e_20`0;22BjHXey-FF#?M8@xU;fc2XC-WjSmZMgnU@0
+zjn_)>us@4jUmq60cxhczrM$cz4*CD97>~Mku6jiOaA%P=x&z5@tS3YU(1jdWK)AF^
+zNE;EKq}sT!AU0Ax$#BsHS`kfv`uH0pcb4r`w3QaLzv=7{F(qfh2jo7<7QqrR3`;q-
+z*Qxy*mfai;=2SWlM8LI`;A+$%k#=~{CDP#Gf;M85hqo;}Uo@8N!Ij9v_%APV*NPEG
+z#TqBGlozU22UBKs<WIi2bQD(FjWQ^I7?J-Cy{nMlwT+wM!&YXebEYWjh1ZF~-*z&9
+zdW+2s=&N$A-)v_txEaKHi+o3YKXY>6aP42{+}j~G?Q}YzwSu3)%XOweNBvU<bgs3J
+zX2F{~gz&;ng!u2tb8<v{2`(n!*(VsX!z&!ZDX4Q!a*~{^>(K56T*Ad}6z)3HR8IHU
+zSnj>pV-_Ox)WeWc6T-i{3rewp3Zr-h@OO1m54>m}E$F_>xlTl9_GF87aKq^74A{4K
+z;su?bRup8d^^6-@abwQ|9bzL~h!xKIWh>i7N9GD=LVJd@8`?>RV)+OYkHuSs{%hm>
+zjTY;1jkDFz9Nub%4f4h|maENO`1}bLm)b%`uDM771yE(Hz8=rj$jkH)YrRM0B`<><
+zX-czsQ-m09CyV%_p5{bnGQ?we7dT%dqaDNP{MB@^&|x_5bWY+h#K2R*%IksLW4-?G
+z*cz$0j^Rak<NuY%e;A~ey6bDqg8Mj6ShIm0N>zZ^(4|iBGNcudmMlAV_wI^X*RN@l
+z*9Hk((@+D4%FST1TF)4jiJ38VsZmY_ItLXd$^OiyKUmY+Sl`TTI&kYAN$OXfA2OO*
+zlC6W@fUj?^3i7fn`VWl^#YW!|x_(VlB|%Ue?v!2e0<bENlq#wAF4JmnynX09PBO&d
+z9h;J{yHm!T-;$ZVo%<_B@tUBAQ9GD<$V&^In|S&;E!?vwV<QUV>l|pGDQfq5(vn1f
+z{<e$c66h2Jp4V@?>-YH!Dh?ie%DLQ`b+Dqqb4F7A%7bkczi{@-aIh_|+J<ZUQsam}
+zT1U@#Wck_H0YVS81bH>~!j%UdZn6K|$xXpO0YJs#+v)p*7*LYG;5XPCr8vprfo=Ol
+z!%;E)C^p^%5NqKmNfor<(NIsn>%^8q^|Z%6dWI7?W8oQMQ|2c*%Z}8PW}o<SJM`E-
+zXn*XIUXT|v@5ZwdndVUMwK1aD-Z6+xOxcR<+<*fqGb_5gdn$0gA+G$Y=Cc49po&ZH
+zx_tXx?FH@IQE(cWI->-sQ+dU0S{G6!WMN+U6%0fqJ6(5+W+!F$_B#>6#??%xe6v`+
+zf5ly5B7%1dmwj@R^B3p#o21ga3RC8>+VT4@mEPB0SXOIQMq~BV@E*d*Zb;H0UIeI9
+zvJ&kv54{udwv&_hNySTdc~U^k<$&{8d;c9_#~z(HMpJx!+FgX3r30A{tw1gevtF@w
+zB1T~zoF)qFBm~0S+r?YfAtwdGBAjRV>p3w2mlIYy=hW}z8MHM8Jr1r6)MT}16lG)`
+z$tcP?HS48<qJk_3I|Tfq&ZKANJ6X&X6|7lNarcQjlYz{hd|cE<^Q?l>;tJ<s*<@w@
+zN~asgVE8S<H%tFFW&Gc_3~=Zq2{pU%O?KLyp1%|TuT$zAWDj>1mFjF!M(K@3h&&Y(
+zAp+AQJJ^l?xcYNqHpss*8|3Ucaps8?kK||P^QX1q<@}lXAgAZXqP8scqXw9P!6TT#
+zVeWQ-GNT9xYO-F+o`jxr^0H5y)m>EdtJ0z(@jNycuM{o8={;w9*6h7!&Nven^1GbU
+zx>GAobuM0sSQeB?fR4)q&rX|LwG~_;6LBf6s3;%V<y=8Io|9R%hzsSX7Tgihze}_g
+zmVD-X&O>N7<;}`lc*R{k+yDrkDH5LX34oW2Ef<?A&k2yqK%lv{HW0J|#ft*1HI>x?
+zK4vyhRac3}(*@e<np=Z>MlE;IfsV?C_8Kc#SKk(>Yi<h$R@XOG2kKjReg!8;Yjdzt
+z0+p4OE(l%OT2ob1-%%6b1=Tid$^5c;fq8S5&aoO4#)jsmH7W83c7aIhDx0bsYTziC
+z^7ba`@0#iq0t9O7@d&$S*_*sZ8(4!AK_U8a_J>uBX$J`2SlKeUzB<q*AwXt;0D-FZ
+zR)93LH#S)+`W?^_W2+sFa;AYJ)y?gzK}Ddsp_)8`2{gDGa8Ag|s%vhn$!ZH$R;|ri
+zR5oXER>$1M^RtezTv@Pu(z0!8ZmO}=q1Zq*7)@&@$Iu?E3$(O0Z`dd)Y^-cuThpqR
+zsI0C6=T&uEM^&H&6C%$y1*$89m9oY9*7_iLi)mXvXTh@hfyHx*Pe=P!#ayt0$D#1U
+z^H7*lPA3Y%vp{_{Cgb$w^G|ml07hLUNRp`ADlu!TE8A);%&W$r+E#_g2Yr%GH5DAc
+z6==YY!fIQKO;%NNyPUFy$~A41tw3XQbq&YH2lgwO0&UG4Ze=Ti=$a**5e%}b6)eZM
+zwZ5j!f|LcCD%&&z>NnNU=a4uM=dWztsHC$^^2Ws$IoS|xQlzE)<l+VMBN|E)*s`^w
+zzN$v<gRBl&$o-jXaG=2g0T3lMOKoZll|k^HKlQ8IgEhKoOHCDM#-eF~OQNM0s|rKq
+znv#MHPFB^`fK!2vU?oJ&NLg@Gpb<yFc}%Saf>yJk9^xI4l7<Fr1GSa)4VDohigTN#
+z4%8~<kP=Ba7b&TiOQEf`!wNLjY#=H~^Ry}MH7}=_D@aZ_d8VigQ7#vzTE*3F-i1c3
+z7_V1&0RO9V&=LM&()lk}{hOlxO~tgXYscUevjcMGNl<%Jds_|KNZFOxusk6$r<5&A
+znVXZ7GBtBbW_HTt?3`)Y)3WnYG8%*JO*KVpYMN?V>#LBhY^|y*f~%b|ZAwbUnv{%1
+zlT$Kk7Z=aPujF3_R#FfSY;$V{RtWTq1!h;b1*PP1<<HP;S&e1g-lAl`t!7=IX?3ex
+z5ZXASEHEeMT_P7^CY6oM5OMBgiFwJI*2<PTD3S(9BpNMgYpJZlijjzLwh_~eAz+<`
+z3OMtvO;wda&OKXHHnh}n<u9qOU!x_XwYt59OFr1#fR=5O1ANA(1Z`?>bm1cM#unDJ
+zv^QbhO58P-1ZiunB8IA#jaDsmLmLODR42h3n%7f#Kyg8&0Gy+G2sBac)Hb)EyUJj5
+zJryM0iW1PZ5>cQM?`fs>U9!5NvS}^xN;^YPC~_^j@+^2DAj27f)m*M@0pGk8BPw39
+z!HiY9^sKJr^*wm+4b9L_fM{=N0fl%&i&?YSPI5qK0Q~}h7C1n1IcS3*H5G`VV!@eV
+z5G@aXV+t_7CJ9|DSq>yk<QibvMgk*U-$-37b1F%IrkeG#1Z_A47^s@(Ky4$f$A&g2
+zE=!$IhIG`{NGPf`Z7BnaH;QE{E(5|^Dxr_(EL(bN;M94iBQGuPl0|b%17(ZKPFjG3
+zR9-c$(2!7A7y=<6Z=i^J9&;<3G}TtOp|qo|k`uIsb_dfZ5iOoGw{-qeE7%;YY|xc5
+zE`-_SY$-L~TGP_7F@UL1QqWurt&Zxdj@s5{DMK8d>Q*W?3<eEcoRzGEgwep5A-C2*
+z*FxR`0g{J}T2o+CO>48oleSWpT+<@uQ%(v-hJ~{>AWbo*u5E)F$LaGHT5XC!0BMCI
+z(cBp5kSpG5tCVwsGUYu;6R6!6xH8(}5QaoZjzJ>pWUjWdu^vMqQJ~a}S<5zhf~ljr
+zmHb!gj3y3fq>ymUU@Vfm#P621#+pVfI<>eVg0*TK^XAT7%;|$m9;m8pz}nQfFbWs|
+zNetvP9JwPvYfU4xo1771f_M={^ZF*Yt5(xSUUTZ?f3ln=#2l9fIrMZeQ<Ydzk}L2Y
+zG&WE}3dysYY9l6!3=9i1PgKEXj2lwd6l|^pEkW33NWRswUiuY*I(Um5k&z?N&E?!+
+zkr7yCwOBILzA_J435^%%Ing+}9mt)mxHNacqWR_X=c2qx#&APHSIxvzPM-sD0F&f;
+zfJX~L0&)$)2x4@4{^SZ+vh?)%fW~UW92=#j7LpVjtO9bgmQJsBg+QA0!ceSE3u3i3
+zX*ry;LM4{WKTWT#mdZBed||<87t5t`F#5)3cw1ERzz6<M#;dg?XQXioHbTJKTNP_t
+zg3x^^kv?TDoNBm;@U6)o-oOG;0Yj-nfl0bq5OtVTdg)R%n_>=z<!yEK!8$qLQt#`*
+z1R>CFoO1P62H9~V`p0c*Ynk3y1FuHz3YuuD=M~Rg8jzl-O3qoj^mKyNx53VWe6X=C
+z*bJ3swJ9YVK_n%P<CRolxdSZB-TEdlUdm>z<Vom=CMm+~l9=jBs2BQTa<=5)IZ76}
+z*aMk$X?S$TkwU9+lWgH00`RhhB!v5JsceOzS<|RG1~#@Zd<1)C2OA`J8`qi{12}vw
+z47vr%0Mx;!b)lqU1=W?S>C>ZjJ!v;f2Ua>XnV?p(LJ9}RN<j2oTVK;qO^dCC$Aue)
+z$d#ilB!Lv<4N~d1Q}bh?>unF@5gHew4;!hphTat!D~UZ{qcW{60XQ4dD^`9b@hH2a
+zo9K-ce1+P|_J*KUrxp`@c(ADj^CDLdY%!d9cw^02pzW>jfdEIVB{jNSWsQ|VXkV#T
+z8#x#{AFa(`QHxT}5=iw%oVY(r4jJ}bQ6ihdwt$muHRLCn2b<RhS_3&%=uPTsc!k0C
+zHsrt>7(~4pgsujyq;s_zw4zOJIqLgxPCC}G2<O1a(C1aD$)QxPo6Qs&HJfcMSfqsK
+z)XEH-gfh9B5`>*FLPctLw&=-_Ixc8vdFi&(?9tN#pP>%n=(|Tu#z?PAbA|?3P6PJi
+zsG_vADPyVmtx%fL5C#n4RA`1&V%ujBELyy@cu^VYgiEH_+M?RCS#xtJNI-OL6p22f
+z-DC`)+Q!gQVyew70*RKa`X>0ha)C(WtUJ`}RC!R+HIybg8@;s337HIZji88|Qm}Zk
+z)x;)L4d5=YD<#2=E6OFSLxt3jR7utCjg1>Qd0a*CC%9>C;})-81|#To5eq19l8OMN
+z5t_*OU+F}|Jr<o#%PKv5^dV=2?bH?)#MOhyyu3hLTU8~uz+Cmv8L)~_wlx6=xQw(D
+zvm^^RxTdH-S`nD%Mm>CCv$nYvD+s$!Qr8r6x0FMmxTSmnxJZchn1Rz>2)Qy`1z?-3
+z3pTb$0e}P0SXosEf~2fK1gTa+;vpAtD|W%HZS>Hqn>mpT0x%$9E_#An*t_To%x)7F
+zPZ$Ne3n=apH7<h~;v#ynXm4aq9ag_w3t(XfoLj_a0zvquZaM3Sbn4|LA*;5<Y`WKk
+zQtJ9tYt0(98?MAG!DZGv0-(fey}@_74^*oVD2YnyW*G3+TI`hqxE_Ts8p54ut;a9!
+z=B_fNS@j@0XrTh0QXAw2ekB~}7HR4lt7{sd-QiI}zG}D<<P{RDwxPYPPUq!%Wmrmi
+zaag@{*+7$Y$eWcaY@(;81cV|euX9+i+gSLzxV~005B^>iA_##7*_sTLn@DWLF)?z(
+z5UgSq{I6gYCO`@}{?o`c*U}V$SlO0c!n-0Rig?gS%4CF!opM9ifQTDr2-2gjCBboB
+zgXJ0ANXTG^w2@fxRe+M+vL5WIYOHL7yU`IKU0_>)j8PYUAY*}=syY~w`ZbU~$%`sd
+z3kXK<*mL9BHdr1^mb{k5N;(-B5TNCNB*7?0xDG+Oz`}V`Plm4o*9g_LcKRAXxH>R*
+zX}Jq}Sqpp&?!73nU|f))7VH6N`GIV%E(y0UrZTHTfX#(uDRgif*R8c0-rHKMi4p*B
+zn>ZKGnK!Sv>=Y|rU1qRy^ncr0W|9kak=MfO$@Hs1bP@g?+i<CASQ^5$#3bFgmVOOf
+zrx{!eLb#Tjq#M_1Ujx_a2A8|x>0hH^`SBW-e~pF}$7@(|OvA-`Y`vi|E;GqtxR%0?
+zZJlkBBXp6P4wLJ_p$rYE65(Hio)@q9v8|;hxlCTV#_g9@&j+0*)2s_UR;y*w2E7DS
+zXu`jy14FcJoo14&a9xNW+gfgtr)cz~|FqpEw_BG2&?NUq0Gb?Lm|!rP<Xl~(Fq+&Y
+zVL+2KqfmefPx$xPVVrJ;VH#ri&v%AfsMN9T%8%3Tp|8=d!n7+7v2BS-8b*=!isP_t
+z$?@1$vHMuIEjb?BDs~^swk5}7+p*Gnz2--TrrBd<?>6a=bs6~fc&8CnGZI;7G8;oe
+zm%Y1Nr_G3n(WK3IWMh;0$ko`Sy`kw}Y?2Fgk!))+4PiKwY<I(%jA4dtnfVUMff?<V
+z&}gH-+-)*<ho*9|Nxl+->)F|9GKN*aZy3cl2J(ZV?K=5DxX2_A=^~GnvpWu#TlpEN
+z|FbMZr)%|pVSzf6xmp*Zi<@-vm2gp(=IadoA5bP~=8Zj=xw$tCW|C%x!15iPM#K#3
+zB_)dB@NZvca`Fu?4X<o#iQ&=S5JQ%jq+yJ(+P3XB8N&rMHA%w*_F&TIhM0u5CUaeg
+zBTG#3J8n3W33Ki=lQis-w3v+H9cbyh7A0I?K9RsMgH-D4unA0m_js%B-OgjX1?1Q1
+z_K2n<CM?w^IVdy}XPU_g5A;lvGzJBtWRhmN+t!)aYY8$E1t^m=Di~0Gd2yF6xKIB_
+zE0Z*>z>0g1QNWLD_@9N_nWU@T_l{}ztcHIp+|DG;SkT|TPLsJhye>@Ag@4~y;x}^~
+zWA)-zBK0w4MqQwzJ;$5l|EIPu0h6k@+P*U&n`lsQCpsW5aX~~7+`%O-zf1RY_lR+3
+znqd|gna!C20TGCKV$iseVAPm=jmEe{P0$$Q7R78DqY<NtCPpR37-KZS#N9;yQ(f<S
+z>P}TP_~rTkc^;^@&OKY5I#svsz18=wS;mMnfN3qHrH1Dk+2UhOjK=hr79fp@Q<cmk
+zbfZ~3VTH40S_hlJl3`?%(!8Xtb5rG2%UE&KKoemq99L;LevFKi7+tlD6;78`NfRMw
+z%`zV=oDqbNkP$8OvBDEq+Ix09!<;@w8lzoS#>$`21!)1&{-RmbM93(Ybug?f*Pt8M
+zqLdXq;awn^wM4k04+Zlv!EpH=3T9)1;aWWutc?kVYxPiYR!lHltFJ=@o^`<?d|{Kp
+zq2SXhm?xwHS^g5Hb%pVwu3xLJEFl$CCAEZUU112R>j~9WOGpJ($t=ROt}v<_pyO@T
+zRUrHjq<H3pg87(W7>Q6Y8xsthoycn;%-;?uCCLdt4N}}y3Yrh}nm@THBBTQ8N5ZtO
+z(EA$bI8${M2+g<Bt@<3{HuwT)+%M`nS_Sij-vg;SIVU0h8)z~EY*@z1$0<hQk+523
+zWQDF6js71UVM`<$gj+&aRZ=9RM$@Qli8bmM#?7m*rFu#kU14&De$Da)rH!u!Csl_3
+zRSj&0P=10^{*(0>AzL6z2|~IhTz+HPp|jWNCfq`G*N2LNmCS`uaH~^9I8+rigo+w`
+zk67OoK*j~(NOx9T6LvfJ_fWY!;o(Xu5T;b!6sS4^{JdO}P!fJcSC0)p1pJ*Ny#V-<
+zk|+m_Npc_1W9n0e@CcR45uT`|%t?Tqjud(j^zXl5h6*L0L#ZIeL#bRS71%l(w$9h4
+z)f0YRo&F@|&8Mx+pZV6V`IGn)x^^_uqn|l0Lf0jYR)hP0Iv_j7T%i!V&aI<zr>Tye
+z%hZWo+fdVNSgA^a{PtM}CnJ)<!9|kK6}fiU746<#+aL7EC=8hSC}k`WUaO=W;RswA
+z#;14c`i2VT3Dbh%Ifm;0q=LCW15z+DF--@{i71C8|Gal+*NuvNzN+MOJqB<oRIEZd
+zJn2c!PR8#3@z4@USLvYzJVX*3DQ6L1aT}x@i-zQzIAmfOhJ=FTia0$Aol&D#@CCx-
+zlvGc6(k8o(f|FG+M|iN33ey0oQ|@Q_4c=?>EEL%aKvIs7cfUn3;VIy<DaRV~SY!$N
+zRbAlJSRDF{vSbK(?_TmNR748Il4J$YN>x-KT&1KOq4`;b`4cAzzh)`&uEFTV36A~>
+zr3eyUiENS6|4qwrSc^44zd<SMJ;LkV&?n@bI-7W`(LiLNh3d0Z-vsq$kwttZXyWRc
+z<*a-o#Yjxk#*u7^wU1Mr#D}`puUXED`3}7Kv*N6=9kFHKnlgWq{0U`je&*?ePD(1i
+z43D~CP^N6c#Yzg2?l?#-K`Eyw!sQ@sAv4LcWPGTMb36P@l7*0<SMs^McfVzi1}6re
+zH!@1easkv1NqUD35l>jZR2}Rw4zju$WXVhQ4B#Cc+7|)Yl!HER<P=Dj2~amOS(+R)
+zK~jIn?!$(R_l>Us*KH`pKf-?~sh)5nNOlae_P%2z{9pj%=8fiQ^bH6ON)|3E(ZIWD
+zqOWWn4nB=il7(=Cl5$k_rX%@^SZ4=GC<ss0-m53P2P7G)8<(<DrP}L90q*2Tp9SQ-
+zXIXX--i<?LZI7e!A16xa&glihZE@O&EMmeI<=G-C6oc!RvO<+I2@>uA?PWgd^Ghm~
+zvp6ADirjk<{n?2A_m=v4Ia@!D1EQbnL`J$gnNcz?yf=T>YrN`i1!R0919>bukR57f
+zv{ukAbNx+t6G+38g~_T%maZN=wnP$pe|XZ*L$u3&O&xj%t}#NfnRF$LQFA0yBHjHz
+zHVnzNC}kuNQjv7W%S-7T^Q=tt-6|8INQ((T>}BIS@%!*u1UD>Y_b~g*MCSi&M4(KZ
+zi%Ka?WX1JphVYRzA1iE$w3zTOX};G{Va&^xSz#)g#t?H*l^M190NbOb%p6HBKYEdT
+zn*$%%VDZ&g{8zBJNh(7~1Jy}iFihAhGoWu!a`u=KD;*%p;)IZSA`g|SO029^z5*fJ
+zCqZ~*DJvWg(n3Ox18ET<^G#+FLU$`(tg^y9k$aGYOc`;Q33I0QWnXoPl~yG#sw%PK
+zf}11kQ$DfF%DEtl-LC>N!Ne{h2TD0mtZ+z6)0k_|s<s^AOU`O_i4~@y=v!K1g*_{F
+z37MJYz_Y^CEcY%eTj}&Hjbnw$D~&^^YQag56O61M2zgO19ZSfr6RxoJbqoZfAY6U}
+zBFhs_7fePo>WF`+IasTvHMF(NhRYnu?<lz~PH)%|Mn5s#6E+6W#i~|=1aJ$=2T=}6
+zhK0{teI{dW^NLoz8Vq7u;kj<OEO3X_Oc++PXQ0n#HJJ#Tyyh8{EDimjoMVdk!Bb#6
+zCOJ_~c$S;t*9ZPnj!cnzyF9cMdd#`okCo38$)H#08S)^e#^;H~gG`)^%EO!$PDhbJ
+z#OtLw>cG<d{C4mdC#LFTO3+rHNAAKrvA?fK>OS9~L}omnZv~vWTt`QE364WwL|G0B
+zD{fTf38^X?JdP=zvxX*1C#)VkV~@ZwGH||&MZ)KiNW2h>gwI!=Nc~9ghRgxFFfI_z
+zQBpl&D@gW|hP8_wBjIHO7%Le)R0Z>dElO%2q#0v0Ut;Z2$4Hnq8s6z*OKC~g$Aq(0
+zR~;eE*o%JFE^>^7X`|tzwId-=RKXl|UFb-De8|!Xmf=ZXGV){j+qp#2IVzncToiIw
+zQcTv!%8R!9plzhwqO?=%(qw#zRN9POp<fQcm(;@o;i9dqLxbfq@IT9Z=P3BP3g!u?
+z>vNkr!b?H2S;5-Fj*;+*0gSBm!4-)Bq4O?wqm<sgtlnh_o#3kX!e*U;Ee98(l!YJR
+z9Q8IAHXuh=Zys(VC2O9IfVnM|bUWbB9BJf8dvtr0Vv(?0Nx6#w*?dv&_sBMQQ2kew
+zTgV2W2bY&vb?!IP{dL-+M!J6nw%y3?Tf$C|pzjV;Hw+}R>e}DP_J4i^+uumYMnh*7
+zt#b`-d>*6^QG%0I7l%ea4qL-9`Y)H0^n_-G6q>B3$!VHx^}g;$kxv^nuQG(Gym~dv
+zt2-fZ7#?$)#nf+s|A4Z*IgowxRrF1n$fmFzMw)G5Lkx}aV@qO7ww+*&p2%wEKZuy?
+zyQ1IlAz(QgrDQ3cd0#U=^D%mQXHD<gFym_(-@`P{!R6xbF#P`Lh9Tilq<3|)Z~`%N
+zTc)Z%{AU?M$T`JQnc-}trLqx>rlm5bjHjhCs?0r0^&{1aaL`WVZU$S&E->9hyq}KA
+z2Es|23O!XNHqMRR2DWT>?VAQB44p6*81`c|?7=g}H<6_yUD&DNZr96m(7V0b%Y{C`
+zMM}zWihJIX2>%U|1n}<vEMu(-BRz7KT7jIs5~b`=BTRMuI@k4#j#v;X1H`CUYNYFh
+zH`4V&jdZ<G{jR?(aI=+ea;)1Xv&NBMmCPYbwMSyZ-sWr|jD)Es3S*>+LX9+0sF5ZL
+zHPS?(`c2#(nXx;{=#?Xx#%mhoE9r488A7U-P;CeuC_?87l+}?dt&k_YVkA!&^vL;T
+z%}2{htWtes^j-vsOHs;H=(mmo{B^KMQ&xNw#PUNN<t!Fa^e>M^CcRO<u>&w6p6br~
+z>!c;Dehy^0+$6khASbK$IPy<L0jocA<VS?e>XVNAn2<TPQmX~yh41VQkh&eEwD}Ie
+zA34$kfWL60M*(Rz5-c`vkxJE{3wW&~5wg{0Y9wZp&4nB>+gqJX587Ux93C`0k}>R|
+zW8p>YwCwZ9qq3`Su+a;G$cC~h(zSm0BR3biV12d5B15UUdgcgHnYJiBT%NgAxOwBV
+zMtlfaf|Uj{gneTAf+@m2F*N3g>z^qlKS^R2<i38nAb)#`1lqSjx^IVc-xleWGM?>`
+ziN*{J-<*)mp!2N>*$g`0n2^n&^KEgb;NE(k4EmGHKgSaE08d5lK+BHh)AT#T_J3=C
+zn<q0ao3ZP=Q{GKV<oH1CWeGprtg!Dq%~I0*&SrBwk-_#|td@9wlrvPQ$7hO-NS`Nu
+zKB~gd*+PfV8H8LjOJ}W&bQUGaCi))<&v!mo%u}DoYz?akVn;5zC$~Qd=|Uu&p;RH1
+z3a&+WLp1i&sMK;T@_=3q)^Z`zt}DM<Uf+$@MQZI%fCoB~pBAG%a}vrsKGxL_En2E?
+z)KY!Bmg<|fRNwlgu+E>X2-o%D*?vbXpljShny?!rqyE9=zWOmZN(FM}Bjn;daz~n%
+zAw6m?xR~`>#C&AI<#UZnmg5AlDj7c_Q!_S5G<x-Wn3kDw*-XDxQup~}oNSDYleeJe
+z4J3}uZg!))L^C<hMJ%s%;v<0?7iuaN2$?Ig(5j+|22IZbAv4ynF?EJ&eijIs#fFW!
+zw1;COWM&&SKTh<Ot(PE~(+7QH^Fj985Ax=e+Mf4yTB@%yo+ZAUGL!h~gyidr%r{4)
+zPuLNX?Nn6Me#j8AALRBhyJ5J-H$%v75H9w@UXF{9y&znb;`M(tVHya#KpK?vk14T2
+z=ZDJg$w!zQ!EC}TG@;DR3LBx^Y)UnpEOWEM#wa(Nw7)i~fsjp7UcX^?dC}g)qdBrZ
+z2$6UmT#cjTj$NMlJQb2O!glA!;hN`tSakQCf;A7v4q3!?IX(DyrYzNu(4M$gaTv<z
+za>8edouqx9c>H)DY9CFM$m+#sikTzN7$}k;o5__`>W?J*)sVP-Q!e;SF&D^l?LZe;
+zrT&Nu?1aw%$SonlsY+@jJRGD!$+D^vEA5W&EI?j>i#Eb9IxfPC)7n`1p5t2!_%lZW
+z3W}YSB~Lh4NezT_&psPr?Ka0qNXwRyHRnfgJC6=Ab`ojAR#jh5NXzyi8f%M`F-u5`
+zmXSvMl9psg0wHx8!P*jQR40tSj%`4ggHoP)5Hfnz$$1GeH4ZY*9$BH+B1`Bj1~dKk
+zu+*#;>j<fEglI2F1I8aXR@-p1V<%+)43l%fg2XVB;>-uzgV#gP-&J3MP(CkE{*z~5
+zg!_PG;#nxMc9dfzoH2lrwW}N>;nf2eS$oYf68>!fBWnpBznfdQfTK}bA6YvBH<}}l
+zG#P?vYBWzs$BnLhiM1~{MnXDn8CiSQF%r^o%gEZhj**a#TSnF<XnXU72ZB_cteQo9
+zhGQfALMklz5^Fa)M#8%WFtYZrV<dcj03&NJJ4V9v2IhQ;wJPnAJRvv8+BUN`-Z2vH
+z3zB7IZHi+gWVc&J<hT~>dH!ZgrYl0`wh_!~rZX>uk;(ABc3qZ`on>WNV}FS(;XbJd
+ziV@V<iLwwSd`5$sC1kv<5!T*vjEwU(8kH;|BWq<@W30qMjS#?aG;$ou*doj4k*od9
+zsgaH8;eGM~Y|KKLS|O6eZFUkNCNlF>NK6OUo{aAZZE*OCuY}ZXV)MTkCp5~$6ODxQ
+z!)mPLN<ErejtMJtM$S}h==IvewS;VYS(J{@YUCt$D@;8fMwkglYpLKfO=uu>$Zr!3
+zaMF`t5Yna%2F-Dj5=KILU>Rwg6M!%h(w}&E>B{%h;bn!+q()kuhBre<Ps-t?BeW`_
+ze(Psoz|GTvS0J3BPjHHaGxdp$Ii<38i(@3bbpRu4&pF0Qel)5ddBRteR7Xh5X0b7A
+z#so?Jaq3O48mS{ZAEY!pY2R|}gmgE}PMT{%usR7tnPn*7(<U?!vI!;=vg*8hu+~6G
+zM=c|3H>%qWgmlp|vgRBP7QmsywRHGMRo_UMcDPm@zS%Jn(z5ZRw#1tAqp?!o)41%s
+zB)miemm^I3F-!emSIat<@Ikm{{Fqf@&G`}BmSsF>$y~J&U#E^_2q$aPbM%R(jU@4P
+z%9dd)?p9KckZ#4U6x(6@Jm&-9Q%b6*4_Q^7A*3sELy7tGZRM(`SB#Kw5k8_^!Nl=Z
+zSpF7Dx$++u-0Sq2B6qaN!l=p|MM%|=-CWghYzLHECVl&@9*lj3etwa82$*H_=%f-W
+z)F6{I;f`s(O3Fq!rpYB%s6kfvgehf{gZONKk`uPDW<-wg3rZ>yz66p<=t7CL@%nVB
+zNH|4F1;X<|va+mwQyGhdUASFu8CknfpHvhH|2BZp4^!B(JX>~}wk$_jP*R5Q7A55f
+z?^RNUkU@|uCBoCRO*z6^CDjq0p`;vxv2Z9mAxFsOi+VyfUy_pWM;e?u!iSZVBYZ_k
+z!I^`>nyC%U63$UlBO!ZPZs=5(SUFVNlO;R?B-4}G5?lFGP|MP+{6eMc2^$fOAx3)l
+z>JsaGyj7NG1y4Q`8Q+9IMsv%2tS}bBN64_0`6^`*w+6`ikdO^Gt*ecMp_XAt=V|!%
+z7>1t7Dd!%-4-k6!G0y69S)p0U2tpbXQ9@={S(K4y29=4dFo#4Rp^J#v^&`S0_#e#+
+zO?<u}NmLOg=+{xE39?Cl!m?y_)v%9u9;fNRZWW<0cY{RzG^}>2^#;PFO3Dy&L`s9N
+zI+qo?WY(haj)5%mF<M{Kl*|w^HOqXgumOXT^Ok9nrb2jC5W<_GnHuC0lJG4Y+DdMl
+zNtl)<V<q{=m%_*d7oAkf5j9|VQLUss;cyHu`H98y5-X#02CAn?j+{!v$j^^A(G84k
+zwM-H|56>r8x-KJRFUccQo)CWEI)d<CB^4Qd=CcSgkJ$tv5pvK==M%E4A`fYq<DBe8
+ziqQF4cRZZo%r2Qsr#dvA8A9i$jyF0df}vBv5a7w^J`G;ck1tv1Y|3vZ6)0xUai)p&
+z9P{*jv{|-6y?LuOAFM5W-s<F_&GJM#fu@+FpNJ(`;wLy8j6pflObM$8W2+RYWAzjn
+ztj(!_XPokQV8zJ=Pw^>7mgrp^X6$9K9}E50aqPBe3rM|PTaYE>F9HTO+0PlOCwKI8
+z7&1j}Nim0C(8h#6w)1(S)<UL;wT-ayfi}EAxchM1NHf!Wf0J<NA!R8LJ`R#ye|mBW
+z1?Q_^p77F?V7|oKeU6bZZ6W+=6)ilhf?2|}VEFSW3Z4i-b0tUIq{=dcblb4?;V_++
+zYZ1aLoh0E6O3D+`v)I++v0$e!(jA1(hXn~SeGxXoCC(rr-4iat{{ff%DDuFLTaRO}
+zs-^<ruo0Fu-rp2_Mg{YPLm?>BHep&<*t68djW=@MC!{kHc*3-<u(PS_dG)K7kP1XS
+zVOm$X1f{N*Ro5&+Dv)(AVOm%C8dK^bcU5u*VOlVJY5PB5{6FeMhH!`mI!8!dk)b^b
+z-219jVL!mBO3D#VQxbn3u8Ff(D5b{$W`L#BX(62dDa#{k#k-eQlKYCv1$Y0c`V?i!
+z5^hvdBjLY5vX@${(FggpnD4<#2+#vFaETvP{aI?-L4PHZtpzMP(vJWiaU{Z*K&nnA
+zmqsHbV^KyPoqT$0>*y4e(!Yd9C@JWvO*Q5@ZA^}hIaJ-u5uT!?4B;QtUXJijO3Dzn
+zX<LF7!-d%JbA@jF$;<?IUZsLF({gyS+Id9CFv|*vVJ)dg#hU@?tZ;1sGYq^$ld*Sx
+z2dl?Ru^;3%l#y=w6%M_rEEz)Xt&_Z87v%jH(Woo5aY59`!bXeFgib2(`4~8IJjyMT
+z<&|&8`OGruQtkxE4@#DY&)Pz{LPRdS$#xGC-~mm9VC_woA1O<LkWx{X4ne1HVsNYj
+z%M+R^f%P8b$y!azg2GXDK*|(S1vn9<Jz=u;o?|3jg8d<uk+qrIsz$=Rk_v=vAX!<~
+z9#Y0e!k-Ud^rtzt>_^(Nyh3$27i(F*#FqWRF%q&Z#=CrpwcF8Nxid$2A4r3e1^E&y
+zucYFVFR{j8h&178+T1)LBVjGGwn!Osgy(}K_nJ>FvBIE<4Z?K%!X*pi_kE3DmQdrE
+z6bR|JaZVm7!GqcAT$V6xG+f)zDAmg1gOECn1$hP(Sg4Iz2v<Czg;}(~T##SK5Hb;r
+z(OH@nG%k#UG%h#d2-!ncmbHg8Bn^b=kc7*s(BU&ehwJF*6`HYiguevI_;E&wwSzTd
+z>j)3gj9s|2#7c+bBRt#jRh3xbNRTBlA!B0=v&Qhq@{o|Rv5c%Sb44Q|BW4->5&seV
+z+D=29q2LXU<V!Ii9N^_AG_0^GGHU1+M_HMVmGhuqh|5Z>(6|WuM(@F((w<DRgb(15
+zc>-Kp;rCpjxXx`9|3pT0_)^LQHXN0QBZKCmjO}U(dBU?Od1h)xuG+Y)#2U5B5c0#t
+zL-QdRS(k(?d2)9^N;)SzLx*y+d^y<<EN=QfT?DQ7qm=t$pSjI4RpjN6l=t~9N7s^c
+zBh;8z{oxQv_u-H%RtRY{#l1QIBER_?h5@rTN@>Dwm73u5$}`vShfF?G<m!XA_Jz$<
+z3rL!ZL(<EHoT5_PetW5yteddySb}{Cjj+vWE%sA4pC>ZZLYBZ1r<RqlC@<OD&u`Nu
+zICd?{Ej2l0(`qH=Yrq`2K=$=Ta^fjSb8Ql7T*wkMZV=|fT~Kb)aWZeIlW5Pl5-V;p
+z53Z9bM<bEea0<Q!swKnssFdM8Z#2Wn^kpcNxnaff5^FRQ*=xW<w?i<M$t2y4Lz4G|
+zJmICd{cfk?`&GK0kkZ!4N`mBygl|1`jvH--Wsd;i8z7nYHWR-Gnp^;GT*}ISQjER}
+zq5eGeQ_P%^!o_JQn5E#m>T8jZuGq61YqSt~st~HLrTX<yKh(TqcF68kB@(F47zvl1
+zA9;~9H(jW5wR&84H6WGB+Q*Ms8(7XlDQC64N~|nXRT;t?(tN%$-z_=C&@1Oc@L=O?
+zsHC?ts%BOiRpea&nIZBc#f9<)EY`15kAr(V$r$VIVJId02wziDBjMjbGVw2zSlj3r
+z{kDhd^Hl$eO4Somq0L9uocbV01?ZTsy6OnOuB5#06g|i&OQ6_iiGOaw=Za(!ZSM#m
+z@g;l!yFkt8CjN!)43+o9v+^3A@Wx)>PW_Wqf1Z$HGE;=F#}DPQl)Do?$XSVyp4h?7
+z+MjiMs(zY+HZ3EK_$4jLl_z0ZFdW%OLc<N}T9HmnRVRvse4nVCoC&XST<ZXTp`;9<
+zYfx|ptQ{V7q7>bP&Z&AjwVUd$4?PHy?Lg=}$>}C^y6ZySbu=?k&1DE(gX;)ybzF>r
+zYj7|H_QRPa&MCs5E2)7_{aHIESf*SA?ysm+hVW{T1|{-pCswXizF@K%3M+h1vvk5B
+zG>V}R61Pb6Etf)qN-fxe8Yrwz4lSJxd~J%h5t!NyAJsFghNg-Eo=3?aa8%O&Np$TD
+zALwhOIW)t#R3|;7e3zbr8uyW<pr<w>mcw+@X`Ya8pOi%x;ZfkSleKRy)Rm<!zGqS{
+z9thLA!b@XcSL`V$_x5sAxy-YK<FJz>IuBCrT-Rp8tCW-@d<y$HZJSwp7gU)r328GP
+zoX}`3jm}qH4TL=@qqQa0N{*56J4&i0q#u!WC)@OpHZwzbiYm&{9NU^|W1>4`GK6E5
+zl=Bnf9GF>((sUy6D(3>BbD=JDp^o1CQ60@N^3H`|N}~%uPPw4iX&MB0k|WWDYaQvw
+zfOJKMB_Umi<>?rR@ikx7$<)%hpnVCYq50w48^>lS&%puDBt(C@_CkU1|0t=Buni=W
+zqJ<J`cREJG9}Hk*?I(_r@TUV9{T9%>V^lCt*rKEyA^oufh_&xKMnd{y8Cm<WV<b#_
+z7hde-AW%@j;H2^Y-w9e^<Yhfc$cEY8VvUg(M#6M6!%w|_70oN5td^INUk^;BhUWi$
+z-s6##o6o}cj$HuO$a#vEZc17A)vU)cw*#<1$nSMZYYCTPqnr(kuZtfq-3DCZ5@AkB
+z!Ax}!4oy>*455<>CKv9;b}Yd<uNn#`pp4z(4SB*_ygpClJ7_Cl;!<rxf$&El*^sfe
+z-Z2tBt)wg=-*^=dH;rDUf_XxkF@pILYd?34gtR0HMwm7l4&2aaEsfr->gxz;+4xbb
+zemtm*wS;^fmt|y)u0$^MO3=X%wMwoL(zu*Esp!vYF+=Ed2N`)SxYw#wkbYGB53t00
+zD8?0r)aQz{Ho?x@PwNic0^vOD6pVWi3g#);uDTit&jQKl%9mKX+A$J-eE=hCe{hV1
+z&ktZ^?LUr@@S_2Ytg&&C8{cf%Xw{V^Y*tboA=_eFmerQ=?WPiOLbk;+vi4i2k&tb%
+zjI6!u7zx=H%gCB*S&&<7*{4-kEn%yY>Iu^=lh<5;;R?q{$hH_iYD=s=>lg{y7R$)m
+z`;L*2ZLy53xt0Ypa@ew2Y}s5@-$2N=81=KXWmh^zLbk;+vi5t&NXWKWM%F%bjD&29
+zWn|5@EV!226*{J=t_)$5l5%X(R~(7n{@Rh~*S{Qz9_*ppf^&oiDk(#Ff|7ECStSMQ
+ztOYQ`JdtZoLON%{P+JO}2s)U$*fVk+M3~k!E21k1DRrfS6?zcN-ITgagI7nXVH$(F
+zk$|6eB!4l}gF`Enr9fD(n>urZEg+dl6-umq*D(^_HGq+|ryQg2$H%b0Jy>E_Ie!5U
+zf14#IL&DQla|6Blz9ad@{s~1}D@%sZDQcvmvmF=V50n(_(R>`bpF}B65<1=W)P1`u
+z3X<&iP{1AeqKMEbs-vRssiI(_y#k7EL@9TjH*OJJ=J{OmWT58dnsVee%PX$=A>IIg
+z-cY{^gxg|sr%j^G3+5^Kp6bdG@;&)RSH8p=Ey&WySO0hDcvp30C^Zs(MOssXL;EXB
+zfpEblTN4WADR`9X$`Nw=ux$-%XE;W}&!vp!ORUkANV6wG!0nvQP-?!a4?1xL4qc)w
+z1;RT(ig#itn5W=Xsw+pxm(tm0vqlS%)?5l5SE{ZIrEYa3zw6iG&@;+XAbi7ZZ6*8%
+zNVb8jwQXg!Mx3Jh$5efu@b9X=j*tp%n^|+}gHhZA%PZA`0^yB#@GrL_!{03?*g?93
+z?j+499L2`e?*q8rk)8oO0@~$-*#Ow2qzvJ8N(v^jnXvq(dXOVbbcbS*a4<-+bGE9)
+z3b!xH1K)>n{6!Vbh0Yg4=YyHxX}I&Yx|Jc^QGHmo=3G|BslhDaq%<EZ*E&8zx-T8H
+z=3II^T|=EE{47XiK319>AK}GmK31-Ce1tcp`B=H#@ew|f=3~XBLYC3|hl*x)L4O~l
+z{hsm1TbO2bY`fE4N8K*X>b?q{E~kRgFdjjks6EiLyu`{0+5>sQCM9JE=c#D_@)9d&
+zIX=dLyA0(4J0abdCrryr?;|LTNNnZu0}R?nb?{~sYD^o$=rq#OuazsqfVt=dYmjGP
+z=C3H@XMCS)Q)hgiH*$_-cTdvs6wCxZi+TQC9jq>VuE<=w5;iy)R40d&{OB1PW5wh$
+zG(Sy!UFFR~zOpjW*B0GoM0MA}MUxK1-_y`!3GY!-k?<iUWqn^8kOmy{(HY-oiri@N
+zS;`YmC1YRG+$;JlYcW!v(^;TEI2PMx<emoM)X`R6tUYobEB)J9qCL;Db|I)`R#xh_
+zPqVVN2GlYuE8iZ#TFLEq)$Kgt{xB?OJHja`5A!9~Xh9e^uRcrlH5!#1Ap;@)uZ>0}
+zTZ%+w?Rl}NWJ{5#tUWIlmGFTmJCnZ3%~HZ@jY<O{<6!!&R->{H;x1Rjg!ITVvPPGL
+zk&qF!jDApeMdYTTG~<f6Tcg@|2_UzP8#dw>9UCM1tTrr|L@!6S-imU9d<Jma-B<9h
+zYS@hJ$E2$J?_HH_Ke{v=yMJm>22zt^Qg^|P$5DPVDL+L2LOQ<#+otV`q1o(;W!EwA
+zhR@eE1g##0QYL&tCal>w#P00Xe$Nm(?dSN)lf}?_p3_eFn394X;h`6mB|~^Cnk=);
+zX=o|CIC4|<OW<a3WLZh6W=Kc27Vd=fnXGA)AzTTPjNzNk^IOY<*E%^uhO#WjSTb-?
+zW#^*pD^bchDEy(m&lKxmpC@vbrFSR7R&1x3&m;b<2$IQXiky-DyV2%{np$qt3<;7b
+zWXbtjeobkliL@ykAU;zp#y(GEzr=qxU-%wV%Q!a-HqR2=iaZ?BC#aSj;X)-9370D=
+zOUQ90gNNhDjl!(&Q9Ts2pfnLAZd2vKnuA83SC(8jc!NHD4BStvu^!)_gp-KV9Ar-k
+z;@?x_8DGskIP|b%A*2(7lHTQ|-{82j7N{csda%k4EZ<sEz=U<WPF#T+_QCaFiRQD<
+z6w7CyCz8+qZ_Z@Y@+)mr(4iqqkk79}dWfzNBXg6_6l=H76PdqgV~VpC&KW*a%ocgL
+zd`hjPs5`zuS_{jM>Z!Ouc+w6wZRAu)crr*vSGb|$PtfsCl*UowT~t|}pN!Z=l#Is#
+zSu{)l+|!YKsYxIlt1Jb=#URDK3<dKPY*$@%glS#j)9FJYFi!<@gl8!!L&z0P<fOR*
+z+^bcpK==!g;;jh<^Ax;Sb=483b%m|D2m<%0V2<!UC1nU7R#Gs^*5lC2%2FWQ30pto
+ztqBG56dVpg8AXI?U14i}597mBFh@8-Ng2W&loYgvn_Z7nmIC3H*dQctdb(-}E4SfR
+zuB^mXE`bwTP}#|<EKgWeQh|^vMgQe7{VM|fv!SF<m1PKD8*IIh^Xy3YU4*MbB5YPt
+z<|}|VDJeLu^3CoyyZzi(V@KnYZX+elO@&z*;b&oQ2*1iIq{l#d0;P}$chCoxjr=O>
+zd?nQ{1N@SbGKBmXt6Xp2f(KbYMJXgc8r)(yBa_jN0=NmzR71B}UN2$gAT<~y&E1H<
+z3wi^i;2dZm<l{fNcqVj@<{Aj^RX4MQ>@}J1!`=!`Z9hc@JgS+H`6HU(p8sYDXK0{u
+zC&O}4J;)HQP*M<s-4MI!u0sjg{gJ8gc;wA&mp_Dj6R}8r*K3M7*Bp(uFhvZF*riK`
+z@CRTwY{c9QA-P957-5i}e|2$~L>b10fiUX)Eb_gT@w{>g-DRA`z<Ys#GSN3tCi*tc
+zM8+}mj330zLa}@C66WC&bc<;F_u}R3D|Ba>I31NEw2w1{OuRB5D@;LSnwXPEnbG%|
+z{;k*9Dwtt>7IXKvDhP1MwQ${e0oORB)Zr*49BYFa^b{Oya!fZ>WMXDYz7SF_lG+6%
+z?Lw4M`#i`&TAdtR;zYyw!qC_g?p<gH2SGP{e#|d`@jFpgC(}wyL8iB%Q9qN<(3s=S
+z=Cp{-X@Si>kwBAOBJt~T%pHlK@9FzEU5s&wx+ds}J#g?4$8=RiCQd(MjF57X?&6_S
+zo$4?X$aJhS^^GgBates@3lKu5O!)j3S7S=r2Bkb)+4K9BX|uf1dpf?tNGrn`vYs>K
+zH{ga`0o(@ofFluZ@*Epn3v)Uh?xxk7mN3U=BR^!a2qR5No}Z)>38_q)M^!vO2^S%?
+zM}iOz05`y>(F~?=0DQ7RcRE_@2H5n7uIZ7%G(G5ezE;-hI<#~d0_O(ip%Go-kHfwg
+z_%$UWHzn}lPAmz3txLnq(}2HqBtN}3;1J)=Cc}bo?*SVpHZPc`;P$#pqMq>6DP8#z
+zYkN6H!nD!w0wVNQ-;qa4axp?kGv>l3t48-wqjiL7qv7L}R}muj7QP%cPf%SsLh6c4
+zo|C|Rgh~|%f2gE7!n;9=UzSlYqk@Gj;2BEF5jH5P;P>Onp_I=;=^m%$Y{11z$`PKY
+zq`+23DCOIt^yN;=D!{9ilp|z}Bx`*|7l%?l3+sI6hiD;u7RO|oC43Gf+aIib=oqPv
+z<t%{t%98mm;Qfw7MbA4DkSnkho2*N+0wF)jCVmqB9bDE=*0$HH!C?AN0`+;SpQ9FY
+zg#S#b&zD%+M%CvCY0>x*j^xm2mPX%DqeVit!syDDSfho=BOZFo3vC&V4?^t|sy;(S
+z{2gy(%+{b`8Es&J@O&lJ5nck4tRk0}SSdNa8vyTdB*F)k6r}QW9HL>fmM8wEiq(h8
+zg9qB5Oj83j-KokO2<dL@l8QeYe?-L!gfA*7NB9?zY@V|Aj$<Tze*hzE{J52@90+&B
+z<$=}chL1(RftnZ8LWa6VLom|+zxSjDCp|k38A2T|;i&8%N`|oVGKl6TKk+NhsPEU?
+zIP_j+7Wz3x{R}SbYjEfUWhoGzq@)aCkCJkPXM<#e#~SY(Mb>9I2%M?9GL*W=k^I)q
+z#34E-b1osBi}b=8NZqB13xtn>Wc_CC1;<GE?f^#LulsQHCn}iv6W|+;^bf$d9m!X;
+z4u_~H_G9}5*LkB+N)QN(N~$NE4U%mkYs(#@?*i5DqbzyC1|`)IQlU|wFR|v-2M-4h
+zfR3Y3ZsNsAKC8S1X;pX+z~_qW#GzY#>VGh|g)D*RD<JK@epMjkrM(R@YcHs|0%3>V
+zFs&mz8zd|1_r}Z6@exY1apN#ZP($n$XaDl#WLQuvt3Cu5=#+X7(px6O_UW--eHmLK
+zk**Av7i*M12(w#oHBk!_bF^)-dpzW7s_YP1s3`VpR7l^bS_*`ZsCn~ri?wGRBjLC8
+zvOY)n9gyPP!XM%`t6+w3o|5Vad2`g9_Ih#nGRNlk`A2Zji5(b3cq@ocR5d|ol4V=4
+z4CqV}cf`R>bmjqIISOU`h8?+%1XpApCJPlsI+H&_eOR>=2pipv3c?~twvSljZx&@$
+z>qnOA`D8*i^AhrooLm7CUY=5)FR^yJ`cX$ni^h*|vHA+yvXu&E2v1j1j^5woNQAd4
+zDMLt$kuxjXjP0YcR4x!=S9222=~0mUIZ6>E9HXn=I>PNhvbtE~`(z@I#;N`%sy<Kn
+zqLOA2Qc*mlyzC*jyo#1^19ZvBV&%dTDq2v`ag9g@Z<Z?(Wh!_Ns^!Ms{Wn+~sPlOv
+z!GV?pJGD)x5f*VwqzLDLWMj|Ta>qz@emPoM@`O!FswbpE8++EA`rzbAGt_D3IpT?`
+zKSxa+AjymGs!F}6P<@$5g)FILvPv!-Tw>)25G7`WN2d9xgyr!7wJ1f7Fb9%cfekH@
+zpXCYwK8_bT!s~HJ5{2+*APr9X?p;=5?NOzgGZJg>J8{BEI=qZHj%%?3XcbDC#|VF+
+zq<TV{vHi&!EkxE!UxbdUQOb;8JuGm7T(q2Wf`Sp<G~0~^N)!pV(sgkoAy?#slVy)A
+zE3x*vV<hC4GA$!(Yp{+PmaMvb>5yU5!*{OI9e1gpC)`f0)DhAF8%fsagN#r@8n%oG
+zqZXmjERF6AkL9ie;VvK<UD*<Av=F&{aSlSeOhcR@<QsydV?ss2xV{7mRyjq4G%q*y
+zFJ7t*1K1Xk<E6E%1qd@PsD!73B!jN1#0q1Zis`l*n!3>UV72~7`1~*DJ0b74i0><x
+zvhufT>%5t}h<~r12_q})V#7$BipI(y8obH!Em)9f5Z(dOP`TJ2VZMRu8xdZ9hxc@C
+zeul6GBo+5Nf_8rBOcT0$3OPc)CQ)8rOABqzDB(3q;%uo_8xU*8FCELhwc~Sy>}zxV
+zQjf!TIyR;NgPacdKOGx$fpLnQtnWwj*Q1PGF!?-@O^qQ-Fk;w@4)_<d<nu%<g)D(3
+zzQAn-x+7-E=ZRPfSprK;?&r1R3xr#5Vf)@pP2u*zQ8+pQrA+mNjVjnD^Ezv@mD(dz
+zO)G$jI9i8NmRv*cw#PQhTb&%aS)NGZEQBe(eoBTTA-_{9QiPX+Tet|XP*N~h*5DA|
+zS0&LQ{H2p3d_qYDLcYu@9(*3%-~<UT!3Bw&1PH$ZlGVl9LynP<uTrv%ti9kE3I8-e
+zBWrvP9$6UB;kVS`JmHsBeH|fPG=Ahutd$%iAzieLto_b064FJ>$lANgm?v~?2u?bD
+z0oWv!$}9w2=16{Gvzh<amIq^yEPUzM@MO@u*J^x4<$8p*rvmF|;L{xSt&x%Zp(8P7
+zFFBHL_&^-WDocinzTrr|6mJ#ODofCApT*pJ2(Q=3<;(|9L6{D%T|wv3z3l;HKoWjV
+zNp*xpknBKUt;I0{1;swfk|$)dWmFJSq0L6toO<$YLVcF%c^gEge?lrW>a!)*ocds=
+z;UpO1o(%~OAwQ&QBjGzl!RfBqgbd}NM1FeBN?KcZFNGIs<Th&pUVl6V3+5Y=#Cy8c
+zAK_6T9hNK@wtDb_k*f#qwJ6!STrNmf4<3JBGJfRBGq2ct?6fgsCXD=8{&wDBds}Y5
+z+wL`cj9VlxKc|u_oc@OZ_j7Bl8Gx%C>0ZE*x`4?{1iZkJZUy|<k@m#dw-u$FWC*#z
+zOfCiZmd`&cSL5FSPtw_?k?*7Yo+GUT9I9h6OE^MF`CS2<l$0gx0ZFcRlbRBT+f$B_
+zkn^qFvmxZnGB{Z*vO{sZYo6Zr$}R)EOGz2R`;?R?d=R9;Nx!J`6Y?4m#%kBiB3!Jb
+z>^A{FaHJj4bv@df*{cEHbR=H;v})I7R{`=_lB};spi|D&e#$Nd{JA4N3Fuz5n>iT$
+z<Q5kBYe4!~do#Z^!hWKLKSOxB_R~TM&T`c5bc}>QQAX1#ucCIChC5RSxK>GL`~vW4
+zl)Fj~95!Z*3>$wW?J=%bhEb)y8HuRNP##7+OM4=}6p#=2<<3JjdZ1N%BEJZbtA62n
+z7o=mgbMkzG$#?Y%*I#jzkEnz+4?Xb%?VSAmfTLa5_XeD=r0n^Ce^yfM>wpJq%xejc
+z(3mfkn75&JwPPf7PbZcLBfr+YhxSA*_agHhhO!a;4zF{BR4M)&aX{iflK60qe=Xr`
+zkZ%2Nr&2QmFG}|M?<eA&jp$xx@*cnHt!486$nTsmeTT7!SD3oTo4K1_-{TteEZ`xU
+zJ+-xf-*cqr0D1i?0Xz+<a)TyR?IVCSnku!&0lG`)+Ur27c6l)zu)&e~0Dq{Y459lz
+zeB+Zi%AKh4;DeA`!X<?XFV!47S5oIb)c&bCmM45qNoOcT3fYNz7u3$yw96CrDJes^
+zL}h!#F5g)9j522ZWE_R9j7OoAB?lqDm@W$@LVo+)u0mMbZG_btx!$1qlU045uun;i
+zgx4!6M|iW68forFO3D-dTS<*$v8VHED5akWxy{oq_gHh@bKRyfqW9xeeU^|e%W{wK
+zeC4Vm{4z*`lZES&5^HRm+;$^$&1_&ZCujp2Y5}iyBto{rt}$7A+cAzn=eTAD%T9K9
+zvo@eWNdL?dkl6WJps&N#UV-s<+lC8-7lCVd(wo?|UWpEW3x|vy;^#tkzEO_tGwj4{
+zsAMo9+nh3}eG70j+RRRrI}L2qk2M@Qb^vV&mv19-V}lA(J?Wb#OC*75QxceFX*2TB
+zm5TWO!(qu%S)q^Lea8|hZ)tOC3E6FqnZ4(X*M`P}Gg<?BiXAMmU?;N2K3T*<MUA1N
+zMuvgi8wm#$G4+PX8cD)YV%>RKpn*rw2+1EpX5dIo*nZIwnh!37YcS|ipI9e62%BCd
+zAcRvvva>2{{PK1rv8aBoPP}=-Ta;8F+)gdl5$*_*{5Za+#0m}C>Cw+rzCiFsHIOBw
+zp+U*n;RCGqz`v`S92S1P)n_u}+IN6FY=g|6glxfp=FnigIon_{vJ1*xQSOe?w>}Tc
+zlKCk4MB^gVFGb1c5WYO`+IK<!5|rPlVDCfFc|9~1`u9cY>z@X~2`DotXQ8|W<quKb
+zkMcp3eo=|<S3V=^XTjfIl#5U<MY#gy7f||YxDq@a?VF8qPKEY93p%%Xa&zimEAS7-
+zQg9oT+oR-HJbZs1!tuvZ{to3UD1H6|usr-DO5U8Df%V;N%)Xr{E6E=P`I#t>Md|a;
+z2K`!;o6~;-_-;da2g-X;K7jIPC?7@1_W1Un!;+FO?yf?+hE!<ZVVGTyM9E(l%|X2t
+zWe-Z<-dmu*f$1bW(sFd8d>-XA?&$CoEQH)*lsBXNF3P)5K8Vs2Pc8(#lAO=KC#Ji}
+zD5s)445iOM68`UkavaKiQ2P7@jH8t-k@wu-y)Q11jzH<l-wL_sQBH^aN|bz*Og+AQ
+zHO9fGP;zrDHwF0oZz7-GM)@Af4^aC2>oIONqI?VG`zU?>hmm(rp!_XLzQ)<--xJ%l
+z4n%nf$|F(w{F6pm3SZ-SC+d82rO)qw#JLvyXQFIG$qy_0^8DQM3E(>g<>vJ8E6%>Y
+ziy-g&&rc-#{QNX;`!@E7|5bCJe+Bryfbs&A{BEz$e>;xfiIQK--H5u+&#%~Sy{$d6
+z4NAV*&*$d{HTeoEem#^Q<MjD^kcYRTT#J(P<o&2WgwmJi7hSeMevU@TFU9!${!8T(
+z<ST!h>Az0im)~);rR<B+f5n*3&-YF7jZX8nvmA?1`uybM8<R5NqnyuAJ*&XC8YSO@
+z<n!}2Kkw5%o&xceJU%~vggyoH*&!$ouQ0#yN8`Mw*o}FLxAA@bmH3ubIN$T({A)P=
+zQ}o}nC^w?y%K-czZu|E6tL>4<8$RUZueg2wXTkR(O5QsD2zCD_%)UJD`~L*z@wM=m
+z?eO{k4nF>7m_P631(nawACVk`{y709e?j8&^TEj}7+?OLbf5q0Al#1f0hB*S>F+@W
+zS&Jiqjz)Pr%A9fx1Ybh+LX;Py<R-j<+)2WH6o;Tahoj`a3ZI`_#QBu?D)i&MD0x17
+z26bPaH@6SPaXzj6Eb6DA<YQo8{t@*5EUdHqtA3xK7uc7B|0a~Y-uEw(efdvNA0!)e
+z6D&v4?1O~3ca%OTSsNLygOb6?BbX)!>e(VWe3vxE;z7xfWX0GReP}Z3(=qz6WcqF~
+z`tW4kJ~8@;WJ8p`WwK^+jDKXZHcH<r`NMTF{;iW&qx4TDH(@VNT53=-Dw%#?nqu*w
+zWSeBh^EJVNLCLns2~qm!3iL5aCd$8EGAl~oKA9b*?~tsE(sxYOycqLyrzF`Bqwky~
+zFURP+B(q<O(Z?pSzd=bP8H90AvTKZ8=#eBT^Vd}1A6J1sz5;#sfNoazgOfKu_79k=
+zimD`xzeG$%SD0^Rm>Bv-FApbzKI0$(slQ_dS0yf<#t-vnrq?R@q`03CON4IpukiF-
+zQ05Qw>f1t(wQFq!x=HUC|3ek%zY@Cfr)H)A`Qzo#bAk<hhH0Sub=x9&Q_7hB4}@;`
+z*PLn@e+K>`5|9}Gr-W|!FK@Pt+%0NuPZ|1(HcLMZdJY7AJ?Pw!dpzjt=2=GWp|1sf
+zcDtqD3O(k>*hc@Tvn*jD=;k&~RkCx!&(mzgY3wqg$Nc|V1^ODH50QBTXBjPTDbwAW
+zpU3a2py%oe^!tS_?}XNQV>bN%NtwP&!p&LK{}|}p-$lB4Mj30@a~0?&-sSjU-k1Tq
+zLXPVBYngvkvf^<tqIkDV567c99P?+8od1kne;ylErib(7PC`%QvmgHaZ}!m`J^s9B
+zZU<B);rw~3&~fEu6zZS3JsP7gFVkhVxx%teg~SCF_)8V&_f?=j4*hG-wTe%Kesfze
+z=8yTo`nHni{6Ok7tQWSB<!Ow6Yz6uO73k(QSTQ|wD$viVK)+b%HE2t^xJl@4w74Vp
+zm-UQH*3GcA&*9LcpkIEeCGf?KPm=#aOJ5BB4WO^ZJiImNua)Vjq>7J(9`ncCW;Jo{
+zX|l}wOMaWb-9WFw`n%tflYKy6GshA(f__+;j!LRH75te)ERlN%>niZKSD>E<J?qfk
+zBVgmg3jAw?J}NR^ZiJp0$n#0ib4LX|X8)0i&)Sk@{FLOS`Fn<XF0%F0ZIQfGLC?qJ
+zUtk&Emb&@dTIT6(<%e$m`fyB{Zh6xGn@u&byfwF<jh}0-wA@^_n$2xxI<AZO-TD^L
+z<>_Pj?-E=VoCEs0FIxHuwn)sUhK-)fao(ASJXu|)gDF**&D&*u^t)M?m_Kv7Cg#7n
+zogJe;3q3uZR(`TAl9xeW3wi-`bKZ;TG28ZHbn||-7~SkWGXAeW)G8i{em9qAhQ4m4
+zr6VnpdeGNgX6eh}kJ+^p)4#X^-E2WO`qv(76}*amF&l?tdcI#F-)@JV8B465Z@`~*
+zpwIT^VRP9U)Bg(iYc945_Cde@y8{2#a{D2sXM6?v)G~c!G8^+7AA=oJfxn>w-E6fn
+zaqEGC>1glr3jANIK>rT)VByw@emA=*js6YLzpvz(`THgLF`vvte120w|HcaR5wfr`
+z`qyK;n02c88(pSboc@15q1U7dz=uIkrppp;fd9u=&~qmE*L}_MbDcc50{@Z<^i|N4
+zOtE_SSnMj$*I#bw++dg)5zmwBD(JrpdPbpLldZbMY^N}BTXTUWd<gne74(>Q;u`+U
+zC6<x<px*)g@-Ko8J*QSUpAM06S<VNXh%ikg+m-1MP8FX4|624fuSlm=;5Yj^jQ({v
+z|C)8D`7^h33_a<v^=8mJD(E?1=%eKNZjpDr{G|%~*FgUaT!<jt$+tn@fca!kYd-lw
+z1wFs6KsTSQjLi?#74l)M(2f88x_9pi{D)ScpIm`HrviORnJ(i!Ya4nE;=B^{QQrJ%
+zKDB82WmKc(uamqnf95e{ti9{Ne>oNoyqx}31^#y{(EkiQ>!IhH)@<@l1^(gkShJkB
+zhg-%Ez(2Z7M<rF5_v{(|8jRnyICg~4Yf^lK=EZrj_O?RLik#)#66>En&_`kXu7si$
+z74(?5)y4FG7kbuQWEJrI`vB;Zur6wW{zoh5d9ech1EJSIHeHO7p=jc>9{SC^Z~pcM
+zeGSGh*S%B9bjy?e|0M9QyVg>7M!tOx^c9y{`lle&D)jMb1;B0P@fF_B{CowwS3!Tx
+zm#qSxcW$o0|6}m4#d&Zq*nP4B|LYa#=G_h^ZatU}cZHs<L0^mcCj)xY+}q#Rzo4yc
+zVza!={iI`RizlC$%NL7DOKWfI-1ffy*4|=&XR*1XyQ{TNI9j@kb33}{G<6hP`n!Ak
+zicJd^CC%NPJsqw6tt}I$O`Se9&Qxq`?`khL_4YO`F1B{{_byJ_dYd|1i!BQ}I~R*c
+zs#X-v{sF9W7PNP?^tPTYJ~nr>i+FpBz}BvX@_%1zS4&@O@50tzsq{7%dzzZ(7dyo9
+zq_4lXsi#K{Pi*e)>g(_6?e3X)VA8a(r>PyhZSAccEzLcPr3GDW?Q_f8`itE?{q5ad
+z#lGH!i8$SY`o#9W-lmC@#GZ0AE$Ft?sg|*`slR!i@u9t^simd2*wNkG)R7iw@9MV#
+z2f-qA_Z3@O+nN@1^d~Lt&Hds=drxsee|v|Z{?49x-F^LY7PKWOJ6gMvj&9>@XLncs
+zyuL(^O+0wYq$vjUwJ$Mvs(7(~XUkM!%FI0W*b`4ZUPAoY+L@;uS3K_2W2JX(R};7N
+zbr<I~b+vS~CdFgVICbVJCmtgl$Ddj#9(Mx7PB^w!NcmHap@QR2KJDn4Cl^oq>}PYw
+z<%{{5N1uG0Q7b`jZt5>K&znDE#_=bgc=R#F$rBHnI3;QClDKvCclS8*<cY@3Vpr=q
+zNniV1>7M4!roNPzIW7vjdU_>pZK2Ax-qzMYn+c%FwU&j_@g@bDoBCRtJ43U*txYXO
+z+wT%i>8SqpPETFaobKNKffkCz*52N(?sC_fEE#xIGNh}eyVE1~_jXB+MTovv#S`<V
+zNG5RHNwCeR%QwxDe(CFP>0aPDV=}F?M|_kKwa|o8(!!=+(d0^(j4xB2E0J$+N!t6G
+z`uhVnTH3ufh=3g;)F%By{WxGk*WQ)1HFx!Q3~ZJWUeG@;Ij6V1-wURA(bL`%uybf@
+zf;0_eDYmvW^*5Pjw6scZcFVjWb5WnCyrX?iuXN`r$4)Ku2tS)`Vv~sB^2k|i;!*4!
+zs9yAz$GDwAlJYENvPK5kKt_|<W@eGZF19tbr`kOwan?_inF}GeHqAU>2<2=uxhXl*
+zB$J<MkI7VVZlTN(QWZ|7qsiKNp`%UB&E-igJh;F#ZJ@uR(ImGSk4AeL%P=z0Fp1vX
+z*3#tVf*dhXm{X3^KxO4&-QPVw61{T6I-7dh+9gTF(A@6s7R-O9D&{BmcP8!K&3>ww
+zdAq-RpdBM1Wckm`=cXUJWHJeO?5LGfMr+xm8}bs#va2l%!tvgHPFHb`na=Ix+}hWd
+z7~cmf?`-W1=885Gn1O7jon}y#r+G2i-_chlnBI1rGRZe}$kgH}nDH=-gxhBQKrzE)
+zGQgi5#3%*(WWMYwCr$ZeCg;4~zH%sxuN__Dku;>UdtqxhX_gPkbQB&D{mt`Qo9CO!
+zxV5vVf3ckD2D)A>&XrS+83;1v6q9}#kg1gI?@kR0v{c-Yl$UA91U5Yf9*8qSPrpBh
+znr1eY2fT^9WUtArt}sz-cFQ^1c7_|`a>DIsZT4KZOma?dHo-PBI{eIeLh6#kliOQt
+zQgv47HyMCMIZrJz3zqi2?&d=dDfaa>H+8kSI87^ei;QJV$;ef+q>+4UUf9;_pC5#?
+zCFz_Wo_>r|Ev+3*17-`E!+XX0!pf(`@(3_zoJbe9MjBS;kFpnwbNc#hcPBmF9bWgE
+z!Q|SFtZfUMA^I2h$(d=OJ5$PWvgvD90PGPn8<*QC1f+YvoXdKX{$|Msb7Y`R$0mn`
+zNs@L`OzmAVxAZ4%-LftW6xkGTCk&G+ktt6MwYQZ|uEmoU7HhFeKBl9ouTPf9b34Nj
+zq@65}TRUZ$`O74Eck}#k0yiE?)B-2XJeEGY%POxZ^Ng&FySuuAyhk#`R%GSXMs%&=
+z&S!a9(Db!+_ja28G4pLXt))9;71ZtZgp>MgdzU?@p$(F+&5N4MxwWaIeTjFXlG#S$
+z9LzOh&$QG{)}o_-aZhV;j#+!Ts2r5aqw)zsT3l(tXaeoeX{Kvr#e!iiwa)o{vRFzc
+z_AT!0Z<-@zf3Gd)5p{L<w@#efwP0d-?XtgcmuvHy`sO7QTNZbTq%9?D%SYr~)+guv
+z0hOX0>y^Q61b}*E{XelhQA`v#ac;L%`&$>u{}Q=&Vd^d~g(kMn!`0F}naQ*!y!LRv
+z3|gzlUPD=N;<K7X#xNS|qO$C1Q)hd#c-P%;4BNxW#IhQ>wCj}XEupo}Suj_WG<D6D
+zBuBNqtIa5|hvv-bZC%J(hphLB&FBS_bR8iy@iO$kEzR=}b87&%V;ultf~Od_N0d5I
+z&^sT0+)a7zt75ql2XNa-pW9P`xgRdKFw{QxU$NW~Hx`UtqeE_omj8A{IYUZAr+x0z
+zV#(jNf<3|Q3s#d81j)-I)PL^hVtF(K=s)eSG|zWFO38EI7falpl4tPNNBU0(S_JTz
+zp>cm0OU9A*DbMzs`=CbtXd^6t+(*W8r3tS58Tp;$pD({iXr_ts*rfc&{bnq82Azem
+zmHz9KN?M-#(pav;eJ9F{0${n!ljr_5mgJ*6{b&74o;>%tv6L4h5BT%-ncMAY|M|R=
+zrQEg}@aMPxtB_|tyn3BwXSr^>0pc2eQm^skxxa$t#Z(Ld-~P>>Jon+TJlVS`>BsN;
+zkRJra+^;v|d27(;_v`lxo1syj`}$7!g!1b|c55Rq|IFY2R{k-OF;fKPxi2j93GF{C
+zvZntj&;5k6KB2r}OUrZL;cUpymgDKansi0*Yx2*GJ=*8~#C4G0V3f-r`<?M;9-lAA
+z()PKJam|ZmvGV+8k^P_YEdS-n>wd=#mVYB1vsKMs%KzJ!f4RnTzHE!xoLFo%!BNy?
+zP88>jE}G%<l-VXQ^2d43*4+HX`cRQK?Vm&fO3LH0pB^>5=8xql$XlxWe>LpS@WvnI
+z$hlhu`KMpE98Yc_r!9T?eJjX+`*F*8(YQ^^A5ua7fPYx|Z|t*adGkqC!|BKGmv+Nf
+za=SNwS*<R98ORT`k|awHuz@?`j{}cTp42ld$lo){X2c4)@1Fki<;~t9=1!XL8T@{r
+r-4pPt<+giWTvjt<SJ=k`l0Ai5EB~1H%u92Ah}mC<-<j;N8UOz;XHns_
+
+literal 0
+HcmV?d00001
+
+diff --git a/src/plugins/vbng/lib/log.c b/src/plugins/vbng/lib/log.c
+new file mode 100644
+index 00000000..09b01a2e
+--- /dev/null
++++ b/src/plugins/vbng/lib/log.c
+@@ -0,0 +1,57 @@
++/*
++ * $Id: log.c,v 1.5 2007/06/21 18:07:23 cparker Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++/*
++ * Function: rc_openlog
++ *
++ * Purpose: open log
++ *
++ * Arguments: identification string
++ *
++ * Returns: nothing
++ *
++ */
++
++void rc_openlog(char const *ident)
++{
++#ifndef _MSC_VER /* TODO: Fix me */
++      openlog(ident, LOG_PID, RC_LOG_FACILITY);
++#endif
++}
++
++/*
++ * Function: rc_log
++ *
++ * Purpose: log information
++ *
++ * Arguments: priority (just like syslog), rest like printf
++ *
++ * Returns: nothing
++ *
++ */
++
++void rc_log(int prio, char const *format, ...)
++{
++      char buff[1024];
++      va_list ap;
++
++      va_start(ap,format);
++    vsnprintf(buff, sizeof(buff), format, ap);
++    va_end(ap);
++
++#ifndef _MSC_VER /* TODO: Fix me */
++      syslog(prio, "%s", buff);
++#endif
++}
+diff --git a/src/plugins/vbng/lib/md5.c b/src/plugins/vbng/lib/md5.c
+new file mode 100644
+index 00000000..2344fb9c
+--- /dev/null
++++ b/src/plugins/vbng/lib/md5.c
+@@ -0,0 +1,251 @@
++#include "md5.h"
++
++/*    The below was retrieved from
++ *    http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.c?rev=1.1
++ *    with the following changes:
++ *    #includes commented out.
++ *    Support context->count as uint32_t[2] instead of uint64_t
++ *    u_int* to uint*
++ */
++
++/*
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest.        This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ *
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ */
++
++/*#include <sys/param.h>*/
++/*#include <sys/systm.h>*/
++/*#include <crypto/md5.h>*/
++
++#define PUT_64BIT_LE(cp, value) do {                          \
++      (cp)[7] = (value)[1] >> 24;                                     \
++      (cp)[6] = (value)[1] >> 16;                                     \
++      (cp)[5] = (value)[1] >> 8;                                      \
++      (cp)[4] = (value)[1];                                           \
++      (cp)[3] = (value)[0] >> 24;                                     \
++      (cp)[2] = (value)[0] >> 16;                                     \
++      (cp)[1] = (value)[0] >> 8;                                      \
++      (cp)[0] = (value)[0]; } while (0)
++
++#define PUT_32BIT_LE(cp, value) do {                                  \
++      (cp)[3] = (value) >> 24;                                        \
++      (cp)[2] = (value) >> 16;                                        \
++      (cp)[1] = (value) >> 8;                                         \
++      (cp)[0] = (value); } while (0)
++
++static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
++      0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/*
++ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void
++MD5Init(MD5_CTX *ctx)
++{
++      ctx->count[0] = 0;
++      ctx->count[1] = 0;
++      ctx->state[0] = 0x67452301;
++      ctx->state[1] = 0xefcdab89;
++      ctx->state[2] = 0x98badcfe;
++      ctx->state[3] = 0x10325476;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void
++MD5Update(MD5_CTX *ctx, uint8_t const *input, size_t len)
++{
++      size_t have, need;
++
++      /* Check how many bytes we already have and how many more we need. */
++      have = (size_t)((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
++      need = MD5_BLOCK_LENGTH - have;
++
++      /* Update bitcount */
++/*    ctx->count += (uint64_t)len << 3;*/
++      if ((ctx->count[0] += ((uint32_t)len << 3)) < (uint32_t)len) {
++      /* Overflowed ctx->count[0] */
++              ctx->count[1]++;
++      }
++      ctx->count[1] += ((uint32_t)len >> 29);
++
++
++
++      if (len >= need) {
++              if (have != 0) {
++                      memcpy(ctx->buffer + have, input, need);
++                      MD5Transform(ctx->state, ctx->buffer);
++                      input += need;
++                      len -= need;
++                      have = 0;
++              }
++
++              /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
++              while (len >= MD5_BLOCK_LENGTH) {
++                      MD5Transform(ctx->state, input);
++                      input += MD5_BLOCK_LENGTH;
++                      len -= MD5_BLOCK_LENGTH;
++              }
++      }
++
++      /* Handle any remaining bytes of data. */
++      if (len != 0)
++              memcpy(ctx->buffer + have, input, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void
++MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
++{
++      uint8_t count[8];
++      size_t padlen;
++      int i;
++
++      /* Convert count to 8 bytes in little endian order. */
++      PUT_64BIT_LE(count, ctx->count);
++
++      /* Pad out to 56 mod 64. */
++      padlen = MD5_BLOCK_LENGTH -
++          ((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
++      if (padlen < 1 + 8)
++              padlen += MD5_BLOCK_LENGTH;
++      MD5Update(ctx, PADDING, padlen - 8);            /* padlen - 8 <= 64 */
++      MD5Update(ctx, count, 8);
++
++      if (digest != NULL) {
++              for (i = 0; i < 4; i++)
++                      PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
++      }
++      memset(ctx, 0, sizeof(*ctx));   /* in case it's sensitive */
++}
++
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x & y | ~x & z) */
++#define F1(x, y, z) (z ^ (x & (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++      ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data.  MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++void
++MD5Transform(uint32_t state[4], uint8_t const block[MD5_BLOCK_LENGTH])
++{
++      uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
++
++      for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
++              in[a] = (uint32_t)(
++                  (uint32_t)(block[a * 4 + 0]) |
++                  (uint32_t)(block[a * 4 + 1]) <<  8 |
++                  (uint32_t)(block[a * 4 + 2]) << 16 |
++                  (uint32_t)(block[a * 4 + 3]) << 24);
++      }
++
++      a = state[0];
++      b = state[1];
++      c = state[2];
++      d = state[3];
++
++      MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
++      MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
++      MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
++      MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
++      MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
++      MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
++      MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
++      MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
++      MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
++      MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
++      MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
++      MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
++      MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
++      MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
++      MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
++      MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
++
++      MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
++      MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
++      MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
++      MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
++      MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
++      MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
++      MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
++      MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
++      MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
++      MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
++      MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
++      MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
++      MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
++      MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
++      MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
++      MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
++
++      MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
++      MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
++      MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
++      MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
++      MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
++      MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
++      MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
++      MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
++      MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
++      MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
++      MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
++      MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
++      MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
++      MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
++      MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
++      MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
++
++      MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
++      MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
++      MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
++      MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
++      MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
++      MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
++      MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
++      MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
++      MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
++      MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
++      MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
++      MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
++      MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
++      MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
++      MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
++      MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
++
++      state[0] += a;
++      state[1] += b;
++      state[2] += c;
++      state[3] += d;
++}
+diff --git a/src/plugins/vbng/lib/md5.h b/src/plugins/vbng/lib/md5.h
+new file mode 100644
+index 00000000..fcbaf91f
+--- /dev/null
++++ b/src/plugins/vbng/lib/md5.h
+@@ -0,0 +1,86 @@
++/*
++ * md5.h        Structures and prototypes for md5.
++ *
++ * Version:     $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $
++ * License:   BSD, but largely derived from a public domain source.
++ *
++ */
++
++#ifndef _RCRAD_MD5_H
++#define _RCRAD_MD5_H
++
++#include "config.h"
++
++#ifdef HAVE_NETTLE
++
++#include <nettle/md5-compat.h>
++
++#else
++
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#endif
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#ifdef HAVE_STDINT_H
++#include <stdint.h>
++#endif
++
++#include <string.h>
++/*
++ *  FreeRADIUS Client defines to ensure globally unique MD5 function names,
++ *  so that we don't pick up vendor-specific broken MD5 libraries.
++ */
++#define MD5_CTX               librad_MD5_CTX
++#define MD5Init               librad_MD5Init
++#define MD5Update     librad_MD5Update
++#define MD5Final      librad_MD5Final
++#define MD5Transform  librad_MD5Transform
++
++/*  The below was retrieved from
++ *  http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.h?rev=1.1
++ *  With the following changes: uint64_t => uint32_t[2]
++ *  Commented out #include <sys/cdefs.h>
++ *  Commented out the __BEGIN and __END _DECLS, and the __attributes.
++ */
++
++/*
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest.  This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ */
++
++#define       MD5_BLOCK_LENGTH                64
++#define       MD5_DIGEST_LENGTH               16
++
++typedef struct MD5Context {
++      uint32_t state[4];                      /* state */
++      uint32_t count[2];                      /* number of bits, mod 2^64 */
++      uint8_t buffer[MD5_BLOCK_LENGTH];       /* input buffer */
++} MD5_CTX;
++
++/* include <sys/cdefs.h> */
++
++/* __BEGIN_DECLS */
++void   MD5Init(MD5_CTX *);
++void   MD5Update(MD5_CTX *, uint8_t const *, size_t)
++/*            __attribute__((__bounded__(__string__,2,3)))*/;
++void   MD5Final(uint8_t [MD5_DIGEST_LENGTH], MD5_CTX *)
++/*            __attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH)))*/;
++void   MD5Transform(uint32_t [4], uint8_t const [MD5_BLOCK_LENGTH])
++/*            __attribute__((__bounded__(__minbytes__,1,4)))*/
++/*            __attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH)))*/;
++/* __END_DECLS */
++
++#endif /* HAVE_NETTLE */
++
++#endif /* _RCRAD_MD5_H */
+diff --git a/src/plugins/vbng/lib/options.h b/src/plugins/vbng/lib/options.h
+new file mode 100644
+index 00000000..05b66dfd
+--- /dev/null
++++ b/src/plugins/vbng/lib/options.h
+@@ -0,0 +1,57 @@
++/*
++ * $Id: options.h,v 1.6 2008/03/05 16:35:20 cparker Exp $
++ *
++ * Copyright (C) 1996 Lars Fenneberg
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#define OPTION_LEN    64
++
++/* ids for different option types */
++#define OT_STR                (1<<0)    /* string */
++#define OT_INT                (1<<1)    /* integer */
++#define OT_SRV                (1<<2)    /* server list */
++#define OT_AUO                (1<<3)    /* authentication order */
++
++#define OT_ANY                ((unsigned int)~0) /* used internally */
++
++/* status types */
++#define ST_UNDEF      (1<<0)    /* option is undefined */
++
++typedef struct _option {
++      char name[OPTION_LEN];    /* name of the option */
++      int type, status;         /* type and status    */
++      void *val;                /* pointer to option value */
++} OPTION;
++
++static OPTION config_options_default[] = {
++/* internally used options */
++{"config_file",               OT_STR, ST_UNDEF, NULL},
++/* General options */
++{"auth_order",                OT_AUO, ST_UNDEF, NULL},
++{"login_tries",               OT_INT, ST_UNDEF, NULL},
++{"login_timeout",     OT_INT, ST_UNDEF, NULL},
++{"nologin",           OT_STR, ST_UNDEF, NULL},
++{"issue",             OT_STR, ST_UNDEF, NULL},
++/* RADIUS specific options */
++{"authserver",                OT_SRV, ST_UNDEF, NULL},
++{"acctserver",                OT_SRV, ST_UNDEF, NULL},
++{"servers",           OT_STR, ST_UNDEF, NULL},
++{"dictionary",                OT_STR, ST_UNDEF, NULL},
++{"login_radius",      OT_STR, ST_UNDEF, NULL},
++{"seqfile",           OT_STR, ST_UNDEF, NULL},
++{"mapfile",           OT_STR, ST_UNDEF, NULL},
++{"default_realm",     OT_STR, ST_UNDEF, NULL},
++{"radius_timeout",    OT_INT, ST_UNDEF, NULL},
++{"radius_retries",    OT_INT, ST_UNDEF, NULL},
++{"radius_deadtime",   OT_INT, ST_UNDEF, NULL},
++{"bindaddr",          OT_STR, ST_UNDEF, NULL},
++/* local options */
++{"login_local",               OT_STR, ST_UNDEF, NULL},
++};
++
++#define       NUM_OPTIONS     ((sizeof(config_options_default))/(sizeof(config_options_default[0])))
+diff --git a/src/plugins/vbng/lib/rc-md5.c b/src/plugins/vbng/lib/rc-md5.c
+new file mode 100644
+index 00000000..be9fbcbd
+--- /dev/null
++++ b/src/plugins/vbng/lib/rc-md5.c
+@@ -0,0 +1,24 @@
++/* MD5 message-digest algorithm */
++
++/* This file is licensed under the BSD License, but is largely derived from
++ * public domain source code
++ */
++
++/*
++ *  FORCE MD5 TO USE OUR MD5 HEADER FILE!
++ *
++ *  If we don't do this, it might pick up the systems broken MD5.
++ *  - Alan DeKok <aland@ox.org>
++ */
++#include "rc-md5.h"
++
++void rc_md5_calc(unsigned char *output, unsigned char const *input,
++                   size_t inlen)
++{
++      MD5_CTX context;
++
++      MD5Init(&context);
++      MD5Update(&context, input, inlen);
++      MD5Final(output, &context);
++}
++
+diff --git a/src/plugins/vbng/lib/rc-md5.h b/src/plugins/vbng/lib/rc-md5.h
+new file mode 100644
+index 00000000..a30f16d3
+--- /dev/null
++++ b/src/plugins/vbng/lib/rc-md5.h
+@@ -0,0 +1,27 @@
++/*
++ * md5.h        Structures and prototypes for md5.
++ *
++ * Version:     $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $
++ * License:   BSD
++ *
++ */
++
++#ifndef _RC_MD5_H
++#define _RC_MD5_H
++
++#include "config.h"
++
++#ifdef HAVE_NETTLE
++
++#include <nettle/md5-compat.h>
++
++#else
++
++#include "md5.h"
++
++#endif /* HAVE_NETTLE */
++
++void rc_md5_calc(unsigned char *output, unsigned char const *input,
++                   size_t inputlen);
++
++#endif /* _RC_MD5_H */
+diff --git a/src/plugins/vbng/lib/sendserver.c b/src/plugins/vbng/lib/sendserver.c
+new file mode 100644
+index 00000000..bfdd9a26
+--- /dev/null
++++ b/src/plugins/vbng/lib/sendserver.c
+@@ -0,0 +1,631 @@
++/*
++ * $Id: sendserver.c,v 1.30 2010/06/15 09:22:52 aland Exp $
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <poll.h>
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++#include <pathnames.h>
++
++#define       SA(p)   ((struct sockaddr *)(p))
++
++static void rc_random_vector (unsigned char *);
++static int rc_check_reply (AUTH_HDR *, int, char const *, unsigned char const *, unsigned char);
++
++/*
++ * Function: rc_pack_list
++ *
++ * Purpose: Packs an attribute value pair list into a buffer.
++ *
++ * Returns: Number of octets packed.
++ *
++ */
++
++static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth)
++{
++      int             length, i, pc, padded_length;
++      int             total_length = 0;
++      size_t                  secretlen;
++      uint32_t           lvalue, vendor;
++      unsigned char   passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
++      unsigned char   md5buf[256];
++      unsigned char   *buf, *vector, *vsa_length_ptr;
++
++      buf = auth->data;
++
++      while (vp != NULL)
++      {
++              vsa_length_ptr = NULL;
++              if (VENDOR(vp->attribute) != 0) {
++                      *buf++ = PW_VENDOR_SPECIFIC;
++                      vsa_length_ptr = buf;
++                      *buf++ = 6;
++                      vendor = htonl(VENDOR(vp->attribute));
++                      memcpy(buf, &vendor, sizeof(uint32_t));
++                      buf += 4;
++                      total_length += 6;
++              }
++              *buf++ = (vp->attribute & 0xff);
++
++              switch (vp->attribute)
++              {
++               case PW_USER_PASSWORD:
++
++                /* Encrypt the password */
++
++                /* Chop off password at AUTH_PASS_LEN */
++                length = vp->lvalue;
++                if (length > AUTH_PASS_LEN)
++                      length = AUTH_PASS_LEN;
++
++                /* Calculate the padded length */
++                padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1);
++
++                /* Record the attribute length */
++                *buf++ = padded_length + 2;
++                if (vsa_length_ptr != NULL) *vsa_length_ptr += padded_length + 2;
++
++                /* Pad the password with zeros */
++                memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
++                memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
++
++                secretlen = strlen (secret);
++                vector = (unsigned char *)auth->vector;
++                for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN)
++                {
++                      /* Calculate the MD5 digest*/
++                      strcpy ((char *) md5buf, secret);
++                      memcpy ((char *) md5buf + secretlen, vector,
++                                AUTH_VECTOR_LEN);
++                      rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
++
++                      /* Remeber the start of the digest */
++                      vector = buf;
++
++                      /* Xor the password into the MD5 digest */
++                      for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
++                      {
++                              *buf++ ^= passbuf[pc];
++                      }
++                }
++
++                total_length += padded_length + 2;
++
++                break;
++#if 0
++               case PW_CHAP_PASSWORD:
++
++                *buf++ = CHAP_VALUE_LENGTH + 2;
++                if (vsa_length_ptr != NULL) *vsa_length_ptr += CHAP_VALUE_LENGTH + 2;
++
++                /* Encrypt the Password */
++                length = vp->lvalue;
++                if (length > CHAP_VALUE_LENGTH)
++                {
++                      length = CHAP_VALUE_LENGTH;
++                }
++                memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH);
++                memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
++
++                /* Calculate the MD5 Digest */
++                secretlen = strlen (secret);
++                strcpy ((char *) md5buf, secret);
++                memcpy ((char *) md5buf + secretlen, (char *) auth->vector,
++                        AUTH_VECTOR_LEN);
++                rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
++
++                /* Xor the password into the MD5 digest */
++                for (i = 0; i < CHAP_VALUE_LENGTH; i++)
++                {
++                      *buf++ ^= passbuf[i];
++                }
++                total_length += CHAP_VALUE_LENGTH + 2;
++
++                break;
++#endif
++               default:
++                switch (vp->type)
++                {
++                  case PW_TYPE_STRING:
++                      length = vp->lvalue;
++                      *buf++ = length + 2;
++                      if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
++                      memcpy (buf, vp->strvalue, (size_t) length);
++                      buf += length;
++                      total_length += length + 2;
++                      break;
++
++                  case PW_TYPE_IPV6ADDR:
++                      length = 16;
++                      if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
++                      memcpy (buf, vp->strvalue, (size_t) length);
++                      buf += length;
++                      total_length += length + 2;
++                      break;
++
++                  case PW_TYPE_IPV6PREFIX:
++                      length = vp->lvalue;
++                      if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
++                      memcpy (buf, vp->strvalue, (size_t) length);
++                      buf += length;
++                      total_length += length + 2;
++                      break;
++
++                  case PW_TYPE_INTEGER:
++                  case PW_TYPE_IPADDR:
++                  case PW_TYPE_DATE:
++                      *buf++ = sizeof (uint32_t) + 2;
++                      if (vsa_length_ptr != NULL) *vsa_length_ptr += sizeof(uint32_t) + 2;
++                      lvalue = htonl (vp->lvalue);
++                      memcpy (buf, (char *) &lvalue, sizeof (uint32_t));
++                      buf += sizeof (uint32_t);
++                      total_length += sizeof (uint32_t) + 2;
++                      break;
++
++                  default:
++                      break;
++                }
++                break;
++              }
++              vp = vp->next;
++      }
++      return total_length;
++}
++
++/* Function strappend
++ *
++ * Purpose: appends a string to the provided buffer
++ */
++static void strappend(char *dest, unsigned max_size, int *pos, const char *src)
++{
++      unsigned len = strlen(src) + 1;
++
++      if (*pos == -1)
++              return;
++
++      if (len + *pos > max_size) {
++              *pos = -1;
++              return;
++      }
++
++      memcpy(&dest[*pos], src, len);
++      *pos += len-1;
++      return;
++}
++
++/*
++ * Function: rc_send_server
++ *
++ * Purpose: send a request to a RADIUS server and wait for the reply
++ *
++ */
++
++int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg)
++{
++      int             sockfd;
++      struct sockaddr_in sinlocal;
++      struct sockaddr_in sinremote;
++      AUTH_HDR       *auth, *recv_auth;
++      uint32_t           auth_ipaddr, nas_ipaddr;
++      char           *server_name;    /* Name of server to query */
++      socklen_t       salen;
++      int             result = 0;
++      int             total_length;
++      int             length, pos;
++      int             retry_max;
++      size_t                  secretlen;
++      char            secret[MAX_SECRET_LENGTH + 1];
++      unsigned char   vector[AUTH_VECTOR_LEN];
++      char            recv_buffer[BUFFER_LEN];
++      char            send_buffer[BUFFER_LEN];
++      int             retries;
++      VALUE_PAIR      *vp;
++      struct pollfd   pfd;
++      double          start_time, timeout;
++
++      server_name = data->server;
++      if (server_name == NULL || server_name[0] == '\0')
++              return ERROR_RC;
++
++      if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \
++          (vp->lvalue == PW_ADMINISTRATIVE))
++      {
++              strcpy(secret, MGMT_POLL_SECRET);
++              if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0)
++                      return ERROR_RC;
++      }
++      else
++      {
++              if(data->secret != NULL)
++              {
++                      strncpy(secret, data->secret, MAX_SECRET_LENGTH);
++              }
++              /*
++              else
++              {
++              */
++              if (rc_find_server (rh, server_name, &auth_ipaddr, secret) != 0)
++              {
++                      rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name);
++                      return ERROR_RC;
++              }
++              /*}*/
++      }
++
++      DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name);
++
++      sockfd = socket (AF_INET, SOCK_DGRAM, 0);
++      if (sockfd < 0)
++      {
++              memset (secret, '\0', sizeof (secret));
++              rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno));
++              return ERROR_RC;
++      }
++
++      memset((char *)&sinlocal, '\0', sizeof(sinlocal));
++      sinlocal.sin_family = AF_INET;
++      sinlocal.sin_addr.s_addr = htonl(rc_own_bind_ipaddress(rh));
++      sinlocal.sin_port = htons((unsigned short) 0);
++      if (bind(sockfd, SA(&sinlocal), sizeof(sinlocal)) < 0)
++      {
++              close (sockfd);
++              memset (secret, '\0', sizeof (secret));
++              rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno));
++              return ERROR_RC;
++      }
++
++      retry_max = data->retries;      /* Max. numbers to try for reply */
++      retries = 0;                    /* Init retry cnt for blocking call */
++
++      memset ((char *)&sinremote, '\0', sizeof(sinremote));
++      sinremote.sin_family = AF_INET;
++      sinremote.sin_addr.s_addr = htonl (auth_ipaddr);
++      sinremote.sin_port = htons ((unsigned short) data->svc_port);
++
++      /*
++       * Fill in NAS-IP-Address (if needed)
++       */
++      if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL) {
++              if (sinlocal.sin_addr.s_addr == htonl(INADDR_ANY)) {
++                      if (rc_get_srcaddr(SA(&sinlocal), SA(&sinremote)) != 0) {
++                              close (sockfd);
++                              memset (secret, '\0', sizeof (secret));
++                              return ERROR_RC;
++                      }
++              }
++              nas_ipaddr = ntohl(sinlocal.sin_addr.s_addr);
++              rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS,
++                  &nas_ipaddr, 0, 0);
++      }
++
++      /* Build a request */
++      auth = (AUTH_HDR *) send_buffer;
++      auth->code = data->code;
++      auth->id = data->seq_nbr;
++
++      if (data->code == PW_ACCOUNTING_REQUEST)
++      {
++              total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
++
++              auth->length = htons ((unsigned short) total_length);
++
++              memset((char *) auth->vector, 0, AUTH_VECTOR_LEN);
++              secretlen = strlen (secret);
++              memcpy ((char *) auth + total_length, secret, secretlen);
++              rc_md5_calc (vector, (unsigned char *) auth, total_length + secretlen);
++              memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
++      }
++      else
++      {
++              rc_random_vector (vector);
++              memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
++
++              total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
++
++              auth->length = htons ((unsigned short) total_length);
++      }
++
++      DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n", 
++              inet_ntoa(sinlocal.sin_addr),
++              inet_ntoa(sinremote.sin_addr), data->svc_port);
++
++      for (;;)
++      {
++              sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0,
++                      SA(&sinremote), sizeof (struct sockaddr_in));
++
++              pfd.fd = sockfd;
++              pfd.events = POLLIN;
++              pfd.revents = 0;
++              start_time = rc_getctime();
++              for (timeout = data->timeout; timeout > 0;
++                  timeout -= rc_getctime() - start_time) {
++                      result = poll(&pfd, 1, timeout * 1000);
++                      if (result != -1 || errno != EINTR)
++                              break;
++              }
++              if (result == -1)
++              {
++                      rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno));
++                      memset (secret, '\0', sizeof (secret));
++                      close (sockfd);
++                      return ERROR_RC;
++              }
++              if (result == 1 && (pfd.revents & POLLIN) != 0)
++                      break;
++
++              /*
++               * Timed out waiting for response.  Retry "retry_max" times
++               * before giving up.  If retry_max = 0, don't retry at all.
++               */
++              if (retries++ >= retry_max)
++              {
++                      rc_log(LOG_ERR,
++                              "rc_send_server: no reply from RADIUS server %s:%u, %s",
++                               rc_ip_hostname (auth_ipaddr), data->svc_port, inet_ntoa(sinremote.sin_addr));
++                      close (sockfd);
++                      memset (secret, '\0', sizeof (secret));
++                      return TIMEOUT_RC;
++              }
++      }
++      salen = sizeof(sinremote);
++      length = recvfrom (sockfd, (char *) recv_buffer,
++                         (int) sizeof (recv_buffer),
++                         (int) 0, SA(&sinremote), &salen);
++
++      if (length <= 0)
++      {
++              rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\
++                       data->svc_port, strerror(errno));
++              close (sockfd);
++              memset (secret, '\0', sizeof (secret));
++              return ERROR_RC;
++      }
++
++      recv_auth = (AUTH_HDR *)recv_buffer;
++
++      if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) {
++              rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short",
++                  server_name, data->svc_port);
++              close(sockfd);
++              memset(secret, '\0', sizeof(secret));
++              return ERROR_RC;
++      }
++
++      result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr);
++
++      length = ntohs(recv_auth->length)  - AUTH_HDR_LEN;
++      if (length > 0) {
++              data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
++                  length, 0);
++      } else {
++              data->receive_pairs = NULL;
++      }
++
++      close (sockfd);
++      memset (secret, '\0', sizeof (secret));
++
++      if (result != OK_RC) return result;
++
++      if (msg) {
++              *msg = '\0';
++              pos = 0;
++              vp = data->receive_pairs;
++              while (vp)
++              {
++                      if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0)))
++                      {
++                              strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue);
++                              strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
++                              vp = vp->next;
++                      }
++              }
++      }
++
++      if ((recv_auth->code == PW_ACCESS_ACCEPT) ||
++              (recv_auth->code == PW_PASSWORD_ACK) ||
++              (recv_auth->code == PW_ACCOUNTING_RESPONSE))
++      {
++              result = OK_RC;
++      }
++      else if ((recv_auth->code == PW_ACCESS_REJECT) ||
++              (recv_auth->code == PW_PASSWORD_REJECT))
++      {
++              result = REJECT_RC;
++      }
++      else
++      {
++              result = BADRESP_RC;
++      }
++
++      return result;
++}
++
++/*
++ * Function: rc_check_reply
++ *
++ * Purpose: verify items in returned packet.
++ *
++ * Returns:   OK_RC       -- upon success,
++ *            BADRESP_RC  -- if anything looks funny.
++ *
++ */
++
++static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char const *secret, unsigned char const *vector, uint8_t seq_nbr)
++{
++      int             secretlen;
++      int             totallen;
++      unsigned char   calc_digest[AUTH_VECTOR_LEN];
++      unsigned char   reply_digest[AUTH_VECTOR_LEN];
++#ifdef DIGEST_DEBUG
++      uint8_t         *ptr;
++#endif
++
++      totallen = ntohs (auth->length);
++      secretlen = (int)strlen (secret);
++
++      /* Do sanity checks on packet length */
++      if ((totallen < 20) || (totallen > 4096))
++      {
++              rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length");
++              return BADRESP_RC;
++      }
++
++      /* Verify buffer space, should never trigger with current buffer size and check above */
++      if ((totallen + secretlen) > bufferlen)
++      {
++              rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response");
++              return BADRESP_RC;
++      }
++
++      /* Verify that id (seq. number) matches what we sent */
++      if (auth->id != seq_nbr)
++      {
++              rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response");
++              return BADRESP_RC;
++      }
++
++      /* Verify the reply digest */
++      memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN);
++      memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
++      memcpy ((char *) auth + totallen, secret, secretlen);
++#ifdef DIGEST_DEBUG
++        rc_log(LOG_ERR, "Calculating digest on:");
++        for (ptr = (u_char *)auth; ptr < ((u_char *)auth) + totallen + secretlen; ptr += 32) {
++                char buf[65];
++                int i;
++
++                buf[0] = '\0';
++                for (i = 0; i < 32; i++) {
++                        if (ptr + i >= ((u_char *)auth) + totallen + secretlen)
++                                break;
++                        sprintf(buf + i * 2, "%.2X", ptr[i]);
++                }
++                rc_log(LOG_ERR, "  %s", buf);
++        }
++#endif
++      rc_md5_calc (calc_digest, (unsigned char *) auth, totallen + secretlen);
++#ifdef DIGEST_DEBUG
++      rc_log(LOG_ERR, "Calculated digest is:");
++        for (ptr = (u_char *)calc_digest; ptr < ((u_char *)calc_digest) + 16; ptr += 32) {
++                char buf[65];
++                int i;
++
++                buf[0] = '\0';
++                for (i = 0; i < 32; i++) {
++                        if (ptr + i >= ((u_char *)calc_digest) + 16)
++                                break;
++                        sprintf(buf + i * 2, "%.2X", ptr[i]);
++                }
++                rc_log(LOG_ERR, "  %s", buf);
++        }
++      rc_log(LOG_ERR, "Reply digest is:");
++        for (ptr = (u_char *)reply_digest; ptr < ((u_char *)reply_digest) + 16; ptr += 32) {
++                char buf[65];
++                int i;
++
++                buf[0] = '\0';
++                for (i = 0; i < 32; i++) {
++                        if (ptr + i >= ((u_char *)reply_digest) + 16)
++                                break;
++                        sprintf(buf + i * 2, "%.2X", ptr[i]);
++                }
++                rc_log(LOG_ERR, "  %s", buf);
++        }
++#endif
++
++      if (memcmp ((char *) reply_digest, (char *) calc_digest,
++                  AUTH_VECTOR_LEN) != 0)
++      {
++#ifdef RADIUS_116
++              /* the original Livingston radiusd v1.16 seems to have
++                 a bug in digest calculation with accounting requests,
++                 authentication request are ok. i looked at the code
++                 but couldn't find any bugs. any help to get this
++                 kludge out are welcome. preferably i want to
++                 reproduce the calculation bug here to be compatible
++                 to stock Livingston radiusd v1.16.   -lf, 03/14/96
++               */
++              if (auth->code == PW_ACCOUNTING_RESPONSE)
++                      return OK_RC;
++#endif
++              rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server");
++              return BADRESP_RC;
++      }
++
++      return OK_RC;
++
++}
++
++/*
++ * Function: rc_random_vector
++ *
++ * Purpose: generates a random vector of AUTH_VECTOR_LEN octets.
++ *
++ * Returns: the vector (call by reference)
++ *
++ */
++
++static void rc_random_vector (unsigned char *vector)
++{
++      int             randno;
++      int             i;
++#if defined(HAVE_GETENTROPY)
++      if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) {
++              return;
++      } /* else fall through */
++#elif defined(HAVE_DEV_URANDOM)
++      int             fd;
++
++/* well, I added this to increase the security for user passwords.
++   we use /dev/urandom here, as /dev/random might block and we don't
++   need that much randomness. BTW, great idea, Ted!     -lf, 03/18/95 */
++
++      if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0)
++      {
++              unsigned char *pos;
++              int readcount;
++
++              i = AUTH_VECTOR_LEN;
++              pos = vector;
++              while (i > 0)
++              {
++                      readcount = read(fd, (char *)pos, i);
++                      if (readcount >= 0) {
++                              pos += readcount;
++                              i -= readcount;
++                      } else {
++                              if (errno != EINTR && errno != EAGAIN)
++                                      goto fallback;
++                      }
++              }
++
++              close(fd);
++              return;
++      } /* else fall through */
++#endif
++ fallback:
++      for (i = 0; i < AUTH_VECTOR_LEN;)
++      {
++              randno = random ();
++              memcpy ((char *) vector, (char *) &randno, sizeof (int));
++              vector += sizeof (int);
++              i += sizeof (int);
++      }
++
++      return;
++}
+diff --git a/src/plugins/vbng/lib/util.c b/src/plugins/vbng/lib/util.c
+new file mode 100644
+index 00000000..aa7c057d
+--- /dev/null
++++ b/src/plugins/vbng/lib/util.c
+@@ -0,0 +1,347 @@
++/*
++ * $Id: util.c,v 1.10 2010/02/04 10:31:41 aland Exp $
++ *
++ * Copyright (c) 1998 The NetBSD Foundation, Inc.
++ *
++ * Copyright (C) 1995,1996,1997 Lars Fenneberg
++ *
++ * Copyright 1992 Livingston Enterprises, Inc.
++ *
++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
++ * and Merit Network, Inc. All Rights Reserved
++ *
++ * See the file COPYRIGHT for the respective terms and conditions.
++ * If the file is missing contact me at lf@elemental.net
++ * and I'll send you a copy.
++ *
++ */
++
++#include <sys/time.h>
++
++#include <config.h>
++#include <includes.h>
++#include <freeradius-client.h>
++
++#define       RC_BUFSIZ       1024
++
++/*
++ * Function: rc_str2tm
++ *
++ * Purpose: Turns printable string into correct tm struct entries.
++ *
++ */
++
++static char const * months[] =
++              {
++                      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
++                      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
++              };
++
++void rc_str2tm (char const *valstr, struct tm *tm)
++{
++      int             i;
++
++      /* Get the month */
++      for (i = 0; i < 12; i++)
++      {
++              if (strncmp (months[i], valstr, 3) == 0)
++              {
++                      tm->tm_mon = i;
++                      i = 13;
++              }
++      }
++
++      /* Get the Day */
++      tm->tm_mday = atoi (&valstr[4]);
++
++      /* Now the year */
++      tm->tm_year = atoi (&valstr[7]) - 1900;
++}
++
++/*
++ * Function: rc_getifname
++ *
++ * Purpose: get the network interface name associated with this tty
++ *
++ */
++
++char *rc_getifname(rc_handle *rh, char const *tty)
++{
++#if defined(BSD4_4) || defined(linux)
++      int             fd;
++
++      if ((fd = open(tty, O_RDWR|O_NDELAY)) < 0) {
++              rc_log(LOG_ERR, "rc_getifname: can't open %s: %s", tty, strerror(errno));
++              return NULL;
++      }
++#endif
++
++#ifdef BSD4_4
++      strcpy(rh->ifname,ttyname(fd));
++      if (strlen(rh->ifname) < 1) {
++              rc_log(LOG_ERR, "rc_getifname: can't get attached interface of %s: %s", tty, strerror(errno));
++              close(fd);
++              return NULL;
++      }
++#elif linux
++      if (ioctl(fd, SIOCGIFNAME, rh->ifname) < 0) {
++              rc_log(LOG_ERR, "rc_getifname: can't ioctl %s: %s", tty, strerror(errno));
++              close(fd);
++              return NULL;
++      }
++#else
++      return NULL;
++#endif
++
++#if defined(BSD4_4) || defined(linux)
++      close(fd);
++      return rh->ifname;
++#endif
++}
++
++/*
++ * Function: rc_getstr
++ *
++ * Purpose: Reads in a string from the user (with or witout echo)
++ *
++ */
++#ifndef _MSC_VER
++char *rc_getstr (rc_handle *rh, char const *prompt, int do_echo)
++{
++      int             in, out;
++      char           *p;
++      struct termios  term_old, term_new;
++      int             is_term, flags, old_flags;
++      char            c;
++      int             flushed = 0;
++      sigset_t        newset;
++      sigset_t        oldset;
++
++      in = fileno(stdin);
++      out = fileno(stdout);
++
++      (void) sigemptyset (&newset);
++      (void) sigaddset (&newset, SIGINT);
++      (void) sigaddset (&newset, SIGTSTP);
++      (void) sigaddset (&newset, SIGQUIT);
++
++      (void) sigprocmask (SIG_BLOCK, &newset, &oldset);
++
++      if ((is_term = isatty(in)))
++      {
++
++              (void) tcgetattr (in, &term_old);
++              term_new = term_old;
++              if (do_echo)
++                      term_new.c_lflag |= ECHO;
++              else
++                      term_new.c_lflag &= ~ECHO;
++
++              if (tcsetattr (in, TCSAFLUSH, &term_new) == 0)
++                      flushed = 1;
++
++      }
++      else
++      {
++              is_term = 0;
++              if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
++                      old_flags = flags;
++                      flags |= O_NONBLOCK;
++
++                      fcntl(in, F_SETFL, flags);
++
++                      while (read(in, &c, 1) > 0)
++                              /* nothing */;
++
++                      fcntl(in, F_SETFL, old_flags);
++
++                      flushed = 1;
++              }
++      }
++
++      (void)write(out, prompt, strlen(prompt));
++
++      /* well, this looks ugly, but it handles the following end of line
++         markers: \r \r\0 \r\n \n \n\r, at least at a second pass */
++
++      p = rh->buf;
++      for (;;)
++      {
++              if (read(in, &c, 1) <= 0)
++                      return NULL;
++
++              if (!flushed && ((c == '\0') || (c == '\r') || (c == '\n'))) {
++                      flushed = 1;
++                      continue;
++              }
++
++              if ((c == '\r') || (c == '\n'))
++                      break;
++
++              flushed = 1;
++
++              if (p < rh->buf + GETSTR_LENGTH)
++              {
++                      if (do_echo && !is_term)
++                              (void)write(out, &c, 1);
++                      *p++ = c;
++              }
++      }
++
++      *p = '\0';
++
++      if (!do_echo || !is_term) (void)write(out, "\r\n", 2);
++
++      if (is_term)
++              tcsetattr (in, TCSAFLUSH, &term_old);
++      else {
++              if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
++                      old_flags = flags;
++                      flags |= O_NONBLOCK;
++
++                      fcntl(in, F_SETFL, flags);
++
++                      while (read(in, &c, 1) > 0)
++                              /* nothing */;
++
++                      fcntl(in, F_SETFL, old_flags);
++              }
++      }
++
++      (void) sigprocmask (SIG_SETMASK, &oldset, NULL);
++
++      return rh->buf;
++}
++#endif
++void rc_mdelay(int msecs)
++{
++      struct timeval tv;
++
++      tv.tv_sec = (int) msecs / 1000;
++      tv.tv_usec = (msecs % 1000) * 1000;
++
++      select(0, NULL, NULL, NULL, &tv);
++}
++
++/*
++ * Function: rc_mksid
++ *
++ * Purpose: generate a quite unique string
++ *
++ * Remarks: not that unique at all...
++ *
++ */
++
++char *
++rc_mksid (rc_handle *rh)
++{
++  snprintf (rh->buf1, sizeof(rh->buf1), "%08lX%04X", (unsigned long int) time (NULL), (unsigned int) getpid ());
++  return rh->buf1;
++}
++
++/*
++ * Function: rc_new
++ *
++ * Purpose: Initialises new Radius Client handle
++ *
++ */
++
++rc_handle *
++rc_new(void)
++{
++      rc_handle *rh;
++
++      rh = malloc(sizeof(*rh));
++      if (rh == NULL) {
++                rc_log(LOG_CRIT, "rc_new: out of memory");
++                return NULL;
++        }
++      memset(rh, 0, sizeof(*rh));
++      return rh;
++}
++
++/*
++ * Function: rc_destroy
++ *
++ * Purpose: Destroys Radius Client handle reclaiming all memory
++ *
++ */
++
++void
++rc_destroy(rc_handle *rh)
++{
++
++      rc_map2id_free(rh);
++      rc_dict_free(rh);
++      rc_config_free(rh);
++      if (rh->this_host_bind_ipaddr != NULL)
++              free(rh->this_host_bind_ipaddr);
++      free(rh);
++}
++
++/*
++ * Function: rc_fgetln
++ *
++ * Purpose: Get next line from the stream.
++ *
++ */
++
++char *
++rc_fgetln(FILE *fp, size_t *len)
++{
++      static char *buf = NULL;
++      static size_t bufsiz = 0;
++      char *ptr;
++
++      if (buf == NULL) {
++              bufsiz = RC_BUFSIZ;
++              if ((buf = malloc(bufsiz)) == NULL)
++                      return NULL;
++      }
++
++      if (fgets(buf, (int)bufsiz, fp) == NULL)
++              return NULL;
++      *len = 0;
++
++      while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
++              size_t nbufsiz = bufsiz + RC_BUFSIZ;
++              char *nbuf = realloc(buf, nbufsiz);
++
++              if (nbuf == NULL) {
++                      int oerrno = errno;
++                      free(buf);
++                      errno = oerrno;
++                      buf = NULL;
++                      return NULL;
++              } else
++                      buf = nbuf;
++
++              *len = bufsiz;
++              if (fgets(&buf[bufsiz], RC_BUFSIZ, fp) == NULL)
++                      return buf;
++
++              bufsiz = nbufsiz;
++      }
++
++      *len = (ptr - buf) + 1;
++      return buf;
++}
++
++/*
++ * Function: rc_getctime
++ *
++ * Purpose: Get current time (seconds since epoch) expressed as
++ * double-precision floating point number.
++ *
++ */
++
++double
++rc_getctime(void)
++{
++    struct timeval timev;
++
++    if (gettimeofday(&timev, NULL) == -1)
++        return -1;
++
++    return timev.tv_sec + ((double)timev.tv_usec) / 1000000.0;
++}
+diff --git a/src/plugins/vbng/vbng.api b/src/plugins/vbng/vbng.api
+new file mode 100644
+index 00000000..eba9a10f
+--- /dev/null
++++ b/src/plugins/vbng/vbng.api
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/** \brief vBNG DHCP config add / del request
++    @param client_index - opaque cookie to identify the sender
++    @param context - sender context, to match reply w/ request
++    @param rx_vrf_id - Rx/interface vrf id
++    @param server_vrf_id - server vrf id
++    @param is_add - add the config if non-zero, else delete
++    @param remote_addr[] - DHCP server address
++    @param local_addr[] - Local Address which could reach DHCP server
++*/
++define vbng_dhcp4_config
++{
++  u32 client_index;
++  u32 context;
++  u32 rx_vrf_id;
++  u32 server_vrf_id;
++  u8 is_add;
++  u8 remote_addr[16];
++  u8 local_addr[16];
++};
++
++/** \brief vBNG DHCP config response
++    @param context - sender context, to match reply w/ request
++    @param retval - return code for the request
++*/
++define vbng_dhcp4_config_reply
++{
++  u32 context;
++  i32 retval;
++};
++
++/*
++ * Local Variables:
++ * eval: (c-set-style "gnu")
++ * End:
++ */
+diff --git a/src/plugins/vbng/vbng_aaa.c b/src/plugins/vbng/vbng_aaa.c
+new file mode 100644
+index 00000000..5e8861f7
+--- /dev/null
++++ b/src/plugins/vbng/vbng_aaa.c
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <ctype.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <vbng/include/freeradius-client.h>
++#include <vbng/vbng_aaa.h>
++
++int
++process(void *rh, VALUE_PAIR *send, int nas_port)
++{
++    VALUE_PAIR *received = NULL;
++    char msg[PW_MAX_MSG_SIZE];
++    int retval;
++
++    retval = rc_auth(rh, nas_port, send, &received, msg);
++    if (retval == OK_RC && received != NULL) {
++        rc_avpair_free(received);
++    }
++
++    return retval;
++}
++
++int
++vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv)
++{
++    int i, nas_port = dm->config.nas_port;
++    char *rc_conf = (char *)dm->config.config_file;
++    VALUE_PAIR *send, **vp;
++    void *rh;
++
++    if ((rh = rc_read_config(rc_conf)) == NULL) {
++        fprintf(stderr, "error opening radius configuration file\n");
++        return (1);
++    }
++
++    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
++        fprintf(stderr, "error reading radius dictionary\n");
++        return (2);
++    }
++
++    send = NULL;
++    vp = &send;
++    for (i = 0; i < argc; i++) {
++        if (rc_avpair_parse(rh, argv[i], vp) < 0) {
++            fprintf(stderr, "%s: can't parse AV pair\n", argv[i]);
++            return (3);
++        }
++        vp = &send->next;
++    }
++
++    return process(rh, send, nas_port);
++}
++
+diff --git a/src/plugins/vbng/vbng_aaa.h b/src/plugins/vbng/vbng_aaa.h
+new file mode 100644
+index 00000000..411a7533
+--- /dev/null
++++ b/src/plugins/vbng/vbng_aaa.h
+@@ -0,0 +1,34 @@
++/*
++ * vbng_aaa.h - vBNG FreeRADIUS client commons.
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef _VBNG_AAA_H_
++#define _VBNG_AAA_H_
++
++#include <vbng/vbng_dhcp4.h>
++
++/* Common configuration for RADIUS client */
++#define AAA_DEFAULT_NAS_PORT  5060
++#define AAA_DEFAULT_CONFIG_FILE       "/etc/vpp/vbng-aaa.cfg"
++
++#define BUF_LEN               4096
++
++/* String template for the vAAA attributes */
++#define STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID "DHCP-Agent-Circuit-Id=%c"
++#define STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID "DHCP-Agent-Remote-Id=%c"
++
++int vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv);
++
++#endif /* _VBNG_AAA_H_ */
+diff --git a/src/plugins/vbng/vbng_all_api_h.h b/src/plugins/vbng/vbng_all_api_h.h
+new file mode 100644
+index 00000000..3f744275
+--- /dev/null
++++ b/src/plugins/vbng/vbng_all_api_h.h
+@@ -0,0 +1,18 @@
++/*
++ * vbng_all_api_h.h - skeleton vpp engine plug-in api #include file
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <vbng/vbng.api.h>
+diff --git a/src/plugins/vbng/vbng_api.c b/src/plugins/vbng/vbng_api.c
+new file mode 100644
+index 00000000..4080f775
+--- /dev/null
++++ b/src/plugins/vbng/vbng_api.c
+@@ -0,0 +1,123 @@
++/*
++ *------------------------------------------------------------------
++ * vbng_api.c - vbng api
++ *
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ *------------------------------------------------------------------
++ */
++
++#include <vnet/vnet.h>
++#include <vlibmemory/api.h>
++
++#include <vnet/interface.h>
++#include <vnet/api_errno.h>
++#include <vnet/dhcp/dhcp_proxy.h>
++#include <vnet/dhcp/client.h>
++#include <vnet/fib/fib_table.h>
++
++#include <vbng/vbng_msg_enum.h>
++
++#define vl_typedefs           /* define message structures */
++#include <vbng/vbng_all_api_h.h>
++#undef vl_typedefs
++
++#define vl_endianfun          /* define message structures */
++#include <vbng/vbng_all_api_h.h>
++#undef vl_endianfun
++
++/* instantiate all the print functions we know about */
++#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
++#define vl_printfun
++#include <vbng/vbng_all_api_h.h>
++#undef vl_printfun
++
++#include <vlibapi/api_helper_macros.h>
++
++#define foreach_vpe_api_msg                       \
++_(VBNG_DHCP4_CONFIG,vbng_dhcp4_config)
++
++static void vl_api_vbng_dhcp4_config_t_handler
++  (vl_api_vbng_dhcp4_config_t * mp)
++{
++  vl_api_vbng_dhcp4_config_reply_t *rmp;
++  ip46_address_t src, server;
++  int rv = -1;
++
++  ip46_address_reset (&src);
++  ip46_address_reset (&server);
++
++  clib_memcpy (&src.ip4, mp->local_addr, sizeof (src.ip4));
++  clib_memcpy (&server.ip4, mp->remote_addr, sizeof (server.ip4));
++
++  rv = dhcp4_proxy_set_server (&server,
++                 &src,
++                                 (u32) ntohl (mp->rx_vrf_id),
++                                 (u32) ntohl (mp->server_vrf_id),
++                                 (int) (mp->is_add == 0));
++
++
++  REPLY_MACRO (VL_API_VBNG_DHCP4_CONFIG_REPLY);
++}
++
++/*
++ * vbng_api_hookup
++ * Add vpe's API message handlers to the table.
++ * vlib has alread mapped shared memory and
++ * added the client registration handlers.
++ * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
++ */
++#define vl_msg_name_crc_list
++#include <vbng/vbng_all_api_h.h>
++#undef vl_msg_name_crc_list
++
++static void
++setup_message_id_table (api_main_t * am)
++{
++#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
++  foreach_vl_msg_name_crc_vbng;
++#undef _
++}
++
++static clib_error_t *
++vbng_api_hookup (vlib_main_t * vm)
++{
++  api_main_t *am = &api_main;
++
++#define _(N,n)                                                  \
++    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
++                           vl_api_##n##_t_handler,              \
++                           vl_noop_handler,                     \
++                           vl_api_##n##_t_endian,               \
++                           vl_api_##n##_t_print,                \
++                           sizeof(vl_api_##n##_t), 1);
++  foreach_vpe_api_msg;
++#undef _
++
++  /*
++   * Set up the (msg_name, crc, message-id) table
++   */
++  setup_message_id_table (am);
++
++  return 0;
++}
++
++VLIB_API_INIT_FUNCTION (vbng_api_hookup);
++
++/*
++ * fd.io coding-style-patch-verification: ON
++ *
++ * Local Variables:
++ * eval: (c-set-style "gnu")
++ * End:
++ */
+diff --git a/src/plugins/vbng/vbng_dhcp4.c b/src/plugins/vbng/vbng_dhcp4.c
+new file mode 100644
+index 00000000..ed79df42
+--- /dev/null
++++ b/src/plugins/vbng/vbng_dhcp4.c
+@@ -0,0 +1,160 @@
++/*
++ * vbng_dhcp4.c: common dhcp v4 processing
++ *
++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <vnet/fib/fib_table.h>
++#include <vnet/mfib/mfib_table.h>
++
++#include <vbng/vbng_dhcp4.h>
++
++/**
++ * @brief Shard 4/6 instance of DHCP main
++ */
++vbng_dhcp4_main_t vbng_dhcp4_main;
++
++void
++vbng_dhcp4_walk (vbng_dhcp4_walk_fn_t fn,
++                 void *ctx)
++{
++  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
++  dhcp_proxy_t * server;
++  u32 server_index, i;
++
++  vec_foreach_index (i, vdm->dhcp_server_index_by_rx_fib_index)
++  {
++      server_index = vdm->dhcp_server_index_by_rx_fib_index[i];
++      if (~0 == server_index)
++          continue;
++
++      server = pool_elt_at_index (vdm->dhcp4_servers, server_index);
++
++      if (!fn(server, ctx))
++          break;
++    }
++}
++
++static u32
++dhcp_proxy_server_find (dhcp_proxy_t *proxy,
++                        fib_protocol_t proto,
++                        ip46_address_t *addr,
++                        u32 server_table_id)
++{
++    dhcp_server_t *server;
++    u32 ii, fib_index;
++
++    vec_foreach_index(ii, proxy->dhcp_servers)
++    {
++        server = &proxy->dhcp_servers[ii];
++        fib_index = fib_table_find(proto, server_table_id);
++
++        if (ip46_address_is_equal(&server->dhcp_server,
++                                  addr) &&
++            (server->server_fib_index == fib_index))
++        {
++            return (ii);
++        }
++    }
++    return (~0);
++}
++
++int
++vbng_dhcp4_server_del (fib_protocol_t proto,
++                       u32 rx_fib_index,
++                       ip46_address_t *addr,
++                       u32 server_table_id)
++{
++  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
++  dhcp_proxy_t *proxy = 0;
++
++  proxy = vbng_dhcp4_get_server(vdm, rx_fib_index);
++
++  if (NULL != proxy)
++  {
++      dhcp_server_t *server;
++      u32 index;
++
++      index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id);
++
++      if (~0 != index)
++      {
++          server = &proxy->dhcp_servers[index];
++          fib_table_unlock (server->server_fib_index, proto);
++
++          vec_del1(proxy->dhcp_servers, index);
++
++          if (0 == vec_len(proxy->dhcp_servers))
++          {
++              /* no servers left, delete the proxy config */
++              vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0;
++              vec_free(proxy->dhcp_servers);
++              pool_put (vdm->dhcp4_servers, proxy);
++              return (1);
++          }
++      }
++  }
++
++  /* the proxy still exists */
++  return (0);
++}
++
++int
++vbng_dhcp4_server_add (fib_protocol_t proto,
++                       ip46_address_t *addr,
++                       ip46_address_t *src_address,
++                       u32 rx_fib_index,
++                       u32 server_table_id)
++{
++  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
++  dhcp_proxy_t * proxy = 0;
++  int new = 0;
++
++  proxy = vbng_dhcp4_get_server(vdm, rx_fib_index);
++
++  if (NULL == proxy)
++  {
++      vec_validate_init_empty(vdm->dhcp_server_index_by_rx_fib_index,
++                              rx_fib_index,
++                              ~0);
++
++      pool_get (vdm->dhcp4_servers, proxy);
++      memset (proxy, 0, sizeof (*proxy));
++      new = 1;
++
++      vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] =
++          proxy - vdm->dhcp4_servers;
++
++      proxy->dhcp_src_address = *src_address;
++      proxy->rx_fib_index = rx_fib_index;
++  }
++  else
++  {
++      if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id))
++      {
++          return (new);
++      }
++  }
++
++  dhcp_server_t server = {
++      .dhcp_server = *addr,
++      .server_fib_index = fib_table_find_or_create_and_lock(proto,
++                                                            server_table_id),
++  };
++
++  vec_add1(proxy->dhcp_servers, server);
++
++  return (new);
++}
++
+diff --git a/src/plugins/vbng/vbng_dhcp4.h b/src/plugins/vbng/vbng_dhcp4.h
+new file mode 100644
+index 00000000..2f41575f
+--- /dev/null
++++ b/src/plugins/vbng/vbng_dhcp4.h
+@@ -0,0 +1,139 @@
++/*
++ * vbng_dhcp4.h: DHCP v4 common functions/types
++ *
++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef _VBNG_DHCP4_H_
++#define _VBNG_DHCP4_H_
++
++#include <vnet/vnet.h>
++#include <vnet/dhcp/dhcp_proxy.h>
++#include <vnet/dhcp/dhcp4_packet.h>
++#include <vnet/ethernet/ethernet.h>
++#include <vnet/ip/ip.h>
++#include <vnet/ip/ip4.h>
++#include <vnet/ip/ip4_packet.h>
++#include <vnet/pg/pg.h>
++#include <vnet/ip/format.h>
++#include <vnet/udp/udp.h>
++
++typedef enum {
++#define vbng_dhcp4_error(n,s) VBNG_DHCP4_ERROR_##n,
++#include <vbng/vbng_dhcp4_err.def>
++#undef vbng_dhcp4_error
++  VBNG_DHCP4_N_ERROR,
++} vbng_dhcp4_error_t;
++
++#define VBNG_AAA_DISABLED     0
++#define VBNG_AAA_ENABLED      1
++
++typedef struct {
++  int is_enabled;
++  u32 nas_port; /* AAA server port */
++  u8 *config_file; /* Radius Client config file path */
++} vbng_aaa_config_t;
++
++/**
++ * @brief Global configuration for the vBNG plugin.
++ */
++typedef struct {
++  /* Pool of DHCP servers */
++  dhcp_proxy_t *dhcp4_servers;
++
++  /* Pool of selected DHCP server. Zero is the default server */
++  u32 * dhcp_server_index_by_rx_fib_index;
++
++  /* to drop pkts in server-to-client direction */
++  u32 error_drop_node_index;
++
++  /* Configuration for the AAA client */
++  vbng_aaa_config_t config;
++
++  /* convenience */
++  vlib_main_t * vlib_main;
++  vnet_main_t * vnet_main;
++} vbng_dhcp4_main_t;
++
++extern vbng_dhcp4_main_t vbng_dhcp4_main;
++
++/**
++ * @brief Add a new DHCP proxy server configuration.
++ * @return 1 is the config is new,
++ *         0 otherwise (implying a modify of an existing)
++ */
++int vbng_dhcp4_server_add(fib_protocol_t proto,
++                          ip46_address_t *addr,
++                          ip46_address_t *src_address,
++                          u32 rx_fib_iindex,
++                          u32 server_table_id);
++
++/**
++ * @brief Delete a DHCP proxy config
++ * @return 1 if the proxy is deleted, 0 otherwise
++ */
++int vbng_dhcp4_server_del(fib_protocol_t proto,
++                          u32 rx_fib_index,
++                          ip46_address_t *addr,
++                          u32 server_table_id);
++
++u32
++dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto,
++                                  u32 fib_index);
++
++/**
++ * @brief Callback function invoked for each DHCP proxy entry
++ *  return 0 to break the walk, non-zero otherwise.
++ */
++typedef int (*vbng_dhcp4_walk_fn_t)(dhcp_proxy_t *server,
++                                    void *ctx);
++
++/**
++ * @brief Walk/Visit each vBNG DHCP server configurations
++ */
++void vbng_dhcp4_walk(vbng_dhcp4_walk_fn_t fn,
++                     void *ctx);
++
++/**
++ * @brief Get the DHCP proxy server data for the FIB index
++ */
++static inline dhcp_proxy_t *
++vbng_dhcp4_get_server(vbng_dhcp4_main_t *vm,
++                    u32 rx_fib_index)
++{
++      dhcp_proxy_t *s = NULL;
++
++      if (vec_len(vm->dhcp_server_index_by_rx_fib_index) > rx_fib_index &&
++          vm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0)
++      {
++              s = pool_elt_at_index (
++                  vm->dhcp4_servers,
++                  vm->dhcp_server_index_by_rx_fib_index[rx_fib_index]);
++      }
++
++      return (s);
++}
++
++int vbng_dhcp4_set_server(ip46_address_t *addr,
++                          ip46_address_t *src_addr,
++                          u32 rx_table_id,
++                          u32 server_table_id,
++                          int is_del);
++
++#define DHCP_PACKET_OPTION_82         82
++#define DHCP_PACKET_OPTION82_SUB1     1
++#define DHCP_PACKET_OPTION82_SUB2     2
++#define DHCP_PACKET_OPTION82_SUB5     5
++
++#endif /* _VBNG_DHCP4_H_ */
+diff --git a/src/plugins/vbng/vbng_dhcp4_err.def b/src/plugins/vbng/vbng_dhcp4_err.def
+new file mode 100644
+index 00000000..23f2d0d2
+--- /dev/null
++++ b/src/plugins/vbng/vbng_dhcp4_err.def
+@@ -0,0 +1,29 @@
++/*
++ * vbng_dhcp4_err.def: VBNG DHCP4 Errors
++ *
++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++vbng_dhcp4_error (NONE, "no error")
++vbng_dhcp4_error (NO_SERVER, "no dhcp server configured")
++vbng_dhcp4_error (RELAY_TO_SERVER, "DHCP packets relayed to the server")
++vbng_dhcp4_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients")
++vbng_dhcp4_error (NO_INTERFACE_ADDRESS, "DHCP no interface address")
++vbng_dhcp4_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields")
++vbng_dhcp4_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.")
++vbng_dhcp4_error (PKT_TOO_BIG, "DHCP packets which are too big.")
++vbng_dhcp4_error (AAA_FAILURE, "DHCP packets failed to pass the AAA check.")
++vbng_dhcp4_error (NO_OPTION_82, "DHCP option 82 missing")
++vbng_dhcp4_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value")
++vbng_dhcp4_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value")
+diff --git a/src/plugins/vbng/vbng_dhcp4_node.c b/src/plugins/vbng/vbng_dhcp4_node.c
+new file mode 100644
+index 00000000..205959bf
+--- /dev/null
++++ b/src/plugins/vbng/vbng_dhcp4_node.c
+@@ -0,0 +1,1024 @@
++/*
++ * proxy_node.c: dhcp proxy node processing
++ *
++ * Copyright (c) 2013 Cisco and/or its affiliates and others.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <vlib/vlib.h>
++#include <vnet/pg/pg.h>
++#include <vnet/fib/ip4_fib.h>
++#include <vnet/dhcp/client.h>
++#include <vnet/plugin/plugin.h>
++#include <vpp/app/version.h>
++
++#include <vbng/vbng_dhcp4.h>
++#include <vbng/vbng_aaa.h>
++
++static char * vbng_dhcp4_error_strings[] = {
++#define vbng_dhcp4_error(n,s) s,
++#include <vbng/vbng_dhcp4_err.def>
++#undef vbng_dhcp4_error
++};
++
++#define foreach_vbng_dhcp4_to_server_input_next \
++  _ (DROP, "error-drop")                      \
++  _ (LOOKUP, "ip4-lookup")                    \
++  _ (SEND_TO_CLIENT, "vbng-dhcp-to-client")
++
++typedef enum {
++#define _(s,n) VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s,
++  foreach_vbng_dhcp4_to_server_input_next
++#undef _
++  VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT,
++} vbng_dhcp4_to_server_input_next_t;
++
++typedef struct {
++  /* 0 => to server, 1 => to client */
++  int which;
++  ip4_address_t trace_ip4_address;
++  u32 error;
++  u32 sw_if_index;
++  u32 original_sw_if_index;
++} dhcp_proxy_trace_t;
++
++#define VPP_DHCP_OPTION82_SUB1_SIZE   6
++#define VPP_DHCP_OPTION82_SUB5_SIZE   6
++#define VPP_DHCP_OPTION82_VSS_SIZE    12
++#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \
++                                VPP_DHCP_OPTION82_SUB5_SIZE + \
++                                VPP_DHCP_OPTION82_VSS_SIZE +3)
++
++static vlib_node_registration_t vbng_dhcp4_to_server_node;
++static vlib_node_registration_t vbng_dhcp4_to_client_node;
++
++static u8 *
++format_dhcp_proxy_trace (u8 * s, va_list * args)
++{
++  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
++  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
++  dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *);
++ 
++  if (t->which == 0)
++    s = format (s, "DHCP proxy: sent to server %U\n",
++                format_ip4_address, &t->trace_ip4_address, t->error);
++  else
++    s = format (s, "DHCP proxy: broadcast to client from %U\n",
++                format_ip4_address, &t->trace_ip4_address);
++
++  if (t->error != (u32)~0)
++    s = format (s, "  error: %s\n", vbng_dhcp4_error_strings[t->error]);
++
++  s = format (s, "  original_sw_if_index: %d, sw_if_index: %d\n",
++              t->original_sw_if_index, t->sw_if_index);
++  
++  return s;
++}
++
++static u8 *
++format_dhcp_proxy_header_with_length (u8 * s, va_list * args)
++{
++  dhcp_header_t * h = va_arg (*args, dhcp_header_t *);
++  u32 max_header_bytes = va_arg (*args, u32);
++  u32 header_bytes;
++
++  header_bytes = sizeof (h[0]);
++  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
++    return format (s, "dhcp header truncated");
++
++  s = format (s, "DHCP Proxy");
++
++  return s;
++}
++
++static uword
++vbng_dhcp_to_server_input (vlib_main_t * vm,
++                           vlib_node_runtime_t * node,
++                           vlib_frame_t * from_frame)
++{
++  u32 n_left_from, next_index, * from, * to_next;
++  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
++  from = vlib_frame_vector_args (from_frame);
++  n_left_from = from_frame->n_vectors;
++  u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0;
++  u32 pkts_no_interface_address=0;
++  u32 pkts_too_big=0, pkts_aaa_fail = 0;
++  ip4_main_t * im = &ip4_main;
++
++  next_index = node->cached_next_index;
++
++  while (n_left_from > 0)
++    {
++      u32 n_left_to_next;
++
++      vlib_get_next_frame (vm, node, next_index,
++                         to_next, n_left_to_next);
++
++      while (n_left_from > 0 && n_left_to_next > 0)
++      {
++        u32 bi0;
++        vlib_buffer_t * b0;
++          udp_header_t * u0;
++        dhcp_header_t * h0;
++          ip4_header_t * ip0;
++        u32 next0;
++          u32 old0, new0;
++          ip_csum_t sum0;
++          u32 error0 = (u32) ~0;
++          u32 sw_if_index = 0;
++          u32 original_sw_if_index = 0;
++          u8  *end = NULL;
++          u32 fib_index;
++          dhcp_proxy_t *proxy;
++          dhcp_server_t *server;
++          u32 rx_sw_if_index;
++          dhcp_option_t *o;
++          u32 len = 0;
++          vlib_buffer_free_list_t *fl;
++          u8 is_discover = 0;
++
++        bi0 = from[0];
++        from += 1;
++        n_left_from -= 1;
++
++        b0 = vlib_get_buffer (vm, bi0);
++
++          h0 = vlib_buffer_get_current (b0);
++
++          /* 
++           * udp_local hands us the DHCP header, need udp hdr, 
++           * ip hdr to relay to server
++           */
++          vlib_buffer_advance (b0, -(sizeof(*u0)));
++        u0 = vlib_buffer_get_current (b0);
++
++          /* This blows. Return traffic has src_port = 67, dst_port = 67 */
++          if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server))
++            {
++              vlib_buffer_advance (b0, sizeof(*u0));
++              next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
++              error0 = 0;
++              pkts_to_client++;
++              goto do_enqueue;
++            }
++
++          rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
++
++          fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index];
++          proxy = vbng_dhcp4_get_server(dm, fib_index);
++
++          if (PREDICT_FALSE (NULL == proxy))
++            {
++              error0 = VBNG_DHCP4_ERROR_NO_SERVER;
++              next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
++              pkts_no_server++;
++              goto do_trace;
++            }
++
++          server = &proxy->dhcp_servers[0];
++          vlib_buffer_advance (b0, -(sizeof(*ip0)));
++          ip0 = vlib_buffer_get_current (b0);
++
++          /* disable UDP checksum */
++          u0->checksum = 0;
++          sum0 = ip0->checksum;
++          old0 = ip0->dst_address.as_u32;
++          new0 = server->dhcp_server.ip4.as_u32;
++          ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
++          sum0 = ip_csum_update (sum0, old0, new0, 
++                                ip4_header_t /* structure */, 
++                                dst_address /* changed member */);
++          ip0->checksum = ip_csum_fold (sum0);
++
++          sum0 = ip0->checksum;
++          old0 = ip0->src_address.as_u32;
++          new0 = proxy->dhcp_src_address.ip4.as_u32;
++          ip0->src_address.as_u32 = new0;
++          sum0 = ip_csum_update (sum0, old0, new0, 
++                                ip4_header_t /* structure */, 
++                                src_address /* changed member */);
++          ip0->checksum = ip_csum_fold (sum0);
++
++          /* Send to DHCP server via the configured FIB */
++          vnet_buffer(b0)->sw_if_index[VLIB_TX] =
++            server->server_fib_index;
++
++          h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32;
++          pkts_to_server++;
++
++          o = (dhcp_option_t *) h0->options;
++              
++          fib_index = im->fib_index_by_sw_if_index 
++              [vnet_buffer(b0)->sw_if_index[VLIB_RX]];
++
++          end = b0->data + b0->current_data + b0->current_length;
++          /* TLVs are not performance-friendly... */
++          while  (o->option != 0xFF /* end of options */ && (u8 *)o < end) 
++            {
++              if (DHCP_PACKET_OPTION_MSG_TYPE == o->option)
++                {
++                  if (DHCP_PACKET_DISCOVER == o->data[0])
++                    {
++                      is_discover = 1;
++                    }
++                }
++
++            if (DHCP_PACKET_OPTION_82 == o->option) {
++                /* For Demo purpose only */
++                if (dm->config.is_enabled) {
++                  int i = 0, num_kvs = 0, retval = 0;
++                  char *kv_pairs[1];
++                  char key_string[32];
++
++                  if (DHCP_PACKET_OPTION82_SUB1 == o->data[0]) {
++                      sprintf(key_string,  STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID, o->data[2]);
++                      for (i = 1; i < o->data[1]; i++) {
++                          sprintf(key_string, "%s%c", key_string, o->data[2 + i]);
++                      }
++                  }
++
++                  if (DHCP_PACKET_OPTION82_SUB2 == o->data[0]) {
++                      sprintf(key_string, STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID, o->data[2]);
++                      for (i = 1; i < o->data[1]; i++) {
++                          sprintf(key_string, "%s%c", key_string, o->data[2 + i]);
++                      }
++                  }
++
++                  kv_pairs[num_kvs] = key_string;
++                  num_kvs++;
++
++                retval = vbng_auth(dm, num_kvs, kv_pairs);
++                if (retval) {
++                    if (retval == 1 /* TIMEOUT_RC */) {
++                        dm->config.is_enabled = VBNG_AAA_DISABLED;
++                    }
++                    error0 = VBNG_DHCP4_ERROR_AAA_FAILURE;
++                    next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
++                    pkts_aaa_fail++;
++                    goto do_trace;
++                }
++              }
++
++                fl = vlib_buffer_get_free_list (vm, b0->free_list_index);
++                if (((u8 *)o - (u8 *)b0->data + (VPP_DHCP_OPTION82_SUB1_SIZE + VPP_DHCP_OPTION82_SUB5_SIZE))
++                    > fl->n_data_bytes)
++                {
++                    next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
++                    pkts_too_big++;
++                    goto do_trace;
++                }
++
++                /* Begin to appending new sub-options */
++                {
++                    vnet_main_t *vnm = vnet_get_main();   
++                    u16 old_l0, new_l0, orig_len = 0;
++                    ip4_address_t _ia0, * ia0 = &_ia0;
++                    vnet_sw_interface_t *swif;
++                    sw_if_index = 0;
++                    original_sw_if_index = 0;
++                        
++                    original_sw_if_index = sw_if_index = 
++                        vnet_buffer(b0)->sw_if_index[VLIB_RX];
++                    swif = vnet_get_sw_interface (vnm, sw_if_index);
++                    if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
++                        sw_if_index = swif->unnumbered_sw_if_index;
++                        
++                    /* 
++                     * Get the first ip4 address on the [client-side] 
++                     * RX interface, if not unnumbered. otherwise use
++                     * the loopback interface's ip address.
++                     */
++                    ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0);
++                        
++                    if (ia0 == 0)
++                    {
++                        error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS;
++                        next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
++                        pkts_no_interface_address++;
++                        goto do_trace;
++                    }
++
++                    orig_len = o->length;
++                    o->data[orig_len + 0] = 1;   /* suboption 1, circuit ID (=FIB id) */
++                    o->data[orig_len + 1] = 4;   /* length of suboption */
++                    o->data[orig_len + 2] = (original_sw_if_index >> 24) & 0xFF;
++                    o->data[orig_len + 3] = (original_sw_if_index >> 16) & 0xFF;
++                    o->data[orig_len + 4] = (original_sw_if_index >> 8)  & 0xFF;
++                    o->data[orig_len + 5] = (original_sw_if_index >> 0)  & 0xFF;
++                    o->data[orig_len + 6] = 5; /* suboption 5 (client RX intfc address) */
++                    o->data[orig_len + 7] = 4; /* length 4 */
++                    o->data[orig_len + 8] = ia0->as_u8[0];
++                    o->data[orig_len + 9] = ia0->as_u8[1];
++                    o->data[orig_len + 10] = ia0->as_u8[2];
++                    o->data[orig_len + 11] = ia0->as_u8[3];
++                    o->data[orig_len + 12] = 0xFF;
++                    o->length += 12;   /* 12 octets appended*/
++
++                    len = o->length + 3;
++                    b0->current_length += len;
++                    /* Fix IP header length and checksum */
++                    old_l0 = ip0->length;
++                    new_l0 = clib_net_to_host_u16 (old_l0);
++                    new_l0 += len;
++                    new_l0 = clib_host_to_net_u16 (new_l0);
++                    ip0->length = new_l0;
++                    sum0 = ip0->checksum;
++                    sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
++                                           length /* changed member */);
++                    ip0->checksum = ip_csum_fold (sum0);
++      
++                    /* Fix UDP length */
++                    new_l0 = clib_net_to_host_u16 (u0->length);
++                    new_l0 += len;
++                    u0->length = clib_host_to_net_u16 (new_l0);
++                }
++              }
++
++              o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
++          }
++
++          next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP;
++
++          /*
++           * If we have multiple servers configured and this is the
++           * client's discover message, then send copies to each of
++           * those servers
++           */
++          if (is_discover && vec_len(proxy->dhcp_servers) > 1)
++          {
++              u32 ii;
++
++              for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++)
++              {
++                  vlib_buffer_t *c0;
++                  u32 ci0;
++              
++                  c0 = vlib_buffer_copy(vm, b0);
++                  ci0 = vlib_get_buffer_index(vm, c0);
++                  server = &proxy->dhcp_servers[ii];
++
++                  ip0 = vlib_buffer_get_current (c0);
++
++                  sum0 = ip0->checksum;
++                  old0 = ip0->dst_address.as_u32;
++                  new0 = server->dhcp_server.ip4.as_u32;
++                  ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
++                  sum0 = ip_csum_update (sum0, old0, new0, 
++                                         ip4_header_t /* structure */, 
++                                         dst_address /* changed member */);
++                  ip0->checksum = ip_csum_fold (sum0);
++
++                  to_next[0] = ci0;
++                  to_next += 1;
++                  n_left_to_next -= 1;
++
++                  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
++                                                   to_next, n_left_to_next,
++                                                   ci0, next0);
++
++                  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
++                  {
++                      dhcp_proxy_trace_t *tr;
++
++                      tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
++                      tr->which = 0; /* to server */
++                      tr->error = error0;
++                      tr->original_sw_if_index = original_sw_if_index;
++                      tr->sw_if_index = sw_if_index;
++                      if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP)
++                          tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32;
++                  }
++
++                  if (PREDICT_FALSE(0 == n_left_to_next))
++                  {
++                      vlib_put_next_frame (vm, node, next_index,
++                                           n_left_to_next);
++                      vlib_get_next_frame (vm, node, next_index,
++                                           to_next, n_left_to_next);
++                  }
++              }
++          }
++        do_trace:
++          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
++            {
++               dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, 
++                                                        b0, sizeof (*tr));
++               tr->which = 0; /* to server */
++               tr->error = error0;
++               tr->original_sw_if_index = original_sw_if_index;
++               tr->sw_if_index = sw_if_index;
++               if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP)
++                 tr->trace_ip4_address.as_u32 =
++                     proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
++            }
++
++        do_enqueue:
++        to_next[0] = bi0;
++        to_next += 1;
++        n_left_to_next -= 1;
++
++        vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
++                                         to_next, n_left_to_next,
++                                         bi0, next0);
++      }
++
++      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
++    }
++
++  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                               VBNG_DHCP4_ERROR_RELAY_TO_CLIENT,
++                               pkts_to_client);
++  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                               VBNG_DHCP4_ERROR_RELAY_TO_SERVER,
++                               pkts_to_server);
++  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                               VBNG_DHCP4_ERROR_NO_SERVER,
++                               pkts_no_server);
++  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                               VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS,
++                               pkts_no_interface_address);
++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                              VBNG_DHCP4_ERROR_PKT_TOO_BIG,
++                              pkts_too_big);
++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
++                              VBNG_DHCP4_ERROR_AAA_FAILURE,
++                              pkts_aaa_fail);
++  return from_frame->n_vectors;
++}
++
++VLIB_REGISTER_NODE (vbng_dhcp4_to_server_node, static) = {
++  .function = vbng_dhcp_to_server_input,
++  .name = "vbng-dhcp-to-server",
++  /* Takes a vector of packets. */
++  .vector_size = sizeof (u32),
++
++  .n_errors = VBNG_DHCP4_N_ERROR,
++  .error_strings = vbng_dhcp4_error_strings,
++
++  .n_next_nodes = VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT,
++  .next_nodes = {
++#define _(s,n) [VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s] = n,
++    foreach_vbng_dhcp4_to_server_input_next
++#undef _
++  },
++
++  .format_buffer = format_dhcp_proxy_header_with_length,
++  .format_trace = format_dhcp_proxy_trace,
++};
++
++static uword
++vbng_dhcp_to_client_input (vlib_main_t * vm,
++                           vlib_node_runtime_t * node,
++                           vlib_frame_t * from_frame)
++{
++  u32 n_left_from, * from;
++  ethernet_main_t *em = ethernet_get_main (vm);
++  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
++  vnet_main_t * vnm = vnet_get_main();
++  ip4_main_t * im = &ip4_main;
++
++  from = vlib_frame_vector_args (from_frame);
++  n_left_from = from_frame->n_vectors;
++
++  while (n_left_from > 0)
++    {
++      u32 bi0;
++      vlib_buffer_t * b0;
++      udp_header_t * u0;
++      dhcp_header_t * h0;
++      ip4_header_t * ip0 = 0;
++      ip4_address_t * ia0 = 0;
++      u32 old0, new0;
++      ip_csum_t sum0;
++      ethernet_interface_t *ei0;
++      ethernet_header_t *mac0;
++      vnet_hw_interface_t *hi0;
++      vlib_frame_t *f0;
++      u32 * to_next0;
++      u32 sw_if_index = ~0;
++      vnet_sw_interface_t *si0;
++      u32 error0 = (u32)~0;
++      vnet_sw_interface_t *swif;
++      u32 fib_index;
++      dhcp_proxy_t *proxy;
++      dhcp_server_t *server;
++      u32 original_sw_if_index = (u32) ~0;
++      ip4_address_t relay_addr = {
++          .as_u32 = 0,
++      };
++
++      bi0 = from[0];
++      from += 1;
++      n_left_from -= 1;
++
++      b0 = vlib_get_buffer (vm, bi0);
++      h0 = vlib_buffer_get_current (b0);
++
++      /* 
++       * udp_local hands us the DHCP header, need udp hdr, 
++       * ip hdr to relay to client
++       */
++      vlib_buffer_advance (b0, -(sizeof(*u0)));
++      u0 = vlib_buffer_get_current (b0);
++
++      vlib_buffer_advance (b0, -(sizeof(*ip0)));
++      ip0 = vlib_buffer_get_current (b0);
++
++      {
++          dhcp_option_t *o = (dhcp_option_t *) h0->options;
++          dhcp_option_t *sub;
++              
++          /* Parse through TLVs looking for option 82.
++             The circuit-ID is the FIB number we need
++             to track down the client-facing interface */
++
++          while (o->option != 0xFF /* end of options */ &&
++                 (u8 *) o < (b0->data + b0->current_data + b0->current_length))
++            {
++              if (o->option == 82)
++                {
++                    sub = (dhcp_option_t *) &o->data[0];
++                    while (sub->option != 0xFF /* end of options */ &&
++                           (u8 *) sub < (u8 *)(o + o->length)) {
++                        /* If this is one of ours, it will have
++                           total length 12, circuit-id suboption type,
++                           and the sw_if_index */
++                        if (sub->option == 1 && sub->length == 4)
++                          {
++                            sw_if_index = ((sub->data[0] << 24) |
++                                           (sub->data[1] << 16) |
++                                           (sub->data[2] << 8)  |
++                                           (sub->data[3]));
++                          }
++                        else if (sub->option == 5 && sub->length == 4)
++                          {
++                              relay_addr.as_u8[0] = sub->data[0];
++                              relay_addr.as_u8[1] = sub->data[1];
++                              relay_addr.as_u8[2] = sub->data[2];
++                              relay_addr.as_u8[3] = sub->data[3];
++                          }
++                        sub = (dhcp_option_t *) 
++                          (((uword) sub) + (sub->length + 2));
++                    }
++
++                }
++              o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
++            }
++        }
++
++      if (sw_if_index == (u32)~0)
++        {
++          error0 = VBNG_DHCP4_ERROR_NO_OPTION_82;
++          
++        drop_packet:
++          vlib_node_increment_counter (vm, vbng_dhcp4_to_client_node.index,
++                                       error0, 1);
++          f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index);
++          to_next0 = vlib_frame_vector_args (f0);
++          to_next0[0] = bi0;
++          f0->n_vectors = 1;
++          vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0);
++          goto do_trace;
++        }
++      
++      if (relay_addr.as_u32 == 0)
++        {
++          error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ADDR;
++          goto drop_packet;
++        }
++
++      if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index))
++        {
++          error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ITF;
++          goto drop_packet;
++        }
++
++      fib_index = im->fib_index_by_sw_if_index [sw_if_index];
++      proxy = vbng_dhcp4_get_server(dm, fib_index);
++
++      if (PREDICT_FALSE (NULL == proxy))
++        {
++          error0 = VBNG_DHCP4_ERROR_NO_SERVER;
++          goto drop_packet;
++        }
++      
++      vec_foreach(server, proxy->dhcp_servers)
++        {
++          if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32)
++            {
++              goto server_found;
++            }
++        }
++
++      error0 = VBNG_DHCP4_ERROR_BAD_SVR_FIB_OR_ADDRESS;
++      goto drop_packet;
++
++    server_found:
++      vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
++
++      swif = vnet_get_sw_interface (vnm, sw_if_index);
++      original_sw_if_index = sw_if_index;
++      if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
++          sw_if_index = swif->unnumbered_sw_if_index;
++
++      ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
++      if (ia0 == 0)
++        {
++          error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS;
++          goto drop_packet;
++        }
++
++      if (relay_addr.as_u32 != ia0->as_u32)
++        {             
++          error0 = VBNG_DHCP4_ERROR_BAD_YIADDR;
++          goto drop_packet;
++        }
++
++      u0->checksum = 0;
++      u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client);
++      sum0 = ip0->checksum;
++      old0 = ip0->dst_address.as_u32;
++      new0 = 0xFFFFFFFF;
++      ip0->dst_address.as_u32 = new0;
++      sum0 = ip_csum_update (sum0, old0, new0, 
++                            ip4_header_t /* structure */, 
++                            dst_address /* offset of changed member */);
++      ip0->checksum = ip_csum_fold (sum0);
++
++      sum0 = ip0->checksum;
++      old0 = ip0->src_address.as_u32;
++      new0 = ia0->as_u32;
++      ip0->src_address.as_u32 = new0;
++      sum0 = ip_csum_update (sum0, old0, new0, 
++                            ip4_header_t /* structure */, 
++                            src_address /* offset of changed member */);
++      ip0->checksum = ip_csum_fold (sum0);
++
++      vlib_buffer_advance (b0, -(sizeof(ethernet_header_t)));
++      si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
++      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
++        vlib_buffer_advance (b0, -4 /* space for VLAN tag */);
++
++      mac0 = vlib_buffer_get_current (b0);
++
++      hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index);
++      ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance);
++      clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address));
++      memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address));
++      mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ?
++      clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800);
++
++      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
++      {
++        u32 * vlan_tag = (u32 *)(mac0+1);
++        u32 tmp;
++        tmp = (si0->sub.id << 16) | 0x0800;
++        *vlan_tag = clib_host_to_net_u32 (tmp);
++      }
++
++      /* $$$ This needs to be rewritten, for sure */
++      f0 = vlib_get_frame_to_node (vm, hi0->output_node_index);
++      to_next0 = vlib_frame_vector_args (f0);
++      to_next0[0] = bi0;
++      f0->n_vectors = 1;
++      vlib_put_frame_to_node (vm, hi0->output_node_index, f0);
++
++    do_trace:
++      if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
++        {
++          dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, 
++                                                   b0, sizeof (*tr));
++          tr->which = 1; /* to client */
++          tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0;
++          tr->error = error0;
++          tr->original_sw_if_index = original_sw_if_index;
++          tr->sw_if_index = sw_if_index;
++        }
++    }
++  return from_frame->n_vectors;
++}
++
++VLIB_REGISTER_NODE (vbng_dhcp4_to_client_node, static) = {
++  .function = vbng_dhcp_to_client_input,
++  .name = "vbng-dhcp-to-client",
++  /* Takes a vector of packets. */
++  .vector_size = sizeof (u32),
++
++  .n_errors = VBNG_DHCP4_N_ERROR,
++  .error_strings = vbng_dhcp4_error_strings,
++  .format_buffer = format_dhcp_proxy_header_with_length,
++  .format_trace = format_dhcp_proxy_trace,
++};
++
++static clib_error_t *
++vbng_dhcp4_proxy_init (vlib_main_t * vm)
++{
++  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
++  vlib_node_t * error_drop_node;
++
++  error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
++  dm->error_drop_node_index = error_drop_node->index;
++
++  udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, 
++                         vbng_dhcp4_to_client_node.index, 1 /* is_ip4 */);
++
++  udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, 
++                         vbng_dhcp4_to_server_node.index, 1 /* is_ip4 */);
++
++  dm->vlib_main = vm;
++  dm->vnet_main = vnet_get_main();
++
++  return 0;
++}
++
++/* *INDENT-OFF* */
++VLIB_INIT_FUNCTION (vbng_dhcp4_proxy_init);
++/* *INDENT-ON* */
++
++int
++vbng_dhcp4_set_server (ip46_address_t *addr,
++                       ip46_address_t *src_addr,
++                       u32 rx_table_id,
++                       u32 server_table_id, 
++                       int is_del)
++{
++  u32 rx_fib_index = 0;
++  int rc = 0;
++
++  const fib_prefix_t all_1s =
++  {
++      .fp_len = 32,
++      .fp_addr.ip4.as_u32 = 0xffffffff,
++      .fp_proto = FIB_PROTOCOL_IP4,
++  };
++
++  if (ip46_address_is_zero(addr))
++    return VNET_API_ERROR_INVALID_DST_ADDRESS;
++  
++  if (ip46_address_is_zero(src_addr))
++    return VNET_API_ERROR_INVALID_SRC_ADDRESS;
++
++  rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
++                                                   rx_table_id);
++
++  if (is_del)
++    {
++      if (vbng_dhcp4_server_del (FIB_PROTOCOL_IP4, rx_fib_index,
++                                 addr, server_table_id))
++      {
++          fib_table_entry_special_remove(rx_fib_index,
++                                         &all_1s,
++                                         FIB_SOURCE_DHCP);
++          fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4);
++      }
++    }
++  else
++  {
++      if (vbng_dhcp4_server_add (FIB_PROTOCOL_IP4,
++                                 addr, src_addr,
++                                 rx_fib_index, server_table_id))
++      {
++          fib_table_entry_special_add(rx_fib_index,
++                                      &all_1s,
++                                      FIB_SOURCE_DHCP,
++                                      FIB_ENTRY_FLAG_LOCAL);
++          fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4);
++      }
++  }
++  fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4);
++
++  return (rc);
++}
++
++static clib_error_t *
++dhcp4_proxy_set_command_fn (vlib_main_t * vm,
++                            unformat_input_t * input,
++                            vlib_cli_command_t * cmd)
++{
++  ip46_address_t server_addr, src_addr;
++  u32 server_table_id = 0, rx_table_id = 0;
++  int is_del = 0;
++  int set_src = 0, set_server = 0;
++
++  memset(&server_addr, 0, sizeof(server_addr));
++  memset(&src_addr, 0, sizeof(src_addr));
++
++  while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
++    {
++      if (unformat (input, "remote %U", 
++                    unformat_ip4_address, &server_addr.ip4)) 
++        set_server = 1;
++      else if (unformat (input, "server-fib-id %d", &server_table_id))
++        ;
++      else if (unformat (input, "rx-fib-id %d", &rx_table_id))
++        ;
++      else if (unformat(input, "local %U", 
++                      unformat_ip4_address, &src_addr.ip4))
++        set_src = 1;
++      else if (unformat (input, "delete") ||
++               unformat (input, "del"))
++        is_del = 1;
++      else
++        break;
++    }
++
++  if (is_del || (set_server && set_src))
++    {
++      int rv;
++
++      rv = vbng_dhcp4_set_server (&server_addr, &src_addr, rx_table_id, 
++                                   server_table_id, is_del);
++      switch (rv)
++        {
++        case 0:
++          return 0;
++
++        case VNET_API_ERROR_INVALID_DST_ADDRESS:
++          return clib_error_return (0, "Invalid remote address");
++          
++        case VNET_API_ERROR_INVALID_SRC_ADDRESS:
++          return clib_error_return (0, "Invalid local address");
++
++        case VNET_API_ERROR_NO_SUCH_ENTRY:
++          return clib_error_return 
++            (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id);
++
++        default:
++          return clib_error_return (0, "BUG: rv %d", rv);
++        }
++    }
++  else
++    return clib_error_return (0, "parse error`%U'",
++                              format_unformat_error, input);
++}
++
++VLIB_CLI_COMMAND (vbng_dhcp4_set_command, static) = {
++  .path = "set vbng dhcp4",
++  .short_help = "set vbng dhcp4 [del] remote <ip-addr> local <ip-addr> [server-fib-id <n>] [rx-fib-id <n>]",
++  .function = dhcp4_proxy_set_command_fn,
++};
++
++static u8 *
++format_dhcp4_proxy_server (u8 * s, va_list * args)
++{
++  dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *);
++  ip4_fib_t * rx_fib, * server_fib;
++  dhcp_server_t *server;
++
++  if (proxy == 0)
++    {
++        s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", 
++                    "Servers FIB,Address");
++      return s;
++    }
++
++  rx_fib = ip4_fib_get(proxy->rx_fib_index);
++
++  s = format (s, "%=14u%=16U",
++              rx_fib->table_id,
++              format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY);
++
++  vec_foreach(server, proxy->dhcp_servers)
++  {
++      server_fib = ip4_fib_get(server->server_fib_index);
++      s = format (s, "%u,%U  ",
++                  server_fib->table_id,
++                  format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY);
++  }
++  return s;
++}
++
++static int
++dhcp4_proxy_show_walk (dhcp_proxy_t *server,
++                       void *ctx)
++{
++    vlib_main_t * vm = ctx;
++
++    vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server);
++
++    return (1);
++}
++
++static clib_error_t *
++vbng_dhcp4_show_command_fn (vlib_main_t * vm,
++                            unformat_input_t * input,
++                            vlib_cli_command_t * cmd)
++{
++  vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, NULL /* header line */);
++
++  vbng_dhcp4_walk(dhcp4_proxy_show_walk, vm);
++
++  return (NULL);
++}
++
++VLIB_CLI_COMMAND (vbng_dhcp4_show_command, static) = {
++  .path = "show vbng dhcp4",
++  .short_help = "Display vbng DHCP4 configuration info",
++  .function = vbng_dhcp4_show_command_fn,
++};
++
++static clib_error_t *
++vbng_aaa_set_command_fn (vlib_main_t * vm,
++                         unformat_input_t * input,
++                         vlib_cli_command_t * cmd)
++{
++      vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
++      u8 *config_file = NULL;
++      u32 nas_port  = 0;
++      int set_config = 0, is_del = 0;
++
++      while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) {
++              if (unformat (input, "nas-port %d", &nas_port))
++                      ;
++              else if (unformat (input, "config %v", &config_file))
++                      set_config = 1;
++              else if (unformat (input, "delete") ||
++                  unformat (input, "del"))
++                      is_del = 1;
++              else
++                      break;
++      }
++
++      if (!is_del && set_config) {
++              if (dm->config.is_enabled == VBNG_AAA_ENABLED) {
++                      return 0;
++              }
++
++              if (nas_port) {
++                      dm->config.nas_port = nas_port;
++              } else {
++                      dm->config.nas_port = AAA_DEFAULT_NAS_PORT;
++              }
++              dm->config.config_file = config_file;
++              dm->config.is_enabled = VBNG_AAA_ENABLED;
++      } else if (is_del) {
++              if (dm->config.is_enabled == VBNG_AAA_DISABLED) {
++                      return 0;
++              }
++
++              vec_free (dm->config.config_file);
++              dm->config.config_file = format(0, "%s",  AAA_DEFAULT_CONFIG_FILE);
++              dm->config.nas_port = AAA_DEFAULT_NAS_PORT;
++              dm->config.is_enabled = VBNG_AAA_DISABLED;
++      } else {
++              return clib_error_return (0, "parse error`%U'",
++                  format_unformat_error, input);
++      }
++
++      return 0;
++}
++
++VLIB_CLI_COMMAND (vbng_aaa_set_command, static) = {
++      .path = "set vbng aaa",
++      .short_help = "set vbng aaa [del] config <file> [nas-port <n>]",
++      .function = vbng_aaa_set_command_fn,
++};
++
++static u8 *
++format_vbng_aaa_config(u8 *s, va_list *args)
++{
++      vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
++
++      s = format(s, "%=8s %=8s %s\n", "Enabled",
++                 "NAS Port", "Config File");
++
++      s = format(s, "%=8s %=8d %v\n",
++              dm->config.is_enabled ? "True" : "False",
++              dm->config.nas_port,
++              dm->config.config_file);
++
++      return s;
++}
++
++static clib_error_t *
++vbng_aaa_show_command_fn (vlib_main_t * vm,
++                          unformat_input_t * input,
++                          vlib_cli_command_t * cmd)
++{
++  vlib_cli_output (vm, "%U", format_vbng_aaa_config, NULL);
++
++  return (NULL);
++}
++
++VLIB_CLI_COMMAND (vbng_aaa_show_command, static) = {
++      .path = "show vbng aaa",
++      .short_help = "Display vbng AAA configuration info",
++      .function = vbng_aaa_show_command_fn,
++};
++
++/* *INDENT-OFF* */
++VLIB_PLUGIN_REGISTER () = {
++      .version = VPP_BUILD_VER,
++      .description = "DHCP V4 Proxy With Radius Client",
++};
++/* *INDENT-ON* */
+diff --git a/src/plugins/vbng/vbng_msg_enum.h b/src/plugins/vbng/vbng_msg_enum.h
+new file mode 100644
+index 00000000..1dc1357f
+--- /dev/null
++++ b/src/plugins/vbng/vbng_msg_enum.h
+@@ -0,0 +1,31 @@
++/*
++ * vbng_msg_enum.h - vpp engine plug-in message enumeration
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef _VBNG_MSG_ENUM_H_
++#define _VBNG_MSG_ENUM_H_
++
++#include <vppinfra/byte_order.h>
++
++#define vl_msg_id(n,h) n,
++typedef enum
++{
++#include <vbng/vbng_all_api_h.h>
++  /* We'll want to know how many messages IDs we need... */
++  VL_MSG_FIRST_AVAILABLE,
++} vl_msg_id_t;
++#undef vl_msg_id
++
++#endif /* _VBNG_MSG_ENUM_H_ */
+diff --git a/src/vnet.am b/src/vnet.am
+index 9e099f33..7c107f0f 100644
+--- a/src/vnet.am
++++ b/src/vnet.am
+@@ -682,31 +682,31 @@ endif
+ ########################################
+ # DHCP client
+ ########################################
+-libvnet_la_SOURCES +=                         \
+- vnet/dhcp/client.c                           \
+- vnet/dhcp/client.h                           \
+- vnet/dhcp/dhcp_api.c
+-
+-nobase_include_HEADERS +=                     \
+- vnet/dhcp/client.h                           \
+- vnet/dhcp/dhcp.api.h
+-
+-API_FILES += vnet/dhcp/dhcp.api
++#libvnet_la_SOURCES +=                                \
++# vnet/dhcp/client.c                          \
++# vnet/dhcp/client.h                          \
++# vnet/dhcp/dhcp_api.c
++#
++#nobase_include_HEADERS +=                    \
++# vnet/dhcp/client.h                          \
++# vnet/dhcp/dhcp.api.h
++#
++#API_FILES += vnet/dhcp/dhcp.api
+ ########################################
+ # DHCP proxy
+ ########################################
+-libvnet_la_SOURCES +=                         \
+- vnet/dhcp/dhcp6_proxy_node.c                   \
+- vnet/dhcp/dhcp4_proxy_node.c                 \
+- vnet/dhcp/dhcp_proxy.c
+-
+-nobase_include_HEADERS +=                     \
+- vnet/dhcp/dhcp4_packet.h                     \
+- vnet/dhcp/dhcp6_packet.h                     \
+- vnet/dhcp/dhcp_proxy.h                               \
+- vnet/dhcp/dhcp6_proxy_error.def                \
+- vnet/dhcp/dhcp4_proxy_error.def
++#libvnet_la_SOURCES +=                                \
++# vnet/dhcp/dhcp6_proxy_node.c                   \
++# vnet/dhcp/dhcp4_proxy_node.c                        \
++# vnet/dhcp/dhcp_proxy.c
++#
++#nobase_include_HEADERS +=                    \
++# vnet/dhcp/dhcp4_packet.h                    \
++# vnet/dhcp/dhcp6_packet.h                    \
++# vnet/dhcp/dhcp_proxy.h                              \
++# vnet/dhcp/dhcp6_proxy_error.def                \
++# vnet/dhcp/dhcp4_proxy_error.def
+ ########################################
+ # ipv6 segment routing
+diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am
+index f18e0c24..cadaa8d9 100644
+--- a/src/vpp-api/java/Makefile.am
++++ b/src/vpp-api/java/Makefile.am
+@@ -149,6 +149,26 @@ jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_js
+ endif
+ #
++# VBNG Plugin
++#
++if ENABLE_VBNG_PLUGIN
++noinst_LTLIBRARIES += libjvpp_vbng.la
++libjvpp_vbng_la_SOURCES = jvpp-vbng/jvpp_vbng.c
++libjvpp_vbng_la_CPPFLAGS = -Ijvpp-vbng
++libjvpp_vbng_la_LIBADD = $(JVPP_LIBS)
++libjvpp_vbng_la_DEPENDENCIES = libjvpp_common.la
++
++BUILT_SOURCES += jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h
++JAR_FILES += jvpp-vbng-$(PACKAGE_VERSION).jar
++CLEANDIRS += jvpp-vbng/target
++
++jvpp_vbng_json_files = @top_builddir@/plugins/vbng/vbng.api.json
++
++jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h: $(jvpp_registry_ok) $(jvpp_vbng_json_files)
++      $(call japigen,vbng,JVppVbngImpl)
++endif
++
++#
+ # iOAM Trace Plugin
+ #
+ if ENABLE_IOAM_PLUGIN
+diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c
+new file mode 100644
+index 00000000..b722a500
+--- /dev/null
++++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c
+@@ -0,0 +1,108 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <vnet/vnet.h>
++
++#include <vbng/vbng_msg_enum.h>
++#define vl_typedefs             /* define message structures */
++#include <vbng/vbng_all_api_h.h>
++#undef vl_typedefs
++
++#include <vnet/api_errno.h>
++#include <vlibapi/api.h>
++#include <vlibmemory/api.h>
++
++#if VPPJNI_DEBUG == 1
++  #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
++#else
++  #define DEBUG_LOG(...)
++#endif
++
++#include <jvpp-common/jvpp_common.h>
++
++#include "jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h"
++#include "jvpp_vbng.h"
++#include "jvpp-vbng/jvpp_vbng_gen.h"
++
++/*
++ * Class:     io_fd_vpp_jvpp_vbng_JVppVbngImpl
++ * Method:    init0
++ * Signature: (JI)V
++ */
++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0
++  (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) {
++  vbng_main_t * plugin_main = &vbng_main;
++  clib_warning ("Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0");
++
++  plugin_main->my_client_index = my_client_index;
++  plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address;
++
++  plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
++  plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
++
++  // verify API has not changed since jar generation
++  #define _(N)             \
++      get_message_id(env, #N);
++      foreach_supported_api_message;
++  #undef _
++
++  #define _(N,n)                                  \
++      vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
++              vl_api_##n##_t_handler,             \
++              vl_noop_handler,                    \
++              vl_noop_handler,                    \
++              vl_noop_handler,                    \
++              sizeof(vl_api_##n##_t), 1);
++      foreach_api_reply_handler;
++  #undef _
++}
++
++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_close0
++(JNIEnv *env, jclass clazz) {
++  vbng_main_t * plugin_main = &vbng_main;
++
++    // cleanup:
++    (*env)->DeleteGlobalRef(env, plugin_main->callbackClass);
++    (*env)->DeleteGlobalRef(env, plugin_main->callbackObject);
++
++    plugin_main->callbackClass = NULL;
++    plugin_main->callbackObject = NULL;
++}
++
++/* Attach thread to JVM and cache class references when initiating JVPP VES */
++jint JNI_OnLoad(JavaVM *vm, void *reserved) {
++    JNIEnv* env;
++
++    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
++        return JNI_EVERSION;
++    }
++
++    if (cache_class_references(env) != 0) {
++        clib_warning ("Failed to cache class references\n");
++        return JNI_ERR;
++    }
++
++    return JNI_VERSION_1_8;
++}
++
++/* Clean up cached references when disposing JVPP VES */
++void JNI_OnUnload(JavaVM *vm, void *reserved) {
++    JNIEnv* env;
++    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
++        return;
++    }
++    delete_class_references(env);
++}
+diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h
+new file mode 100644
+index 00000000..62b4cda5
+--- /dev/null
++++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef __included_jvpp_vbng_h__
++#define __included_jvpp_vbng_h__
++
++#include <vnet/vnet.h>
++#include <vnet/ip/ip.h>
++#include <vnet/api_errno.h>
++#include <vlibapi/api.h>
++#include <vlibmemory/api.h>
++#include <jni.h>
++
++/* Global state for JVPP-VES */
++typedef struct {
++    /* Pointer to shared memory queue */
++    unix_shared_memory_queue_t * vl_input_queue;
++
++    /* VPP api client index */
++    u32 my_client_index;
++
++    /* Callback object and class references enabling asynchronous Java calls */
++    jobject callbackObject;
++    jclass callbackClass;
++
++} vbng_main_t;
++
++vbng_main_t vbng_main __attribute__((aligned (64)));
++
++#endif /* __included_jvpp_vbng_h__ */
+-- 
+2.12.2.windows.2
+
diff --git a/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch
new file mode 100644 (file)
index 0000000..8c2e31b
--- /dev/null
@@ -0,0 +1,1079 @@
+From 9a00b1af18dfe4c2df185299b8bd2db7f5d061c0 Mon Sep 17 00:00:00 2001
+From: Johnson Li <johnson.li@intel.com>
+Date: Fri, 8 Sep 2017 17:35:16 +0800
+Subject: [PATCH] Add VES agent configuration for vG-MUX
+
+Signed-off-by: Johnson Li <johnson.li@intel.com>
+
+diff --git a/pom.xml b/pom.xml
+index 538a5d98..581bedfc 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -44,13 +44,14 @@
+     <module>nat</module>
+     <module>lisp</module>
+     <module>release-notes</module>
+-    <module>vpp-integration</module>
+     <module>acl</module>
+     <module>dhcp</module>
++    <module>ves</module>
+     <module>samples</module>
+     <module>vpp-classifier</module>
+     <module>l3</module>
+     <module>vpp-management</module>
++    <module>vpp-integration</module>
+     <module>it</module>
+   </modules>
+ </project>
+\ No newline at end of file
+diff --git a/ves/asciidoc/Readme.adoc b/ves/asciidoc/Readme.adoc
+new file mode 100644
+index 00000000..682e7555
+--- /dev/null
++++ b/ves/asciidoc/Readme.adoc
+@@ -0,0 +1,3 @@
++= ves-agent
++
++Overview of ves-agent
+diff --git a/ves/pom.xml b/ves/pom.xml
+new file mode 100644
+index 00000000..1ded0109
+--- /dev/null
++++ b/ves/pom.xml
+@@ -0,0 +1,56 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++ Copyright (c) 2017 Cisco and/or its affiliates.
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ You may obtain a copy of the License at:
++
++     http://www.apache.org/licenses/LICENSE-2.0
++
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
++
++  <parent>
++    <groupId>io.fd.hc2vpp.common</groupId>
++    <artifactId>hc2vpp-parent</artifactId>
++    <version>1.17.04.1-SNAPSHOT</version>
++    <relativePath>../common/hc2vpp-parent</relativePath>
++  </parent>
++
++  <groupId>io.fd.hc2vpp.ves</groupId>
++  <artifactId>ves-agent</artifactId>
++  <version>1.17.04.1-SNAPSHOT</version>
++  <name>ves-agent</name>
++  <packaging>pom</packaging>
++  <modelVersion>4.0.0</modelVersion>
++  <description>Agent for VNF Event Stream plugin</description>
++
++  <modules>
++    <module>ves-api</module>
++    <module>ves-impl</module>
++  </modules>
++
++  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
++  <build>
++    <plugins>
++      <plugin>
++        <groupId>org.apache.maven.plugins</groupId>
++        <artifactId>maven-deploy-plugin</artifactId>
++        <configuration>
++          <skip>true</skip>
++        </configuration>
++      </plugin>
++      <plugin>
++        <groupId>org.apache.maven.plugins</groupId>
++        <artifactId>maven-install-plugin</artifactId>
++        <configuration>
++          <skip>true</skip>
++        </configuration>
++      </plugin>
++    </plugins>
++  </build>
++</project>
+diff --git a/ves/ves-api/asciidoc/Readme.adoc b/ves/ves-api/asciidoc/Readme.adoc
+new file mode 100644
+index 00000000..b561268c
+--- /dev/null
++++ b/ves/ves-api/asciidoc/Readme.adoc
+@@ -0,0 +1,3 @@
++= vesagent-api
++
++Overview of vesagent-api
+\ No newline at end of file
+diff --git a/ves/ves-api/pom.xml b/ves/ves-api/pom.xml
+new file mode 100644
+index 00000000..78bf47b9
+--- /dev/null
++++ b/ves/ves-api/pom.xml
+@@ -0,0 +1,52 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++ Copyright (c) 2017 Cisco and/or its affiliates.
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ You may obtain a copy of the License at:
++
++     http://www.apache.org/licenses/LICENSE-2.0
++
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
++  <parent>
++    <groupId>io.fd.hc2vpp.common</groupId>
++    <artifactId>api-parent</artifactId>
++    <version>1.17.04.1-SNAPSHOT</version>
++    <relativePath>../../common/api-parent</relativePath>
++  </parent>
++
++  <modelVersion>4.0.0</modelVersion>
++  <groupId>io.fd.hc2vpp.ves</groupId>
++  <artifactId>ves-api</artifactId>
++  <name>ves-api</name>
++  <version>1.17.04.1-SNAPSHOT</version>
++  <packaging>bundle</packaging>
++
++  <dependencies>
++    <dependency>
++      <groupId>org.opendaylight.mdsal.model</groupId>
++      <artifactId>iana-if-type-2014-05-08</artifactId>
++    </dependency>
++    <dependency>
++      <groupId>org.opendaylight.mdsal.model</groupId>
++      <artifactId>ietf-yang-types-20130715</artifactId>
++    </dependency>
++    <dependency>
++      <groupId>org.opendaylight.mdsal.model</groupId>
++      <artifactId>ietf-interfaces</artifactId>
++    </dependency>
++    <dependency>
++      <groupId>org.opendaylight.mdsal.model</groupId>
++      <artifactId>ietf-inet-types-2013-07-15</artifactId>
++    </dependency>
++    <dependency>
++      <groupId>org.opendaylight.mdsal.model</groupId>
++      <artifactId>yang-ext</artifactId>
++    </dependency>
++  </dependencies>
++</project>
+diff --git a/ves/ves-api/src/main/yang/vesagent.yang b/ves/ves-api/src/main/yang/vesagent.yang
+new file mode 100644
+index 00000000..a3c79797
+--- /dev/null
++++ b/ves/ves-api/src/main/yang/vesagent.yang
+@@ -0,0 +1,71 @@
++module vesagent {
++
++    yang-version 1;
++    namespace "urn:opendaylight:params:xml:ns:yang:vpp:vesagent";
++    prefix "vesagent";
++
++    description
++        "This YANG module defines the generic configuration and
++        operational data for VES Agent in VPP";
++
++    revision "2017-08-01" {
++        description
++            "Initial revision of VES Agent model";
++    }
++
++    import ietf-inet-types {
++        prefix inet;
++    }
++
++    grouping vesagent-attributes {
++        container config {
++            description
++                "VNF Event Stream Agent configuration";
++
++            leaf server-addr {
++                type inet:ipv4-address;
++                description
++                    "VES Collector's IP address.";
++            }
++
++            leaf server-port {
++                type uint32;
++                description
++                    "VES Collector's Server Port.";
++            }
++
++            leaf read-interval {
++                type uint32;
++                description
++                    "Seconds of time period for each loop.";
++            }
++
++            leaf is-add {
++                type uint32;
++                description
++                    "0-Delete VES agent, NonZero-Start VES agent.";
++            }
++        }
++
++        container mode {
++            description
++                "VNF Event Stream Agent Working Mode.";
++
++            leaf base-packet-loss {
++                type uint32;
++                description
++                    "Base packet Loss for Demo Mode";
++            }
++
++            leaf working-mode {
++                type string;
++                description
++                    "VES Working Mode, Demo Or Real Only.";
++            }
++        }
++    }
++
++    container vesagent {
++        uses vesagent-attributes;
++    }
++}
+diff --git a/ves/ves-impl/asciidoc/Readme.adoc b/ves/ves-impl/asciidoc/Readme.adoc
+new file mode 100644
+index 00000000..e07fb05f
+--- /dev/null
++++ b/ves/ves-impl/asciidoc/Readme.adoc
+@@ -0,0 +1,3 @@
++= vesagent-impl
++
++Overview of vesagent-impl
+\ No newline at end of file
+diff --git a/ves/ves-impl/pom.xml b/ves/ves-impl/pom.xml
+new file mode 100644
+index 00000000..5ed2c1b4
+--- /dev/null
++++ b/ves/ves-impl/pom.xml
+@@ -0,0 +1,157 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!--
++ Copyright (c) 2017 Cisco and/or its affiliates.
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ You may obtain a copy of the License at:
++
++     http://www.apache.org/licenses/LICENSE-2.0
++
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
++    <parent>
++        <groupId>io.fd.hc2vpp.common</groupId>
++        <artifactId>vpp-impl-parent</artifactId>
++        <version>1.17.04.1-SNAPSHOT</version>
++        <relativePath>../../vpp-common/vpp-impl-parent</relativePath>
++    </parent>
++
++    <modelVersion>4.0.0</modelVersion>
++    <groupId>io.fd.hc2vpp.ves</groupId>
++    <artifactId>ves-impl</artifactId>
++    <name>${project.artifactId}</name>
++    <version>1.17.04.1-SNAPSHOT</version>
++    <packaging>bundle</packaging>
++
++    <properties>
++        <honeycomb.infra.version>1.17.04.1-SNAPSHOT</honeycomb.infra.version>
++        <hc2vpp.common.version>1.17.04.1-SNAPSHOT</hc2vpp.common.version>
++    </properties>
++
++    <dependencies>
++        <dependency>
++            <groupId>${project.groupId}</groupId>
++            <artifactId>ves-api</artifactId>
++            <version>${project.version}</version>
++        </dependency>
++
++        <!--VPP common-->
++        <dependency>
++            <groupId>io.fd.hc2vpp.common</groupId>
++            <artifactId>vpp-translate-utils</artifactId>
++        </dependency>
++
++        <!-- JVPP -->
++        <dependency>
++            <groupId>io.fd.vpp</groupId>
++            <artifactId>jvpp-registry</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>io.fd.vpp</groupId>
++            <artifactId>jvpp-ves</artifactId>
++            <version>17.04.2-SNAPSHOT</version>
++        </dependency>
++
++        <!-- Honeycomb infrastructure-->
++        <dependency>
++            <groupId>io.fd.honeycomb</groupId>
++            <artifactId>minimal-distribution</artifactId>
++            <version>${honeycomb.infra.version}</version>
++        </dependency>
++
++        <dependency>
++            <groupId>io.fd.honeycomb</groupId>
++            <artifactId>translate-api</artifactId>
++            <version>${honeycomb.infra.version}</version>
++        </dependency>
++
++        <dependency>
++            <groupId>io.fd.honeycomb</groupId>
++            <artifactId>translate-spi</artifactId>
++            <version>${honeycomb.infra.version}</version>
++        </dependency>
++
++        <dependency>
++            <groupId>io.fd.honeycomb</groupId>
++            <artifactId>cfg-init</artifactId>
++            <version>${honeycomb.infra.version}</version>
++        </dependency>
++
++        <!-- Translation -->
++        <dependency>
++            <groupId>io.fd.hc2vpp.common</groupId>
++            <artifactId>vpp-translate-utils</artifactId>
++        </dependency>
++
++        <!-- DI -->
++        <dependency>
++            <groupId>com.google.inject</groupId>
++            <artifactId>guice</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>net.jmob</groupId>
++            <artifactId>guice.conf</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>com.google.inject.extensions</groupId>
++            <artifactId>guice-multibindings</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>io.fd.honeycomb</groupId>
++            <artifactId>translate-impl</artifactId>
++            <version>1.17.04.1-SNAPSHOT</version>
++        </dependency>
++
++
++        <!-- Testing dependencies-->
++        <dependency>
++            <groupId>com.google.inject</groupId>
++            <artifactId>guice</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>net.jmob</groupId>
++            <artifactId>guice.conf</artifactId>
++        </dependency>
++        <dependency>
++            <groupId>com.google.inject.extensions</groupId>
++            <artifactId>guice-multibindings</artifactId>
++        </dependency>
++
++        <dependency>
++            <groupId>junit</groupId>
++            <artifactId>junit</artifactId>
++            <scope>test</scope>
++        </dependency>
++        <dependency>
++            <groupId>io.fd.hc2vpp.common</groupId>
++            <artifactId>vpp-translate-test</artifactId>
++            <version>${hc2vpp.common.version}</version>
++            <scope>test</scope>
++        </dependency>
++        <dependency>
++            <groupId>org.mockito</groupId>
++            <artifactId>mockito-core</artifactId>
++            <scope>test</scope>
++        </dependency>
++        <dependency>
++            <groupId>com.google.inject.extensions</groupId>
++            <artifactId>guice-testlib</artifactId>
++            <scope>test</scope>
++        </dependency>
++        <dependency>
++            <groupId>org.hamcrest</groupId>
++            <artifactId>hamcrest-all</artifactId>
++            <scope>test</scope>
++        </dependency>
++        <dependency>
++            <groupId>io.fd.honeycomb.infra</groupId>
++            <artifactId>test-tools</artifactId>
++            <version>${project.version}</version>
++            <scope>test</scope>
++        </dependency>
++    </dependencies>
++</project>
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java
+new file mode 100644
+index 00000000..0cd60068
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java
+@@ -0,0 +1,67 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves;
++
++import com.google.common.annotations.VisibleForTesting;
++import com.google.inject.AbstractModule;
++import com.google.inject.Provider;
++import com.google.inject.Singleton;
++import com.google.inject.multibindings.Multibinder;
++import io.fd.hc2vpp.ves.jvpp.JVppVesProvider;
++import io.fd.hc2vpp.ves.read.VesReaderFactory;
++import io.fd.hc2vpp.ves.write.VesWriterFactory;
++import io.fd.honeycomb.translate.read.ReaderFactory;
++import io.fd.honeycomb.translate.write.WriterFactory;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++/**
++ * VesModule class instantiating ves plugin components.
++ */
++public final class VesModule extends AbstractModule {
++
++    private static final Logger LOG = LoggerFactory.getLogger(VesModule.class);
++    private final Class<? extends Provider<FutureJVppVesFacade>> jvppVesProviderClass;
++
++    public VesModule() {
++        this(JVppVesProvider.class);
++    }
++
++    @VisibleForTesting
++    VesModule(Class<? extends Provider<FutureJVppVesFacade>> jvppVesProvider) {
++        this.jvppVesProviderClass = jvppVesProvider;
++    }
++
++    @Override
++    protected void configure() {
++        LOG.info("Installing VES Agent module");
++
++        // Bind to Plugin's JVPP
++        bind(FutureJVppVesFacade.class).toProvider(jvppVesProviderClass).in(Singleton.class);
++
++        LOG.info("Injecting writers factories");
++        final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
++        writerFactoryBinder.addBinding().to(VesWriterFactory.class);
++
++        LOG.info("Injecting readers factories");
++        final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
++        readerFactoryBinder.addBinding().to(VesReaderFactory.class);
++
++        LOG.info("Module VES Agent successfully configured");
++    }
++}
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java
+new file mode 100644
+index 00000000..8afed84e
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.jvpp;
++
++import com.google.inject.Inject;
++import io.fd.honeycomb.infra.distro.ProviderTrait;
++import io.fd.vpp.jvpp.JVppRegistry;
++import io.fd.vpp.jvpp.ves.JVppVesImpl;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import java.io.IOException;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++/**
++ * Provides future API for jvpp-ves plugin. Must be a singleton due to shutdown hook usage.
++ * Registers shutdown hook to free plugin's resources on shutdown.
++ */
++public final class JVppVesProvider extends ProviderTrait<FutureJVppVesFacade> {
++
++    private static final Logger LOG = LoggerFactory.getLogger(JVppVesProvider.class);
++
++    @Inject
++    private JVppRegistry registry;
++
++    @Override
++    protected FutureJVppVesFacade create() {
++        try {
++            final JVppVesImpl jvppVes = new JVppVesImpl();
++            Runtime.getRuntime().addShutdownHook(new Thread() {
++                @Override
++                public void run() {
++                    LOG.info("Unloading jvpp-ves plugin");
++                    jvppVes.close();
++                    LOG.info("Successfully unloaded jvpp-ves plugin");
++                }
++            });
++
++            LOG.info("Successfully loaded jvpp-ves plugin");
++            return new FutureJVppVesFacade(registry, jvppVes);
++        } catch (IOException e) {
++            throw new IllegalStateException("Unable to open VPP management connection", e);
++        }
++    }
++}
++
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java
+new file mode 100644
+index 00000000..bef652fd
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.read;
++
++import com.google.inject.Inject;
++import io.fd.honeycomb.translate.read.ReaderFactory;
++import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
++import io.fd.vpp.jvpp.core.future.FutureJVppCore;
++import javax.annotation.Nonnull;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.VesagentBuilder;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ModeBuilder;
++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
++
++/**
++ * Factory producing writers for VES Agent plugin's data.
++ */
++public final class VesReaderFactory implements ReaderFactory {
++
++    private static final InstanceIdentifier<Vesagent> VESAGENT_ID = InstanceIdentifier.create(Vesagent.class);
++    private static final InstanceIdentifier<Config> CONFIG_ID = InstanceIdentifier.create(Config.class);
++    private static final InstanceIdentifier<Mode> MODE_ID = InstanceIdentifier.create(Mode.class);
++
++    @Inject
++    private FutureJVppCore vppApi;
++
++    @Override
++    public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
++        registry.addStructuralReader(VESAGENT_ID, VesagentBuilder.class);
++        registry.addStructuralReader(CONFIG_ID, ConfigBuilder.class);
++        registry.addStructuralReader(MODE_ID, ModeBuilder.class);
++    }
++}
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java
+new file mode 100644
+index 00000000..e06afa73
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.write;
++
++import static com.google.common.base.Preconditions.checkArgument;
++
++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
++import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
++import io.fd.hc2vpp.common.translate.util.Ipv6Translator;
++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
++import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
++import io.fd.honeycomb.translate.write.WriteContext;
++import io.fd.honeycomb.translate.write.WriteFailedException;
++import io.fd.vpp.jvpp.core.future.FutureJVppCore;
++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes;
++import io.fd.vpp.jvpp.ves.dto.VesAgentConfig;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import javax.annotation.Nonnull;
++//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder;
++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++final class VesConfigCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Config>,
++    JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator {
++    private static final Logger LOG = LoggerFactory.getLogger(VesConfigCustomizer.class);
++
++    private final FutureJVppVesFacade jvppVes;
++
++    VesConfigCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) {
++        super(vppApi);
++        this.jvppVes = jvppVes;
++    }
++
++    @Override
++    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataAfter,
++                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        InstanceIdentifier<Config> id = iid;
++
++        LOG.debug("Writing VES Agent Config {} dataAfter={}", id, dataAfter);
++        checkArgument(dataAfter.getServerAddr() != null && dataAfter.getServerAddr().getValue() != null
++            && dataAfter.getServerPort() != 0, "VES Server Address and Port need to be configured");
++
++        configBuilder.setServerAddr(dataAfter.getServerAddr())
++                     .setServerPort(dataAfter.getServerPort())
++                     .setReadInterval(dataAfter.getReadInterval())
++                     .setIsAdd(1L);
++
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    @Override
++    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataBefore,
++                                        @Nonnull final Config dataAfter, @Nonnull final WriteContext writeContext)
++        throws WriteFailedException {
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        InstanceIdentifier<Config> id = iid;
++
++        checkArgument(dataBefore.getServerAddr() != null && dataBefore.getServerAddr().getValue() != null
++            && dataBefore.getServerPort() != 0, "VES Server Address and Port need to be configured");
++        checkArgument(dataAfter.getServerAddr() != null && dataAfter.getServerAddr().getValue() != null
++            && dataAfter.getServerPort() != 0, "VES Server Address and Port need to be configured");
++
++        // remove old configuration:
++        configBuilder.setServerAddr(dataBefore.getServerAddr())
++                     .setServerPort(dataBefore.getServerPort())
++                     .setReadInterval(dataBefore.getReadInterval())
++                     .setIsAdd(0L);
++        setVesAgentConfig(id, configBuilder.build());
++
++        // and add new one:
++        configBuilder.setServerAddr(dataAfter.getServerAddr())
++                     .setServerPort(dataAfter.getServerPort())
++                     .setReadInterval(dataAfter.getReadInterval())
++                     .setIsAdd(1L);
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    @Override
++    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataBefore,
++                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        InstanceIdentifier<Config> id = iid;
++        LOG.debug("Removing VES Agent {} dataBefore={}", id, dataBefore);
++
++        checkArgument(dataBefore.getServerAddr() != null && dataBefore.getServerAddr().getValue() != null
++            && dataBefore.getServerPort() != 0, "VES Server Address and Port need to be dataBeforeured");
++
++        configBuilder.setServerAddr(dataBefore.getServerAddr())
++                     .setServerPort(dataBefore.getServerPort())
++                     .setReadInterval(dataBefore.getReadInterval())
++                     .setIsAdd(0L);
++
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    private void setVesAgentConfig(final InstanceIdentifier<Config> id, final Config config)
++        throws WriteFailedException {
++        final VesAgentConfig request = new VesAgentConfig();
++
++        request.serverPort = config.getServerPort().byteValue();
++        request.readInterval = config.getReadInterval().byteValue();
++        request.isAdd = config.getIsAdd().byteValue();
++        request.serverAddr = ipv4AddressNoZoneToArray(config.getServerAddr().getValue());
++
++        LOG.debug("VES agent config change id={} request={}", id, request);
++        getReplyForWrite(jvppVes.vesAgentConfig(request).toCompletableFuture(), id);
++    }
++}
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java
+new file mode 100644
+index 00000000..8b6d5a9a
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java
+@@ -0,0 +1,97 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.write;
++
++import static com.google.common.base.Preconditions.checkArgument;
++
++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
++import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
++import io.fd.hc2vpp.common.translate.util.Ipv6Translator;
++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
++import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
++import io.fd.honeycomb.translate.write.WriteContext;
++import io.fd.honeycomb.translate.write.WriteFailedException;
++import io.fd.vpp.jvpp.core.future.FutureJVppCore;
++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes;
++import io.fd.vpp.jvpp.ves.dto.VesAgentMode;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import javax.annotation.Nonnull;
++//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ModeBuilder;
++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++final class VesModeCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Mode>,
++    JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator {
++    private static final Logger LOG = LoggerFactory.getLogger(VesModeCustomizer.class);
++
++    private final FutureJVppVesFacade jvppVes;
++
++    VesModeCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) {
++        super(vppApi);
++        this.jvppVes = jvppVes;
++    }
++
++    @Override
++    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataAfter,
++                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        LOG.debug("Writing VES Agent Working Mode {} dataAfter={}", iid, dataAfter);
++
++        checkArgument(dataAfter.getWorkingMode() != null && dataAfter.getBasePacketLoss() <= 100,
++                      "VES Agent Working Mode need to be correctly configured.");
++
++        setVesAgentMode(iid, dataAfter);
++    }
++
++    @Override
++    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataBefore,
++                                        @Nonnull final Mode dataAfter, @Nonnull final WriteContext writeContext)
++        throws WriteFailedException {
++        LOG.debug("Writing VES Agent Working Mode {} {}-->{}", iid, dataBefore, dataAfter);
++
++        checkArgument(dataAfter.getWorkingMode() != null && dataAfter.getBasePacketLoss() <= 100,
++                      "VES Agent Working Mode need to be correctly configured.");
++
++        setVesAgentMode(iid, dataAfter);
++    }
++
++    @Override
++    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataBefore,
++                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        ModeBuilder modeBuilder = new ModeBuilder();
++        LOG.debug("Restoring VES Mode {} dataBefore={} to default.", iid, dataBefore);
++
++        modeBuilder.setWorkingMode("Real")
++                   .setBasePacketLoss(0L);
++
++        setVesAgentMode(iid, modeBuilder.build());
++    }
++
++    private void setVesAgentMode(final InstanceIdentifier<Mode> id, final Mode mode)
++        throws WriteFailedException {
++        final VesAgentMode request = new VesAgentMode();
++
++        request.pktLossRate = mode.getBasePacketLoss().byteValue();
++        request.workMode = mode.getWorkingMode().getBytes();
++
++        LOG.debug("VES agent working mode change id={} request={}", id, request);
++        getReplyForWrite(jvppVes.vesAgentMode(request).toCompletableFuture(), id);
++    }
++}
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java
+new file mode 100644
+index 00000000..581f0460
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.write;
++
++import com.google.common.collect.ImmutableSet;
++import com.google.inject.Inject;
++import io.fd.honeycomb.translate.impl.write.GenericWriter;
++import io.fd.honeycomb.translate.write.WriterFactory;
++import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
++import io.fd.vpp.jvpp.core.future.FutureJVppCore;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import javax.annotation.Nonnull;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode;
++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
++
++/**
++ * Factory producing writers for VES Agent plugin's data.
++ */
++public final class VesWriterFactory implements WriterFactory {
++
++    private static final InstanceIdentifier<Vesagent> VESAGENT_ID = InstanceIdentifier.create(Vesagent.class);
++
++    @Inject
++    private FutureJVppCore vppApi;
++
++    @Inject
++    protected FutureJVppVesFacade futureVesFacade;
++
++    @Override
++    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
++         registry.add(new GenericWriter<>(VESAGENT_ID,
++             new VesagentCustomizer(vppApi, futureVesFacade)));
++         registry.add(new GenericWriter<>(VESAGENT_ID.child(Config.class),
++             new VesConfigCustomizer(vppApi, futureVesFacade)));
++         registry.add(new GenericWriter<>(VESAGENT_ID.child(Mode.class),
++             new VesModeCustomizer(vppApi, futureVesFacade)));
++    }
++}
+diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java
+new file mode 100644
+index 00000000..62e46cdb
+--- /dev/null
++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java
+@@ -0,0 +1,131 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package io.fd.hc2vpp.ves.write;
++
++import static com.google.common.base.Preconditions.checkArgument;
++
++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
++import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
++import io.fd.hc2vpp.common.translate.util.Ipv6Translator;
++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
++import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
++import io.fd.honeycomb.translate.write.WriteContext;
++import io.fd.honeycomb.translate.write.WriteFailedException;
++import io.fd.vpp.jvpp.core.future.FutureJVppCore;
++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes;
++import io.fd.vpp.jvpp.ves.dto.VesAgentConfig;
++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade;
++import javax.annotation.Nonnull;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config;
++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder;
++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++final class VesagentCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Vesagent>,
++    JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator {
++    private static final Logger LOG = LoggerFactory.getLogger(VesagentCustomizer.class);
++
++    private final FutureJVppVesFacade jvppVes;
++
++    VesagentCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) {
++        super(vppApi);
++        this.jvppVes = jvppVes;
++    }
++
++    @Override
++    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataAfter,
++                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        Config config = dataAfter.getConfig();
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        InstanceIdentifier<Config> id = iid.child(Config.class);
++
++        LOG.debug("Writing VES Agent Config {} dataAfter={}", id, config);
++        checkArgument(config.getServerAddr() != null && config.getServerAddr().getValue() != null
++            && config.getServerPort() != 0, "VES Server Address and Port need to be configured");
++
++        configBuilder.setServerAddr(config.getServerAddr())
++                     .setServerPort(config.getServerPort())
++                     .setReadInterval(config.getReadInterval())
++                     .setIsAdd(1L);
++
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    @Override
++    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataBefore,
++                                        @Nonnull final Vesagent dataAfter, @Nonnull final WriteContext writeContext)
++        throws WriteFailedException {
++        Config configBefore = dataBefore.getConfig();
++        Config configAfter = dataAfter.getConfig();
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        InstanceIdentifier<Config> id = iid.child(Config.class);
++
++        checkArgument(configBefore.getServerAddr() != null && configBefore.getServerAddr().getValue() != null
++            && configBefore.getServerPort() != 0, "VES Server Address and Port need to be configured");
++        checkArgument(configAfter.getServerAddr() != null && configAfter.getServerAddr().getValue() != null
++            && configAfter.getServerPort() != 0, "VES Server Address and Port need to be configured");
++
++        // remove old configuration:
++        configBuilder.setServerAddr(configBefore.getServerAddr())
++                     .setServerPort(configBefore.getServerPort())
++                     .setReadInterval(configBefore.getReadInterval())
++                     .setIsAdd(0L);
++        setVesAgentConfig(id, configBuilder.build());
++
++        // and add new one:
++        configBuilder.setServerAddr(configAfter.getServerAddr())
++                     .setServerPort(configAfter.getServerPort())
++                     .setReadInterval(configAfter.getReadInterval())
++                     .setIsAdd(1L);
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    @Override
++    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataBefore,
++                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
++        Config config = dataBefore.getConfig();
++        InstanceIdentifier<Config> id = iid.child(Config.class);
++        LOG.debug("Removing VES Agent {} dataBefore={}", id, config);
++
++        checkArgument(config.getServerAddr() != null && config.getServerAddr().getValue() != null
++            && config.getServerPort() != 0, "VES Server Address and Port need to be configured");
++
++        ConfigBuilder configBuilder = new ConfigBuilder();
++        configBuilder.setServerAddr(config.getServerAddr())
++                     .setServerPort(config.getServerPort())
++                     .setReadInterval(config.getReadInterval())
++                     .setIsAdd(0L);
++
++        setVesAgentConfig(id, configBuilder.build());
++    }
++
++    private void setVesAgentConfig(final InstanceIdentifier<Config> id, final Config config)
++        throws WriteFailedException {
++        final VesAgentConfig request = new VesAgentConfig();
++
++        request.serverPort = config.getServerPort().byteValue();
++        request.readInterval = config.getReadInterval().byteValue();
++        request.isAdd = config.getIsAdd().byteValue();
++        request.serverAddr = ipv4AddressNoZoneToArray(config.getServerAddr().getValue());
++
++        LOG.debug("VES agent config change id={} request={}", id, request);
++        getReplyForWrite(jvppVes.vesAgentConfig(request).toCompletableFuture(), id);
++    }
++}
+diff --git a/vpp-integration/minimal-distribution/pom.xml b/vpp-integration/minimal-distribution/pom.xml
+index e126114a..ca0e5b24 100644
+--- a/vpp-integration/minimal-distribution/pom.xml
++++ b/vpp-integration/minimal-distribution/pom.xml
+@@ -40,6 +40,7 @@
+     <routing.version>1.17.04.1-SNAPSHOT</routing.version>
+     <acl.version>1.17.04.1-SNAPSHOT</acl.version>
+     <dhcp.version>1.17.04.1-SNAPSHOT</dhcp.version>
++    <vesagent.version>1.17.04.1-SNAPSHOT</vesagent.version>
+     <vpp.classifier.version>1.17.04.1-SNAPSHOT</vpp.classifier.version>
+     <l3-impl.version>1.17.04.1-SNAPSHOT</l3-impl.version>
+     <vpp-management-impl.version>1.17.04.1-SNAPSHOT</vpp-management-impl.version>
+@@ -63,6 +64,7 @@
+       io.fd.hc2vpp.routing.RoutingModule,
+       io.fd.hc2vpp.acl.AclModule,
+       io.fd.hc2vpp.dhcp.DhcpModule,
++      io.fd.hc2vpp.ves.VesModule,
+       io.fd.hc2vpp.policer.PolicerModule,
+       // io.fd.hc2vpp.vppnsh.impl.VppNshModule,
+       <!-- Nsh module by default disabled, because it needs vpp-nsh plugin, which is not part of vpp codebase.-->
+@@ -151,6 +153,11 @@
+       <version>${dhcp.version}</version>
+     </dependency>
+     <dependency>
++      <groupId>io.fd.hc2vpp.ves</groupId>
++      <artifactId>ves-impl</artifactId>
++      <version>${vesagent.version}</version>
++    </dependency>
++    <dependency>
+       <groupId>io.fd.hc2vpp.management</groupId>
+       <artifactId>vpp-management-impl</artifactId>
+       <version>${vpp-management-impl.version}</version>
+-- 
+2.12.2.windows.2
+
diff --git a/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch
new file mode 100644 (file)
index 0000000..edfb6a3
--- /dev/null
@@ -0,0 +1,7299 @@
+From 3d16acbb7942682864fd9b8ca9ca15e4147325f1 Mon Sep 17 00:00:00 2001
+From: Johnson Li <johnson.li@intel.com>
+Date: Fri, 22 Sep 2017 08:58:40 +0800
+Subject: [PATCH] Add VES Agent to report statistics
+
+Change Log:
+v2: Use VES 5.x as agent library
+v1: Add VES agent to report statistics
+
+Signed-off-by: Johnson Li <johnson.li@intel.com>
+
+diff --git a/src/configure.ac b/src/configure.ac
+index fb2ead6d..ea641525 100644
+--- a/src/configure.ac
++++ b/src/configure.ac
+@@ -154,6 +154,7 @@ PLUGIN_ENABLED(lb)
+ PLUGIN_ENABLED(memif)
+ PLUGIN_ENABLED(sixrd)
+ PLUGIN_ENABLED(snat)
++PLUGIN_ENABLED(ves)
+ ###############################################################################
+ # Dependency checks
+diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
+index 623892e7..84513755 100644
+--- a/src/plugins/Makefile.am
++++ b/src/plugins/Makefile.am
+@@ -69,6 +69,10 @@ if ENABLE_SNAT_PLUGIN
+ include snat.am
+ endif
++if ENABLE_VES_PLUGIN
++include ves.am
++endif
++
+ include ../suffix-rules.mk
+ # Remove *.la files
+diff --git a/src/plugins/ves.am b/src/plugins/ves.am
+new file mode 100644
+index 00000000..10f2194b
+--- /dev/null
++++ b/src/plugins/ves.am
+@@ -0,0 +1,35 @@
++# Copyright (c) <current-year> <your-organization>
++# Licensed under the Apache License, Version 2.0 (the "License");
++# you may not use this file except in compliance with the License.
++# You may obtain a copy of the License at:
++#
++#     http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++
++vppplugins_LTLIBRARIES += ves_plugin.la
++
++LIBS_DIR=$(CURDIR)/ves/libs
++ves_plugin_la_LDFLAGS = $(AM_LDFLAGS) -L$(LIBS_DIR)
++ves_plugin_la_LDFLAGS += -Wl,--whole-archive -level -Wl,--no-whole-archive
++ves_plugin_la_LDFLAGS += -Wl,-lpthread,-lcurl
++
++ves_plugin_la_SOURCES = ves/ves_node.c  \
++  ves/ves_api.c
++
++BUILT_SOURCES +=                      \
++  ves/ves.api.h                               \
++  ves/ves.api.json
++
++API_FILES += ves/ves.api
++
++nobase_apiinclude_HEADERS +=          \
++  ves/ves_all_api_h.h                 \
++  ves/ves_msg_enum.h                  \
++  ves/ves.api.h
++
++# vi:syntax=automake
+diff --git a/src/plugins/ves/include/double_list.h b/src/plugins/ves/include/double_list.h
+new file mode 100644
+index 00000000..5cf7e1af
+--- /dev/null
++++ b/src/plugins/ves/include/double_list.h
+@@ -0,0 +1,57 @@
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++/**************************************************************************//**
++ * @file
++ * A simple double-linked list.
++ *
++ * @note  No thread protection so you will need to use appropriate
++ * synchronization if use spans multiple threads.
++ *
++ ****************************************************************************/
++
++#ifndef DOUBLE_LIST_INCLUDED
++#define DOUBLE_LIST_INCLUDED
++
++typedef struct dlist_item
++{
++  struct dlist_item * previous;
++  struct dlist_item * next;
++  void * item;
++} DLIST_ITEM;
++
++/**************************************************************************//**
++ * Double-linked list structure
++ *****************************************************************************/
++typedef struct dlist
++{
++  DLIST_ITEM * head;
++  DLIST_ITEM * tail;
++} DLIST;
++
++
++void dlist_initialize(DLIST * list);
++void * dlist_pop_last(DLIST * list);
++void dlist_push_first(DLIST * list, void * item);
++void dlist_push_last(DLIST * list, void * item);
++DLIST_ITEM * dlist_get_first(DLIST * list);
++DLIST_ITEM * dlist_get_last(DLIST * list);
++DLIST_ITEM * dlist_get_next(DLIST_ITEM * item);
++int dlist_is_empty(DLIST * list);
++int dlist_count(DLIST * list);
++
++#endif
+diff --git a/src/plugins/ves/include/evel.h b/src/plugins/ves/include/evel.h
+new file mode 100644
+index 00000000..6aceec30
+--- /dev/null
++++ b/src/plugins/ves/include/evel.h
+@@ -0,0 +1,4494 @@
++#ifndef EVEL_INCLUDED
++#define EVEL_INCLUDED
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++/**************************************************************************//**
++ * @file
++ * Header for EVEL library
++ *
++ * This file implements the EVEL library which is intended to provide a
++ * simple wrapper around the complexity of AT&T's Vendor Event Listener API so
++ * that VNFs can use it without worrying about details of the API transport.
++ *
++ * Zero return value is success (::EVEL_SUCCESS), non-zero is failure and will
++ * be one of ::EVEL_ERR_CODES.
++ *****************************************************************************/
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdarg.h>
++#include <time.h>
++
++#include "jsmn.h"
++#include "double_list.h"
++#include "hashtable.h"
++
++/*****************************************************************************/
++/* Supported API version.                                                    */
++/*****************************************************************************/
++#define EVEL_API_MAJOR_VERSION 5
++#define EVEL_API_MINOR_VERSION 0
++
++/**************************************************************************//**
++ * Error codes
++ *
++ * Error codes for EVEL low level interface
++ *****************************************************************************/
++typedef enum {
++  EVEL_SUCCESS,                   /** The operation was successful.          */
++  EVEL_ERR_GEN_FAIL,              /** Non-specific failure.                  */
++  EVEL_CURL_LIBRARY_FAIL,         /** A cURL library operation failed.       */
++  EVEL_PTHREAD_LIBRARY_FAIL,      /** A Posix threads operation failed.      */
++  EVEL_OUT_OF_MEMORY,             /** A memory allocation failure occurred.  */
++  EVEL_EVENT_BUFFER_FULL,         /** Too many events in the ring-buffer.    */
++  EVEL_EVENT_HANDLER_INACTIVE,    /** Attempt to raise event when inactive.  */
++  EVEL_NO_METADATA,               /** Failed to retrieve OpenStack metadata. */
++  EVEL_BAD_METADATA,              /** OpenStack metadata invalid format.     */
++  EVEL_BAD_JSON_FORMAT,           /** JSON failed to parse correctly.        */
++  EVEL_JSON_KEY_NOT_FOUND,        /** Failed to find the specified JSON key. */
++  EVEL_MAX_ERROR_CODES            /** Maximum number of valid error codes.   */
++} EVEL_ERR_CODES;
++
++/**************************************************************************//**
++ * Logging levels
++ *
++ * Variable levels of verbosity in the logging functions.
++ *****************************************************************************/
++typedef enum {
++  EVEL_LOG_MIN               = 0,
++  EVEL_LOG_SPAMMY            = 30,
++  EVEL_LOG_DEBUG             = 40,
++  EVEL_LOG_INFO              = 50,
++  EVEL_LOG_ERROR             = 60,
++  EVEL_LOG_MAX               = 101
++} EVEL_LOG_LEVELS;
++
++/*****************************************************************************/
++/* Maximum string lengths.                                                   */
++/*****************************************************************************/
++#define EVEL_MAX_STRING_LEN          4096
++#define EVEL_MAX_JSON_BODY           16000
++#define EVEL_MAX_ERROR_STRING_LEN    255
++#define EVEL_MAX_URL_LEN             511
++
++/**************************************************************************//**
++ * This value represents there being no restriction on the reporting interval.
++ *****************************************************************************/
++static const int EVEL_MEASUREMENT_INTERVAL_UKNOWN = 0;
++
++/**************************************************************************//**
++ * How many events can be backed-up before we start dropping events on the
++ * floor.
++ *
++ * @note  This value should be tuned in accordance with expected burstiness of
++ *        the event load and the expected response time of the ECOMP event
++ *        listener so that the probability of the buffer filling is suitably
++ *        low.
++ *****************************************************************************/
++static const int EVEL_EVENT_BUFFER_DEPTH = 100;
++
++/*****************************************************************************/
++/* How many different IP Types-of-Service are supported.                     */
++/*****************************************************************************/
++#define EVEL_TOS_SUPPORTED      256
++
++/**************************************************************************//**
++ * Event domains for the various events we support.
++ * JSON equivalent field: domain
++ *****************************************************************************/
++typedef enum {
++  EVEL_DOMAIN_INTERNAL,       /** Internal event, not for external routing.  */
++  EVEL_DOMAIN_HEARTBEAT,      /** A Heartbeat event (event header only).     */
++  EVEL_DOMAIN_FAULT,          /** A Fault event.                             */
++  EVEL_DOMAIN_MEASUREMENT,    /** A Measurement for VF Scaling event.        */
++  EVEL_DOMAIN_MOBILE_FLOW,    /** A Mobile Flow event.                       */
++  EVEL_DOMAIN_REPORT,         /** A Measurement for VF Reporting event.      */
++  EVEL_DOMAIN_HEARTBEAT_FIELD,/** A Heartbeat field event.                   */
++  EVEL_DOMAIN_SIPSIGNALING,   /** A Signaling event.                         */
++  EVEL_DOMAIN_STATE_CHANGE,   /** A State Change event.                      */
++  EVEL_DOMAIN_SYSLOG,         /** A Syslog event.                            */
++  EVEL_DOMAIN_OTHER,          /** Another event.                             */
++  EVEL_DOMAIN_THRESHOLD_CROSS,  /** A Threshold Crossing  Event                    */
++  EVEL_DOMAIN_VOICE_QUALITY,  /** A Voice Quality Event                            */
++  EVEL_MAX_DOMAINS            /** Maximum number of recognized Event types.  */
++} EVEL_EVENT_DOMAINS;
++
++/**************************************************************************//**
++ * Event priorities.
++ * JSON equivalent field: priority
++ *****************************************************************************/
++typedef enum {
++  EVEL_PRIORITY_HIGH,
++  EVEL_PRIORITY_MEDIUM,
++  EVEL_PRIORITY_NORMAL,
++  EVEL_PRIORITY_LOW,
++  EVEL_MAX_PRIORITIES
++} EVEL_EVENT_PRIORITIES;
++
++/**************************************************************************//**
++ * Fault / Threshold severities.
++ * JSON equivalent field: eventSeverity
++ *****************************************************************************/
++typedef enum {
++  EVEL_SEVERITY_CRITICAL,
++  EVEL_SEVERITY_MAJOR,
++  EVEL_SEVERITY_MINOR,
++  EVEL_SEVERITY_WARNING,
++  EVEL_SEVERITY_NORMAL,
++  EVEL_MAX_SEVERITIES
++} EVEL_SEVERITIES;
++
++/**************************************************************************//**
++ * Fault source types.
++ * JSON equivalent field: eventSourceType
++ *****************************************************************************/
++typedef enum {
++  EVEL_SOURCE_OTHER,
++  EVEL_SOURCE_ROUTER,
++  EVEL_SOURCE_SWITCH,
++  EVEL_SOURCE_HOST,
++  EVEL_SOURCE_CARD,
++  EVEL_SOURCE_PORT,
++  EVEL_SOURCE_SLOT_THRESHOLD,
++  EVEL_SOURCE_PORT_THRESHOLD,
++  EVEL_SOURCE_VIRTUAL_MACHINE,
++  EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION,
++  /***************************************************************************/
++  /* START OF VENDOR-SPECIFIC VALUES                                         */
++  /*                                                                         */
++  /* Vendor-specific values should be added here, and handled appropriately  */
++  /* in evel_event.c.                                                        */
++  /***************************************************************************/
++
++  /***************************************************************************/
++  /* END OF VENDOR-SPECIFIC VALUES                                           */
++  /***************************************************************************/
++  EVEL_MAX_SOURCE_TYPES
++} EVEL_SOURCE_TYPES;
++
++/**************************************************************************//**
++ * Fault VNF Status.
++ * JSON equivalent field: vfStatus
++ *****************************************************************************/
++typedef enum {
++  EVEL_VF_STATUS_ACTIVE,
++  EVEL_VF_STATUS_IDLE,
++  EVEL_VF_STATUS_PREP_TERMINATE,
++  EVEL_VF_STATUS_READY_TERMINATE,
++  EVEL_VF_STATUS_REQ_TERMINATE,
++  EVEL_MAX_VF_STATUSES
++} EVEL_VF_STATUSES;
++
++/**************************************************************************//**
++ * Counter criticalities.
++ * JSON equivalent field: criticality
++ *****************************************************************************/
++typedef enum {
++  EVEL_COUNTER_CRITICALITY_CRIT,
++  EVEL_COUNTER_CRITICALITY_MAJ,
++  EVEL_MAX_COUNTER_CRITICALITIES
++} EVEL_COUNTER_CRITICALITIES;
++
++/**************************************************************************//**
++ * Alert actions.
++ * JSON equivalent field: alertAction
++ *****************************************************************************/
++typedef enum {
++  EVEL_ALERT_ACTION_CLEAR,
++  EVEL_ALERT_ACTION_CONT,
++  EVEL_ALERT_ACTION_SET,
++  EVEL_MAX_ALERT_ACTIONS
++} EVEL_ALERT_ACTIONS;
++
++/**************************************************************************//**
++ * Alert types.
++ * JSON equivalent field: alertType
++ *****************************************************************************/
++typedef enum {
++  EVEL_ALERT_TYPE_CARD,
++  EVEL_ALERT_TYPE_ELEMENT,
++  EVEL_ALERT_TYPE_INTERFACE,
++  EVEL_ALERT_TYPE_SERVICE,
++  EVEL_MAX_ALERT_TYPES
++} EVEL_ALERT_TYPES;
++
++/**************************************************************************//**
++ * Alert types.
++ * JSON equivalent fields: newState, oldState
++ *****************************************************************************/
++typedef enum {
++  EVEL_ENTITY_STATE_IN_SERVICE,
++  EVEL_ENTITY_STATE_MAINTENANCE,
++  EVEL_ENTITY_STATE_OUT_OF_SERVICE,
++  EVEL_MAX_ENTITY_STATES
++} EVEL_ENTITY_STATE;
++
++/**************************************************************************//**
++ * Syslog facilities.
++ * JSON equivalent field: syslogFacility
++ *****************************************************************************/
++typedef enum {
++  EVEL_SYSLOG_FACILITY_KERNEL,
++  EVEL_SYSLOG_FACILITY_USER,
++  EVEL_SYSLOG_FACILITY_MAIL,
++  EVEL_SYSLOG_FACILITY_SYSTEM_DAEMON,
++  EVEL_SYSLOG_FACILITY_SECURITY_AUTH,
++  EVEL_SYSLOG_FACILITY_INTERNAL,
++  EVEL_SYSLOG_FACILITY_LINE_PRINTER,
++  EVEL_SYSLOG_FACILITY_NETWORK_NEWS,
++  EVEL_SYSLOG_FACILITY_UUCP,
++  EVEL_SYSLOG_FACILITY_CLOCK_DAEMON,
++  EVEL_SYSLOG_FACILITY_SECURITY_AUTH2,
++  EVEL_SYSLOG_FACILITY_FTP_DAEMON,
++  EVEL_SYSLOG_FACILITY_NTP,
++  EVEL_SYSLOG_FACILITY_LOG_AUDIT,
++  EVEL_SYSLOG_FACILITY_LOG_ALERT,
++  EVEL_SYSLOG_FACILITY_CLOCK_DAEMON2,
++  EVEL_SYSLOG_FACILITY_LOCAL0,
++  EVEL_SYSLOG_FACILITY_LOCAL1,
++  EVEL_SYSLOG_FACILITY_LOCAL2,
++  EVEL_SYSLOG_FACILITY_LOCAL3,
++  EVEL_SYSLOG_FACILITY_LOCAL4,
++  EVEL_SYSLOG_FACILITY_LOCAL5,
++  EVEL_SYSLOG_FACILITY_LOCAL6,
++  EVEL_SYSLOG_FACILITY_LOCAL7,
++  EVEL_MAX_SYSLOG_FACILITIES
++} EVEL_SYSLOG_FACILITIES;
++
++/**************************************************************************//**
++ * TCP flags.
++ * JSON equivalent fields: tcpFlagCountList, tcpFlagList
++ *****************************************************************************/
++typedef enum {
++  EVEL_TCP_NS,
++  EVEL_TCP_CWR,
++  EVEL_TCP_ECE,
++  EVEL_TCP_URG,
++  EVEL_TCP_ACK,
++  EVEL_TCP_PSH,
++  EVEL_TCP_RST,
++  EVEL_TCP_SYN,
++  EVEL_TCP_FIN,
++  EVEL_MAX_TCP_FLAGS
++} EVEL_TCP_FLAGS;
++
++/**************************************************************************//**
++ * Mobile QCI Classes of Service.
++ * JSON equivalent fields: mobileQciCosCountList, mobileQciCosList
++ *****************************************************************************/
++typedef enum {
++
++  /***************************************************************************/
++  /* UMTS Classes of Service.                                                */
++  /***************************************************************************/
++  EVEL_QCI_COS_UMTS_CONVERSATIONAL,
++  EVEL_QCI_COS_UMTS_STREAMING,
++  EVEL_QCI_COS_UMTS_INTERACTIVE,
++  EVEL_QCI_COS_UMTS_BACKGROUND,
++
++  /***************************************************************************/
++  /* LTE Classes of Service.                                                 */
++  /***************************************************************************/
++  EVEL_QCI_COS_LTE_1,
++  EVEL_QCI_COS_LTE_2,
++  EVEL_QCI_COS_LTE_3,
++  EVEL_QCI_COS_LTE_4,
++  EVEL_QCI_COS_LTE_65,
++  EVEL_QCI_COS_LTE_66,
++  EVEL_QCI_COS_LTE_5,
++  EVEL_QCI_COS_LTE_6,
++  EVEL_QCI_COS_LTE_7,
++  EVEL_QCI_COS_LTE_8,
++  EVEL_QCI_COS_LTE_9,
++  EVEL_QCI_COS_LTE_69,
++  EVEL_QCI_COS_LTE_70,
++  EVEL_MAX_QCI_COS_TYPES
++} EVEL_QCI_COS_TYPES;
++
++/**************************************************************************//**
++ * Service Event endpoint description
++ * JSON equivalent field: endpointDesc
++ *****************************************************************************/
++typedef enum {
++  EVEL_SERVICE_ENDPOINT_CALLEE,
++  EVEL_SERVICE_ENDPOINT_CALLER,
++  EVEL_MAX_SERVICE_ENDPOINT_DESC
++} EVEL_SERVICE_ENDPOINT_DESC;
++
++/**************************************************************************//**
++ * Boolean type for EVEL library.
++ *****************************************************************************/
++typedef enum {
++  EVEL_FALSE,
++  EVEL_TRUE
++} EVEL_BOOLEAN;
++
++/**************************************************************************//**
++ * Optional parameter holder for double.
++ *****************************************************************************/
++typedef struct evel_option_double
++{
++  double value;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_DOUBLE;
++
++/**************************************************************************//**
++ * Optional parameter holder for string.
++ *****************************************************************************/
++typedef struct evel_option_string
++{
++  char * value;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_STRING;
++
++/**************************************************************************//**
++ * Optional parameter holder for int.
++ *****************************************************************************/
++typedef struct evel_option_int
++{
++  int value;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_INT;
++
++/**************************************************************************//**
++ * Optional parameter holder for unsigned long long.
++ *****************************************************************************/
++typedef struct evel_option_ull
++{
++  unsigned long long value;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_ULL;
++
++/**************************************************************************//**
++ * Optional parameter holder for time_t.
++ *****************************************************************************/
++typedef struct evel_option_time
++{
++  time_t value;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_TIME;
++
++/**************************************************************************//**
++ * enrichment fields for internal VES Event Listener service use only,
++ * not supplied by event sources
++ *****************************************************************************/
++typedef struct internal_header_fields
++{
++  void *object;
++  EVEL_BOOLEAN is_set;
++} EVEL_OPTION_INTHEADER_FIELDS;
++
++/*****************************************************************************/
++/* Supported Common Event Header version.                                    */
++/*****************************************************************************/
++#define EVEL_HEADER_MAJOR_VERSION 1
++#define EVEL_HEADER_MINOR_VERSION 2
++
++/**************************************************************************//**
++ * Event header.
++ * JSON equivalent field: commonEventHeader
++ *****************************************************************************/
++typedef struct event_header {
++  /***************************************************************************/
++  /* Version                                                                 */
++  /***************************************************************************/
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  EVEL_EVENT_DOMAINS event_domain;
++  char * event_id;
++  char * event_name;
++  char * source_name;
++  char * reporting_entity_name;
++  EVEL_EVENT_PRIORITIES priority;
++  unsigned long long start_epoch_microsec;
++  unsigned long long last_epoch_microsec;
++  int sequence;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_STRING event_type;
++  EVEL_OPTION_STRING source_id;
++  EVEL_OPTION_STRING reporting_entity_id;
++  EVEL_OPTION_INTHEADER_FIELDS internal_field;
++  EVEL_OPTION_STRING nfcnaming_code;
++  EVEL_OPTION_STRING nfnaming_code;
++
++} EVENT_HEADER;
++
++/*****************************************************************************/
++/* Supported Fault version.                                                  */
++/*****************************************************************************/
++#define EVEL_FAULT_MAJOR_VERSION 2
++#define EVEL_FAULT_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Fault.
++ * JSON equivalent field: faultFields
++ *****************************************************************************/
++typedef struct event_fault {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  EVEL_SEVERITIES event_severity;
++  EVEL_SOURCE_TYPES event_source_type;
++  char * alarm_condition;
++  char * specific_problem;
++  EVEL_VF_STATUSES vf_status;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_STRING category;
++  EVEL_OPTION_STRING alarm_interface_a;
++  DLIST additional_info;
++
++} EVENT_FAULT;
++
++/**************************************************************************//**
++ * Fault Additional Info.
++ * JSON equivalent field: alarmAdditionalInformation
++ *****************************************************************************/
++typedef struct fault_additional_info {
++  char * name;
++  char * value;
++} FAULT_ADDL_INFO;
++
++
++/**************************************************************************//**
++ * optional field block for fields specific to heartbeat events
++ *****************************************************************************/
++typedef struct event_heartbeat_fields
++{
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  double heartbeat_version;
++  int    heartbeat_interval;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  DLIST additional_info;
++
++} EVENT_HEARTBEAT_FIELD;
++
++/**************************************************************************//**
++ * tuple which provides the name of a key along with its value and
++ * relative order
++ *****************************************************************************/
++typedef struct internal_key
++{
++  char                *keyname;
++  EVEL_OPTION_INT      keyorder;
++  EVEL_OPTION_STRING   keyvalue;
++} EVEL_INTERNAL_KEY;
++
++/**************************************************************************//**
++ * meta-information about an instance of a jsonObject along with
++ * the actual object instance
++ *****************************************************************************/
++typedef struct json_object_instance
++{
++
++  char *jsonstring;
++  unsigned long long objinst_epoch_microsec;
++  DLIST object_keys; /*EVEL_INTERNAL_KEY list */
++
++} EVEL_JSON_OBJECT_INSTANCE;
++#define MAX_JSON_TOKENS 128
++/**************************************************************************//**
++ * Create a new json object instance.
++ *
++ * @note    The mandatory fields on the Other must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Other has immutable properties.
++ * @param   yourjson       json string.
++ * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT_INSTANCE.
++ *          not used (i.e. posted) it must be released using ::evel_free_jsonobjectinstance.
++ * @retval  NULL  Failed to create the json object instance.
++ *****************************************************************************/
++EVEL_JSON_OBJECT_INSTANCE * evel_new_jsonobjinstance(const char *const yourjson);
++/**************************************************************************//**
++ * Free an json object instance.
++ *
++ * Free off the json object instance supplied.
++ *  Will free all the contained allocated memory.
++ *
++ *****************************************************************************/
++void evel_free_jsonobjinst(EVEL_JSON_OBJECT_INSTANCE * objinst);
++
++/**************************************************************************//**
++ * enrichment fields for internal VES Event Listener service use only,
++ * not supplied by event sources
++ *****************************************************************************/
++typedef struct json_object
++{
++
++  char *object_name;
++  EVEL_OPTION_STRING objectschema;
++  EVEL_OPTION_STRING objectschemaurl;
++  EVEL_OPTION_STRING nfsubscribedobjname;
++  EVEL_OPTION_STRING nfsubscriptionid;
++  DLIST jsonobjectinstances;  /* EVEL_JSON_OBJECT_INSTANCE list */
++
++} EVEL_JSON_OBJECT;
++
++/**************************************************************************//**
++ * Create a new json object.
++ *
++ * @note    The mandatory fields on the Other must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Other has immutable properties.
++ * @param name       name of the object.
++ * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT.
++ *          not used (i.e. posted) it must be released using ::evel_free_jsonobject.
++ * @retval  NULL  Failed to create the json object.
++ *****************************************************************************/
++EVEL_JSON_OBJECT * evel_new_jsonobject(const char *const name);
++/**************************************************************************//**
++ * Free an json object.
++ *
++ * Free off the json object instance supplied.
++ *  Will free all the contained allocated memory.
++ *
++ *****************************************************************************/
++void evel_free_jsonobject(EVEL_JSON_OBJECT * jsobj);
++/*****************************************************************************/
++/* Supported Measurement version.                                            */
++/*****************************************************************************/
++#define EVEL_MEASUREMENT_MAJOR_VERSION 2
++#define EVEL_MEASUREMENT_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Errors.
++ * JSON equivalent field: errors
++ *****************************************************************************/
++typedef struct measurement_errors {
++  int receive_discards;
++  int receive_errors;
++  int transmit_discards;
++  int transmit_errors;
++} MEASUREMENT_ERRORS;
++
++/**************************************************************************//**
++ * Measurement.
++ * JSON equivalent field: measurementsForVfScalingFields
++ *****************************************************************************/
++typedef struct event_measurement {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  double measurement_interval;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  DLIST additional_info;
++  DLIST additional_measurements;
++  DLIST additional_objects;
++  DLIST codec_usage;
++  EVEL_OPTION_INT concurrent_sessions;
++  EVEL_OPTION_INT configured_entities;
++  DLIST cpu_usage;
++  DLIST disk_usage;
++  MEASUREMENT_ERRORS * errors;
++  DLIST feature_usage;
++  DLIST filesystem_usage;
++  DLIST latency_distribution;
++  EVEL_OPTION_DOUBLE mean_request_latency;
++  DLIST mem_usage;
++  EVEL_OPTION_INT media_ports_in_use;
++  EVEL_OPTION_INT request_rate;
++  EVEL_OPTION_INT vnfc_scaling_metric;
++  DLIST vnic_usage;
++
++} EVENT_MEASUREMENT;
++
++/**************************************************************************//**
++ * CPU Usage.
++ * JSON equivalent field: cpuUsage
++ *****************************************************************************/
++typedef struct measurement_cpu_use {
++  char * id;
++  double usage;
++  EVEL_OPTION_DOUBLE idle;
++  EVEL_OPTION_DOUBLE intrpt;
++  EVEL_OPTION_DOUBLE nice;
++  EVEL_OPTION_DOUBLE softirq;
++  EVEL_OPTION_DOUBLE steal;
++  EVEL_OPTION_DOUBLE sys;
++  EVEL_OPTION_DOUBLE user;
++  EVEL_OPTION_DOUBLE wait;
++} MEASUREMENT_CPU_USE;
++
++
++/**************************************************************************//**
++ * Disk Usage.
++ * JSON equivalent field: diskUsage
++ *****************************************************************************/
++typedef struct measurement_disk_use {
++  char * id;
++  EVEL_OPTION_DOUBLE iotimeavg;
++  EVEL_OPTION_DOUBLE iotimelast;
++  EVEL_OPTION_DOUBLE iotimemax;
++  EVEL_OPTION_DOUBLE iotimemin;
++  EVEL_OPTION_DOUBLE mergereadavg;
++  EVEL_OPTION_DOUBLE mergereadlast;
++  EVEL_OPTION_DOUBLE mergereadmax;
++  EVEL_OPTION_DOUBLE mergereadmin;
++  EVEL_OPTION_DOUBLE mergewriteavg;
++  EVEL_OPTION_DOUBLE mergewritelast;
++  EVEL_OPTION_DOUBLE mergewritemax;
++  EVEL_OPTION_DOUBLE mergewritemin;
++  EVEL_OPTION_DOUBLE octetsreadavg;
++  EVEL_OPTION_DOUBLE octetsreadlast;
++  EVEL_OPTION_DOUBLE octetsreadmax;
++  EVEL_OPTION_DOUBLE octetsreadmin;
++  EVEL_OPTION_DOUBLE octetswriteavg;
++  EVEL_OPTION_DOUBLE octetswritelast;
++  EVEL_OPTION_DOUBLE octetswritemax;
++  EVEL_OPTION_DOUBLE octetswritemin;
++  EVEL_OPTION_DOUBLE opsreadavg;
++  EVEL_OPTION_DOUBLE opsreadlast;
++  EVEL_OPTION_DOUBLE opsreadmax;
++  EVEL_OPTION_DOUBLE opsreadmin;
++  EVEL_OPTION_DOUBLE opswriteavg;
++  EVEL_OPTION_DOUBLE opswritelast;
++  EVEL_OPTION_DOUBLE opswritemax;
++  EVEL_OPTION_DOUBLE opswritemin;
++  EVEL_OPTION_DOUBLE pendingopsavg;
++  EVEL_OPTION_DOUBLE pendingopslast;
++  EVEL_OPTION_DOUBLE pendingopsmax;
++  EVEL_OPTION_DOUBLE pendingopsmin;
++  EVEL_OPTION_DOUBLE timereadavg;
++  EVEL_OPTION_DOUBLE timereadlast;
++  EVEL_OPTION_DOUBLE timereadmax;
++  EVEL_OPTION_DOUBLE timereadmin;
++  EVEL_OPTION_DOUBLE timewriteavg;
++  EVEL_OPTION_DOUBLE timewritelast;
++  EVEL_OPTION_DOUBLE timewritemax;
++  EVEL_OPTION_DOUBLE timewritemin;
++
++} MEASUREMENT_DISK_USE;
++
++/**************************************************************************//**
++ * Add an additional Disk usage value name/value pair to the Measurement.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement   Pointer to the measurement.
++ * @param id            ASCIIZ string with the CPU's identifier.
++ * @param usage         Disk utilization.
++ *****************************************************************************/
++MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * measurement, char * id);
++
++/**************************************************************************//**
++ * Filesystem Usage.
++ * JSON equivalent field: filesystemUsage
++ *****************************************************************************/
++typedef struct measurement_fsys_use {
++  char * filesystem_name;
++  double block_configured;
++  int block_iops;
++  double block_used;
++  double ephemeral_configured;
++  int ephemeral_iops;
++  double ephemeral_used;
++} MEASUREMENT_FSYS_USE;
++
++/**************************************************************************//**
++ * Memory Usage.
++ * JSON equivalent field: memoryUsage
++ *****************************************************************************/
++typedef struct measurement_mem_use {
++  char * id;
++  char * vmid;
++  double membuffsz;
++  EVEL_OPTION_DOUBLE memcache;
++  EVEL_OPTION_DOUBLE memconfig;
++  EVEL_OPTION_DOUBLE memfree;
++  EVEL_OPTION_DOUBLE slabrecl;
++  EVEL_OPTION_DOUBLE slabunrecl;
++  EVEL_OPTION_DOUBLE memused;
++} MEASUREMENT_MEM_USE;
++
++/**************************************************************************//**
++ * Add an additional Memory usage value name/value pair to the Measurement.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement   Pointer to the measurement.
++ * @param id            ASCIIZ string with the Memory identifier.
++ * @param vmidentifier  ASCIIZ string with the VM's identifier.
++ * @param membuffsz     Memory Size.
++ *
++ * @return  Returns pointer to memory use structure in measurements
++ *****************************************************************************/
++MEASUREMENT_MEM_USE * evel_measurement_new_mem_use_add(EVENT_MEASUREMENT * measurement,
++                                 char * id,  char *vmidentifier,  double membuffsz);
++
++/**************************************************************************//**
++ * Set kilobytes of memory used for cache
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_memcache_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set kilobytes of memory configured in the virtual machine on which the VNFC reporting
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_memconfig_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set kilobytes of physical RAM left unused by the system
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_memfree_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the part of the slab that can be reclaimed such as caches measured in kilobytes
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_slab_reclaimed_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the part of the slab that cannot be reclaimed such as caches measured in kilobytes
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_slab_unreclaimable_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the total memory minus the sum of free, buffered, cached and slab memory in kilobytes
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mem_use      Pointer to the Memory Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_mem_use_usedup_set(MEASUREMENT_MEM_USE * const mem_use,
++                                    const double val);
++/**************************************************************************//**
++ * Latency Bucket.
++ * JSON equivalent field: latencyBucketMeasure
++ *****************************************************************************/
++typedef struct measurement_latency_bucket {
++  int count;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_DOUBLE high_end;
++  EVEL_OPTION_DOUBLE low_end;
++
++} MEASUREMENT_LATENCY_BUCKET;
++
++/**************************************************************************//**
++ * Virtual NIC usage.
++ * JSON equivalent field: vNicUsage
++ *****************************************************************************/
++typedef struct measurement_vnic_performance {
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  /*Cumulative count of broadcast packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_bcast_packets_acc;
++  /*Count of broadcast packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_bcast_packets_delta;
++  /*Cumulative count of discarded packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_discarded_packets_acc;
++  /*Count of discarded packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_discarded_packets_delta;
++  /*Cumulative count of error packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_error_packets_acc;
++  /*Count of error packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_error_packets_delta;
++  /*Cumulative count of multicast packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_mcast_packets_acc;
++  /*Count of mcast packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_mcast_packets_delta;
++  /*Cumulative count of octets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_octets_acc;
++  /*Count of octets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_octets_delta;
++  /*Cumulative count of all packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_total_packets_acc;
++  /*Count of all packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_total_packets_delta;
++  /*Cumulative count of unicast packets received as read at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_ucast_packets_acc;
++  /*Count of unicast packets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE recvd_ucast_packets_delta;
++  /*Cumulative count of transmitted broadcast packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_bcast_packets_acc;
++  /*Count of transmitted broadcast packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_bcast_packets_delta;
++  /*Cumulative count of transmit discarded packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_discarded_packets_acc;
++  /*Count of transmit discarded packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_discarded_packets_delta;
++  /*Cumulative count of transmit error packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_error_packets_acc;
++  /*Count of transmit error packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_error_packets_delta;
++  /*Cumulative count of transmit multicast packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_mcast_packets_acc;
++  /*Count of transmit multicast packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_mcast_packets_delta;
++  /*Cumulative count of transmit octets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_octets_acc;
++  /*Count of transmit octets received within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_octets_delta;
++  /*Cumulative count of all transmit packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_total_packets_acc;
++  /*Count of transmit packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_total_packets_delta;
++  /*Cumulative count of all transmit unicast packets at the end of
++   the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_ucast_packets_acc;
++  /*Count of transmit unicast packets within the measurement interval*/
++  EVEL_OPTION_DOUBLE tx_ucast_packets_delta;
++  /* Indicates whether vNicPerformance values are likely inaccurate
++           due to counter overflow or other condtions*/
++  char *valuesaresuspect;
++  char *vnic_id;
++
++} MEASUREMENT_VNIC_PERFORMANCE;
++
++/**************************************************************************//**
++ * Codec Usage.
++ * JSON equivalent field: codecsInUse
++ *****************************************************************************/
++typedef struct measurement_codec_use {
++  char * codec_id;
++  int number_in_use;
++} MEASUREMENT_CODEC_USE;
++
++/**************************************************************************//**
++ * Feature Usage.
++ * JSON equivalent field: featuresInUse
++ *****************************************************************************/
++typedef struct measurement_feature_use {
++  char * feature_id;
++  int feature_utilization;
++} MEASUREMENT_FEATURE_USE;
++
++/**************************************************************************//**
++ * Measurement Group.
++ * JSON equivalent field: additionalMeasurements
++ *****************************************************************************/
++typedef struct measurement_group {
++  char * name;
++  DLIST measurements;
++} MEASUREMENT_GROUP;
++
++/**************************************************************************//**
++ * Custom Defined Measurement.
++ * JSON equivalent field: measurements
++ *****************************************************************************/
++typedef struct custom_measurement {
++  char * name;
++  char * value;
++} CUSTOM_MEASUREMENT;
++
++/*****************************************************************************/
++/* Supported Report version.                                                 */
++/*****************************************************************************/
++#define EVEL_REPORT_MAJOR_VERSION 1
++#define EVEL_REPORT_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Report.
++ * JSON equivalent field: measurementsForVfReportingFields
++ *
++ * @note  This is an experimental event type and is not currently a formal part
++ *        of AT&T's specification.
++ *****************************************************************************/
++typedef struct event_report {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  double measurement_interval;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  DLIST feature_usage;
++  DLIST measurement_groups;
++
++} EVENT_REPORT;
++
++/**************************************************************************//**
++ * Mobile GTP Per Flow Metrics.
++ * JSON equivalent field: gtpPerFlowMetrics
++ *****************************************************************************/
++typedef struct mobile_gtp_per_flow_metrics {
++  double avg_bit_error_rate;
++  double avg_packet_delay_variation;
++  int avg_packet_latency;
++  int avg_receive_throughput;
++  int avg_transmit_throughput;
++  int flow_activation_epoch;
++  int flow_activation_microsec;
++  int flow_deactivation_epoch;
++  int flow_deactivation_microsec;
++  time_t flow_deactivation_time;
++  char * flow_status;
++  int max_packet_delay_variation;
++  int num_activation_failures;
++  int num_bit_errors;
++  int num_bytes_received;
++  int num_bytes_transmitted;
++  int num_dropped_packets;
++  int num_l7_bytes_received;
++  int num_l7_bytes_transmitted;
++  int num_lost_packets;
++  int num_out_of_order_packets;
++  int num_packet_errors;
++  int num_packets_received_excl_retrans;
++  int num_packets_received_incl_retrans;
++  int num_packets_transmitted_incl_retrans;
++  int num_retries;
++  int num_timeouts;
++  int num_tunneled_l7_bytes_received;
++  int round_trip_time;
++  int time_to_first_byte;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_INT ip_tos_counts[EVEL_TOS_SUPPORTED];
++  EVEL_OPTION_INT tcp_flag_counts[EVEL_MAX_TCP_FLAGS];
++  EVEL_OPTION_INT qci_cos_counts[EVEL_MAX_QCI_COS_TYPES];
++  EVEL_OPTION_INT dur_connection_failed_status;
++  EVEL_OPTION_INT dur_tunnel_failed_status;
++  EVEL_OPTION_STRING flow_activated_by;
++  EVEL_OPTION_TIME flow_activation_time;
++  EVEL_OPTION_STRING flow_deactivated_by;
++  EVEL_OPTION_STRING gtp_connection_status;
++  EVEL_OPTION_STRING gtp_tunnel_status;
++  EVEL_OPTION_INT large_packet_rtt;
++  EVEL_OPTION_DOUBLE large_packet_threshold;
++  EVEL_OPTION_INT max_receive_bit_rate;
++  EVEL_OPTION_INT max_transmit_bit_rate;
++  EVEL_OPTION_INT num_gtp_echo_failures;
++  EVEL_OPTION_INT num_gtp_tunnel_errors;
++  EVEL_OPTION_INT num_http_errors;
++
++} MOBILE_GTP_PER_FLOW_METRICS;
++
++/*****************************************************************************/
++/* Supported Mobile Flow version.                                            */
++/*****************************************************************************/
++#define EVEL_MOBILE_FLOW_MAJOR_VERSION 1
++#define EVEL_MOBILE_FLOW_MINOR_VERSION 2
++
++/**************************************************************************//**
++ * Mobile Flow.
++ * JSON equivalent field: mobileFlow
++ *****************************************************************************/
++typedef struct event_mobile_flow {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  char * flow_direction;
++  MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics;
++  char * ip_protocol_type;
++  char * ip_version;
++  char * other_endpoint_ip_address;
++  int other_endpoint_port;
++  char * reporting_endpoint_ip_addr;
++  int reporting_endpoint_port;
++  DLIST additional_info;                         /* JSON: additionalFields */
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_STRING application_type;
++  EVEL_OPTION_STRING app_protocol_type;
++  EVEL_OPTION_STRING app_protocol_version;
++  EVEL_OPTION_STRING cid;
++  EVEL_OPTION_STRING connection_type;
++  EVEL_OPTION_STRING ecgi;
++  EVEL_OPTION_STRING gtp_protocol_type;
++  EVEL_OPTION_STRING gtp_version;
++  EVEL_OPTION_STRING http_header;
++  EVEL_OPTION_STRING imei;
++  EVEL_OPTION_STRING imsi;
++  EVEL_OPTION_STRING lac;
++  EVEL_OPTION_STRING mcc;
++  EVEL_OPTION_STRING mnc;
++  EVEL_OPTION_STRING msisdn;
++  EVEL_OPTION_STRING other_functional_role;
++  EVEL_OPTION_STRING rac;
++  EVEL_OPTION_STRING radio_access_technology;
++  EVEL_OPTION_STRING sac;
++  EVEL_OPTION_INT sampling_algorithm;
++  EVEL_OPTION_STRING tac;
++  EVEL_OPTION_STRING tunnel_id;
++  EVEL_OPTION_STRING vlan_id;
++
++} EVENT_MOBILE_FLOW;
++
++/*****************************************************************************/
++/* Supported Other field version.                                            */
++/*****************************************************************************/
++#define EVEL_OTHER_EVENT_MAJOR_VERSION 1
++#define EVEL_OTHER_EVENT_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Other.
++ * JSON equivalent field: otherFields
++ *****************************************************************************/
++typedef struct event_other {
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  HASHTABLE_T *namedarrays; /* HASHTABLE_T */
++  DLIST jsonobjects; /* DLIST of EVEL_JSON_OBJECT */
++  DLIST namedvalues;
++} EVENT_OTHER;
++
++/**************************************************************************//**
++ * Other Field.
++ * JSON equivalent field: otherFields
++ *****************************************************************************/
++typedef struct other_field {
++  char * name;
++  char * value;
++} OTHER_FIELD;
++
++
++/*****************************************************************************/
++/* Supported Service Events version.                                         */
++/*****************************************************************************/
++#define EVEL_HEARTBEAT_FIELD_MAJOR_VERSION 1
++#define EVEL_HEARTBEAT_FIELD_MINOR_VERSION 1
++
++
++/*****************************************************************************/
++/* Supported Signaling version.                                              */
++/*****************************************************************************/
++#define EVEL_SIGNALING_MAJOR_VERSION 2
++#define EVEL_SIGNALING_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Vendor VNF Name fields.
++ * JSON equivalent field: vendorVnfNameFields
++ *****************************************************************************/
++typedef struct vendor_vnfname_field {
++  char * vendorname;
++  EVEL_OPTION_STRING vfmodule;
++  EVEL_OPTION_STRING vnfname;
++} VENDOR_VNFNAME_FIELD;
++
++/**************************************************************************//**
++ * Signaling.
++ * JSON equivalent field: signalingFields
++ *****************************************************************************/
++typedef struct event_signaling {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  VENDOR_VNFNAME_FIELD vnfname_field;
++  EVEL_OPTION_STRING correlator;                         /* JSON: correlator */
++  EVEL_OPTION_STRING local_ip_address;               /* JSON: localIpAddress */
++  EVEL_OPTION_STRING local_port;                          /* JSON: localPort */
++  EVEL_OPTION_STRING remote_ip_address;             /* JSON: remoteIpAddress */
++  EVEL_OPTION_STRING remote_port;                        /* JSON: remotePort */
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_STRING compressed_sip;                  /* JSON: compressedSip */
++  EVEL_OPTION_STRING summary_sip;                        /* JSON: summarySip */
++  DLIST additional_info;
++
++} EVENT_SIGNALING;
++
++/**************************************************************************//**
++ * Sgnaling Additional Field.
++ * JSON equivalent field: additionalFields
++ *****************************************************************************/
++typedef struct signaling_additional_field {
++  char * name;
++  char * value;
++} SIGNALING_ADDL_FIELD;
++
++/*****************************************************************************/
++/* Supported State Change version.                                           */
++/*****************************************************************************/
++#define EVEL_STATE_CHANGE_MAJOR_VERSION 1
++#define EVEL_STATE_CHANGE_MINOR_VERSION 2
++
++/**************************************************************************//**
++ * State Change.
++ * JSON equivalent field: stateChangeFields
++ *****************************************************************************/
++typedef struct event_state_change {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  EVEL_ENTITY_STATE new_state;
++  EVEL_ENTITY_STATE old_state;
++  char * state_interface;
++  double version;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  DLIST additional_fields;
++
++} EVENT_STATE_CHANGE;
++
++/**************************************************************************//**
++ * State Change Additional Field.
++ * JSON equivalent field: additionalFields
++ *****************************************************************************/
++typedef struct state_change_additional_field {
++  char * name;
++  char * value;
++} STATE_CHANGE_ADDL_FIELD;
++
++/*****************************************************************************/
++/* Supported Syslog version.                                                 */
++/*****************************************************************************/
++#define EVEL_SYSLOG_MAJOR_VERSION 1
++#define EVEL_SYSLOG_MINOR_VERSION 2
++
++/**************************************************************************//**
++ * Syslog.
++ * JSON equivalent field: syslogFields
++ *****************************************************************************/
++typedef struct event_syslog {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  EVEL_SOURCE_TYPES event_source_type;
++  char * syslog_msg;
++  char * syslog_tag;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  EVEL_OPTION_STRING additional_filters;
++  EVEL_OPTION_STRING event_source_host;
++  EVEL_OPTION_INT syslog_facility;
++  EVEL_OPTION_INT syslog_priority;
++  EVEL_OPTION_STRING syslog_proc;
++  EVEL_OPTION_INT syslog_proc_id;
++  EVEL_OPTION_STRING syslog_s_data;
++  EVEL_OPTION_STRING syslog_sdid;
++  EVEL_OPTION_STRING syslog_severity;
++  double syslog_fver;
++  EVEL_OPTION_INT syslog_ver;
++
++} EVENT_SYSLOG;
++
++/**************************************************************************//**
++ * Copyright.
++ * JSON equivalent object: attCopyrightNotice
++ *****************************************************************************/
++typedef struct copyright {
++  char * useAndRedistribution;
++  char * condition1;
++  char * condition2;
++  char * condition3;
++  char * condition4;
++  char * disclaimerLine1;
++  char * disclaimerLine2;
++  char * disclaimerLine3;
++  char * disclaimerLine4;
++} COPYRIGHT;
++
++/**************************************************************************//**
++ * Library initialization.
++ *
++ * Initialize the EVEL library.
++ *
++ * @note  This function initializes the cURL library.  Applications making use
++ *        of libcurl may need to pull the initialization out of here.  Note
++ *        also that this function is not threadsafe as a result - refer to
++ *        libcurl's API documentation for relevant warnings.
++ *
++ * @sa  Matching Term function.
++ *
++ * @param   fqdn    The API's FQDN or IP address.
++ * @param   port    The API's port.
++ * @param   path    The optional path (may be NULL).
++ * @param   topic   The optional topic part of the URL (may be NULL).
++ * @param   secure  Whether to use HTTPS (0=HTTP, 1=HTTPS).
++ * @param   username  Username for Basic Authentication of requests.
++ * @param   password  Password for Basic Authentication of requests.
++ * @param   source_type The kind of node we represent.
++ * @param   role    The role this node undertakes.
++ * @param   verbosity  0 for normal operation, positive values for chattier
++ *                     logs.
++ *
++ * @returns Status code
++ * @retval  EVEL_SUCCESS      On success
++ * @retval  ::EVEL_ERR_CODES  On failure.
++ *****************************************************************************/
++EVEL_ERR_CODES evel_initialize(const char * const fqdn,
++                               int port,
++                               const char * const path,
++                               const char * const topic,
++                               int secure,
++                               const char * const username,
++                               const char * const password,
++                               EVEL_SOURCE_TYPES source_type,
++                               const char * const role,
++                               int verbosity
++                               );
++
++/**************************************************************************//**
++ * Clean up the EVEL library.
++ *
++ * @note that at present don't expect Init/Term cycling not to leak memory!
++ *
++ * @returns Status code
++ * @retval  EVEL_SUCCESS On success
++ * @retval  "One of ::EVEL_ERR_CODES" On failure.
++ *****************************************************************************/
++EVEL_ERR_CODES evel_terminate(void);
++
++EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event);
++const char * evel_error_string(void);
++
++
++/**************************************************************************//**
++ * Free an event.
++ *
++ * Free off the event supplied.  Will free all the contained allocated memory.
++ *
++ * @note  It is safe to free a NULL pointer.
++ *****************************************************************************/
++void evel_free_event(void * event);
++
++/**************************************************************************//**
++ * Encode the event as a JSON event object according to AT&T's schema.
++ *
++ * @param json      Pointer to where to store the JSON encoded data.
++ * @param max_size  Size of storage available in json_body.
++ * @param event     Pointer to the ::EVENT_HEADER to encode.
++ * @returns Number of bytes actually written.
++ *****************************************************************************/
++int evel_json_encode_event(char * json,
++                           int max_size,
++                           EVENT_HEADER * event);
++
++/**************************************************************************//**
++ * Initialize an event instance id.
++ *
++ * @param vfield        Pointer to the event vnfname field being initialized.
++ * @param vendor_id     The vendor id to encode in the event instance id.
++ * @param event_id      The event id to encode in the event instance id.
++ *****************************************************************************/
++void evel_init_vendor_field(VENDOR_VNFNAME_FIELD * const vfield,
++                                 const char * const vendor_name);
++
++/**************************************************************************//**
++ * Set the Vendor module property of the Vendor.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vfield        Pointer to the Vendor field.
++ * @param module_name   The module name to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_vendor_field_module_set(VENDOR_VNFNAME_FIELD * const vfield,
++                                    const char * const module_name);
++/**************************************************************************//**
++ * Set the Vendor module property of the Vendor.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vfield        Pointer to the Vendor field.
++ * @param module_name   The module name to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_vendor_field_vnfname_set(VENDOR_VNFNAME_FIELD * const vfield,
++                                    const char * const vnfname);
++/**************************************************************************//**
++ * Free an event instance id.
++ *
++ * @param vfield   Pointer to the event vnfname_field being freed.
++ *****************************************************************************/
++void evel_free_event_vendor_field(VENDOR_VNFNAME_FIELD * const vfield);
++
++/**************************************************************************//**
++ * Callback function to provide returned data.
++ *
++ * Copy data into the supplied buffer, write_callback::ptr, checking size
++ * limits.
++ *
++ * @returns   Number of bytes placed into write_callback::ptr. 0 for EOF.
++ *****************************************************************************/
++size_t evel_write_callback(void *contents,
++                           size_t size,
++                           size_t nmemb,
++                           void *userp);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   HEARTBEAT - (includes common header, too)                               */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new heartbeat event.
++ *
++ * @note that the heartbeat is just a "naked" commonEventHeader!
++ *
++ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
++ *          not used it must be released using ::evel_free_event
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_HEADER * evel_new_heartbeat(void);
++
++/**************************************************************************//**
++ * Create a new heartbeat event of given name and type.
++ *
++ * @note that the heartbeat is just a "naked" commonEventHeader!
++ *
++ * @param event_name  Unique Event Name confirming Domain AsdcModel Description
++ * @param event_id    A universal identifier of the event for: troubleshooting correlation, analysis, etc
++ *
++ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
++ *          not used it must be released using ::evel_free_event
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_HEADER * evel_new_heartbeat_nameid(const char* ev_name, const char *ev_id);
++
++
++/**************************************************************************//**
++ * Free an event header.
++ *
++ * Free off the event header supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the header itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_header(EVENT_HEADER * const event);
++
++/**************************************************************************//**
++ * Initialize a newly created event header.
++ *
++ * @param header  Pointer to the header being initialized.
++ *****************************************************************************/
++void evel_init_header(EVENT_HEADER * const header,const char *const eventname);
++
++/**************************************************************************//**
++ * Set the Event Type property of the event header.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param type          The Event Type to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_header_type_set(EVENT_HEADER * const header,
++                          const char * const type);
++
++/**************************************************************************//**
++ * Set the Start Epoch property of the event header.
++ *
++ * @note The Start Epoch defaults to the time of event creation.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param start_epoch_microsec
++ *                      The start epoch to set, in microseconds.
++ *****************************************************************************/
++void evel_start_epoch_set(EVENT_HEADER * const header,
++                          const unsigned long long start_epoch_microsec);
++
++/**************************************************************************//**
++ * Set the Last Epoch property of the event header.
++ *
++ * @note The Last Epoch defaults to the time of event creation.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param last_epoch_microsec
++ *                      The last epoch to set, in microseconds.
++ *****************************************************************************/
++void evel_last_epoch_set(EVENT_HEADER * const header,
++                         const unsigned long long last_epoch_microsec);
++
++/**************************************************************************//**
++ * Set the Reporting Entity Name property of the event header.
++ *
++ * @note The Reporting Entity Name defaults to the OpenStack VM Name.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param entity_name   The entity name to set.
++ *****************************************************************************/
++void evel_reporting_entity_name_set(EVENT_HEADER * const header,
++                                    const char * const entity_name);
++
++/**************************************************************************//**
++ * Set the Reporting Entity Id property of the event header.
++ *
++ * @note The Reporting Entity Id defaults to the OpenStack VM UUID.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param entity_id     The entity id to set.
++ *****************************************************************************/
++void evel_reporting_entity_id_set(EVENT_HEADER * const header,
++                                  const char * const entity_id);
++
++/**************************************************************************//**
++ * Set the NFC Naming code property of the event header.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param nfcnamingcode String
++ *****************************************************************************/
++void evel_nfcnamingcode_set(EVENT_HEADER * const header,
++                         const char * const nfcnam);
++/**************************************************************************//**
++ * Set the NF Naming code property of the event header.
++ *
++ * @param header        Pointer to the ::EVENT_HEADER.
++ * @param nfnamingcode String
++ *****************************************************************************/
++void evel_nfnamingcode_set(EVENT_HEADER * const header,
++                         const char * const nfnam);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   FAULT                                                                   */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new fault event.
++ *
++ * @note    The mandatory fields on the Fault must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Fault has immutable properties.
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param   condition   The condition indicated by the Fault.
++ * @param   specific_problem  The specific problem triggering the fault.
++ * @param   priority    The priority of the event.
++ * @param   severity    The severity of the Fault.
++ * @param   ev_source_type    Source of Alarm event
++ * @param   version     fault version
++ * @param   status      status of Virtual Function
++ * @returns pointer to the newly manufactured ::EVENT_FAULT.  If the event is
++ *          not used (i.e. posted) it must be released using ::evel_free_fault.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_FAULT * evel_new_fault(const char* ev_name, const char *ev_id,
++                           const char * const condition,
++                             const char * const specific_problem,
++                             EVEL_EVENT_PRIORITIES priority,
++                             EVEL_SEVERITIES severity,
++                             EVEL_SOURCE_TYPES ev_source_type,
++                             EVEL_VF_STATUSES status);
++
++/**************************************************************************//**
++ * Free a Fault.
++ *
++ * Free off the Fault supplied.  Will free all the contained allocated memory.
++ *
++ * @note It does not free the Fault itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_fault(EVENT_FAULT * event);
++
++/**************************************************************************//**
++ * Set the Fault Category property of the Fault.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param fault      Pointer to the fault.
++ * @param category   Category : license, link, routing, security, signaling.
++ *                       ASCIIZ string. The caller
++ *                   does not need to preserve the value once the function
++ *                   returns.
++ *****************************************************************************/
++void evel_fault_category_set(EVENT_FAULT * fault,
++                              const char * const category);
++
++/**************************************************************************//**
++ * Set the Alarm Interface A property of the Fault.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param fault      Pointer to the fault.
++ * @param interface  The Alarm Interface A to be set. ASCIIZ string. The caller
++ *                   does not need to preserve the value once the function
++ *                   returns.
++ *****************************************************************************/
++void evel_fault_interface_set(EVENT_FAULT * fault,
++                              const char * const interface);
++
++/**************************************************************************//**
++ * Add an additional value name/value pair to the Fault.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param fault     Pointer to the fault.
++ * @param name      ASCIIZ string with the attribute's name.
++ * @param value     ASCIIZ string with the attribute's value.
++ *****************************************************************************/
++void evel_fault_addl_info_add(EVENT_FAULT * fault, char * name, char * value);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Fault.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param fault      Pointer to the fault.
++ * @param type       The Event Type to be set. ASCIIZ string. The caller
++ *                   does not need to preserve the value once the function
++ *                   returns.
++ *****************************************************************************/
++void evel_fault_type_set(EVENT_FAULT * fault, const char * const type);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   MEASUREMENT                                                             */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new Measurement event.
++ *
++ * @note    The mandatory fields on the Measurement must be supplied to this
++ *          factory function and are immutable once set.  Optional fields have
++ *          explicit setter functions, but again values may only be set once so
++ *          that the Measurement has immutable properties.
++ *
++ * @param   measurement_interval
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ *
++ * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT.  If the
++ *          event is not used (i.e. posted) it must be released using
++ *          ::evel_free_event.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval,const char* ev_name, const char *ev_id);
++
++/**************************************************************************//**
++ * Free a Measurement.
++ *
++ * Free off the Measurement supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the Measurement itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_measurement(EVENT_MEASUREMENT * event);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement Pointer to the Measurement.
++ * @param type        The Event Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_measurement_type_set(EVENT_MEASUREMENT * measurement,
++                               const char * const type);
++
++/**************************************************************************//**
++ * Set the Concurrent Sessions property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement         Pointer to the Measurement.
++ * @param concurrent_sessions The Concurrent Sessions to be set.
++ *****************************************************************************/
++void evel_measurement_conc_sess_set(EVENT_MEASUREMENT * measurement,
++                                    int concurrent_sessions);
++
++/**************************************************************************//**
++ * Set the Configured Entities property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement         Pointer to the Measurement.
++ * @param configured_entities The Configured Entities to be set.
++ *****************************************************************************/
++void evel_measurement_cfg_ents_set(EVENT_MEASUREMENT * measurement,
++                                   int configured_entities);
++
++/**************************************************************************//**
++ * Add an additional set of Errors to the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement       Pointer to the measurement.
++ * @param receive_discards  The number of receive discards.
++ * @param receive_errors    The number of receive errors.
++ * @param transmit_discards The number of transmit discards.
++ * @param transmit_errors   The number of transmit errors.
++ *****************************************************************************/
++void evel_measurement_errors_set(EVENT_MEASUREMENT * measurement,
++                                 int receive_discards,
++                                 int receive_errors,
++                                 int transmit_discards,
++                                 int transmit_errors);
++
++/**************************************************************************//**
++ * Set the Mean Request Latency property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement          Pointer to the Measurement.
++ * @param mean_request_latency The Mean Request Latency to be set.
++ *****************************************************************************/
++void evel_measurement_mean_req_lat_set(EVENT_MEASUREMENT * measurement,
++                                       double mean_request_latency);
++
++/**************************************************************************//**
++ * Set the Request Rate property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement  Pointer to the Measurement.
++ * @param request_rate The Request Rate to be set.
++ *****************************************************************************/
++void evel_measurement_request_rate_set(EVENT_MEASUREMENT * measurement,
++                                       int request_rate);
++
++/**************************************************************************//**
++ * Add an additional CPU usage value name/value pair to the Measurement.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement   Pointer to the measurement.
++ * @param id            ASCIIZ string with the CPU's identifier.
++ * @param usage         CPU utilization.
++ *****************************************************************************/
++MEASUREMENT_CPU_USE * evel_measurement_new_cpu_use_add(EVENT_MEASUREMENT * measurement, char * id, double usage);
++
++/**************************************************************************//**
++ * Set the CPU Idle value in measurement interval
++ *   percentage of CPU time spent in the idle task
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_idle_set(MEASUREMENT_CPU_USE *const cpu_use,
++                                    const double val);
++
++/**************************************************************************//**
++ * Set the percentage of time spent servicing interrupts
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_interrupt_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++
++/**************************************************************************//**
++ * Set the percentage of time spent running user space processes that have been niced
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_nice_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++
++/**************************************************************************//**
++ * Set the percentage of time spent handling soft irq interrupts
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_softirq_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the percentage of time spent in involuntary wait
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_steal_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the percentage of time spent on system tasks running the kernel
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_system_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the percentage of time spent running un-niced user space processes
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_usageuser_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++/**************************************************************************//**
++ * Set the percentage of CPU time spent waiting for I/O operations to complete
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param cpu_use      Pointer to the CPU Use.
++ * @param val          double
++ *****************************************************************************/
++void evel_measurement_cpu_use_wait_set(MEASUREMENT_CPU_USE * const cpu_use,
++                                    const double val);
++
++/**************************************************************************//**
++ * Add an additional File System usage value name/value pair to the
++ * Measurement.
++ *
++ * The filesystem_name is null delimited ASCII string.  The library takes a
++ * copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement     Pointer to the measurement.
++ * @param filesystem_name   ASCIIZ string with the file-system's UUID.
++ * @param block_configured  Block storage configured.
++ * @param block_used        Block storage in use.
++ * @param block_iops        Block storage IOPS.
++ * @param ephemeral_configured  Ephemeral storage configured.
++ * @param ephemeral_used        Ephemeral storage in use.
++ * @param ephemeral_iops        Ephemeral storage IOPS.
++ *****************************************************************************/
++void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
++                                   char * filesystem_name,
++                                   double block_configured,
++                                   double block_used,
++                                   int block_iops,
++                                   double ephemeral_configured,
++                                   double ephemeral_used,
++                                   int ephemeral_iops);
++
++/**************************************************************************//**
++ * Add a Feature usage value name/value pair to the Measurement.
++ *
++ * The name is null delimited ASCII string.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement     Pointer to the measurement.
++ * @param feature         ASCIIZ string with the feature's name.
++ * @param utilization     Utilization of the feature.
++ *****************************************************************************/
++void evel_measurement_feature_use_add(EVENT_MEASUREMENT * measurement,
++                                      char * feature,
++                                      int utilization);
++
++/**************************************************************************//**
++ * Add a Additional Measurement value name/value pair to the Measurement.
++ *
++ * The name is null delimited ASCII string.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement   Pointer to the Measurement.
++ * @param group    ASCIIZ string with the measurement group's name.
++ * @param name     ASCIIZ string containing the measurement's name.
++ * @param name     ASCIIZ string containing the measurement's value.
++ *****************************************************************************/
++void evel_measurement_custom_measurement_add(EVENT_MEASUREMENT * measurement,
++                                             const char * const group,
++                                             const char * const name,
++                                             const char * const value);
++
++/**************************************************************************//**
++ * Add a Codec usage value name/value pair to the Measurement.
++ *
++ * The name is null delimited ASCII string.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param measurement     Pointer to the measurement.
++ * @param codec           ASCIIZ string with the codec's name.
++ * @param utilization     Utilization of the feature.
++ *****************************************************************************/
++void evel_measurement_codec_use_add(EVENT_MEASUREMENT * measurement,
++                                    char * codec,
++                                    int utilization);
++
++/**************************************************************************//**
++ * Set the Media Ports in Use property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement         Pointer to the measurement.
++ * @param media_ports_in_use  The media port usage to set.
++ *****************************************************************************/
++void evel_measurement_media_port_use_set(EVENT_MEASUREMENT * measurement,
++                                         int media_ports_in_use);
++
++/**************************************************************************//**
++ * Set the VNFC Scaling Metric property of the Measurement.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param measurement     Pointer to the measurement.
++ * @param scaling_metric  The scaling metric to set.
++ *****************************************************************************/
++void evel_measurement_vnfc_scaling_metric_set(EVENT_MEASUREMENT * measurement,
++                                              int scaling_metric);
++
++/**************************************************************************//**
++ * Create a new Latency Bucket to be added to a Measurement event.
++ *
++ * @note    The mandatory fields on the ::MEASUREMENT_LATENCY_BUCKET must be
++ *          supplied to this factory function and are immutable once set.
++ *          Optional fields have explicit setter functions, but again values
++ *          may only be set once so that the ::MEASUREMENT_LATENCY_BUCKET has
++ *          immutable properties.
++ *
++ * @param count         Count of events in this bucket.
++ *
++ * @returns pointer to the newly manufactured ::MEASUREMENT_LATENCY_BUCKET.
++ * @retval  NULL  Failed to create the Latency Bucket.
++ *****************************************************************************/
++MEASUREMENT_LATENCY_BUCKET * evel_new_meas_latency_bucket(const int count);
++
++/**************************************************************************//**
++ * Set the High End property of the Measurement Latency Bucket.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param bucket        Pointer to the Measurement Latency Bucket.
++ * @param high_end      High end of the bucket's range.
++ *****************************************************************************/
++void evel_meas_latency_bucket_high_end_set(
++                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
++                                     const double high_end);
++
++/**************************************************************************//**
++ * Set the Low End property of the Measurement Latency Bucket.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param bucket        Pointer to the Measurement Latency Bucket.
++ * @param low_end       Low end of the bucket's range.
++ *****************************************************************************/
++void evel_meas_latency_bucket_low_end_set(
++                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
++                                     const double low_end);
++
++/**************************************************************************//**
++ * Add an additional Measurement Latency Bucket to the specified event.
++ *
++ * @param measurement   Pointer to the Measurement event.
++ * @param bucket        Pointer to the Measurement Latency Bucket to add.
++ *****************************************************************************/
++void evel_meas_latency_bucket_add(EVENT_MEASUREMENT * const measurement,
++                                  MEASUREMENT_LATENCY_BUCKET * const bucket);
++
++/**************************************************************************//**
++ * Add an additional Latency Distribution bucket to the Measurement.
++ *
++ * This function implements the previous API, purely for convenience.
++ *
++ * @param measurement   Pointer to the measurement.
++ * @param low_end       Low end of the bucket's range.
++ * @param high_end      High end of the bucket's range.
++ * @param count         Count of events in this bucket.
++ *****************************************************************************/
++void evel_measurement_latency_add(EVENT_MEASUREMENT * const measurement,
++                                  const double low_end,
++                                  const double high_end,
++                                  const int count);
++
++/**************************************************************************//**
++ * Create a new vNIC Use to be added to a Measurement event.
++ *
++ * @note    The mandatory fields on the ::MEASUREMENT_VNIC_PERFORMANCE must be supplied
++ *          to this factory function and are immutable once set. Optional
++ *          fields have explicit setter functions, but again values may only be
++ *          set once so that the ::MEASUREMENT_VNIC_PERFORMANCE has immutable
++ *          properties.
++ *
++ * @param vnic_id               ASCIIZ string with the vNIC's ID.
++ * @param val_suspect           True or false confidence in data.
++ *
++ * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_PERFORMANCE.
++ *          If the structure is not used it must be released using
++ *          ::evel_measurement_free_vnic_performance.
++ * @retval  NULL  Failed to create the vNIC Use.
++ *****************************************************************************/
++MEASUREMENT_VNIC_PERFORMANCE * evel_measurement_new_vnic_performance(char * const vnic_id, char * const val_suspect);
++
++/**************************************************************************//**
++ * Free a vNIC Use.
++ *
++ * Free off the ::MEASUREMENT_VNIC_PERFORMANCE supplied.  Will free all the contained
++ * allocated memory.
++ *
++ * @note It does not free the vNIC Use itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_measurement_free_vnic_performance(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance);
++
++/**************************************************************************//**
++ * Set the Accumulated Broadcast Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_bcast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_bcast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Broadcast Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_bcast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_bcast_packets_delta);
++/**************************************************************************//**
++ * Set the Discarded Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_discard_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_discard_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_discard_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Discarded Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_discard_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_discard_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_discard_packets_delta);
++/**************************************************************************//**
++ * Set the Error Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_error_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_error_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Error Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_error_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_error_packets_delta);
++/**************************************************************************//**
++ * Set the Accumulated Multicast Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_mcast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_mcast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Multicast Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_mcast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_mcast_packets_delta);
++/**************************************************************************//**
++ * Set the Accumulated Octets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_octets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_octets_acc);
++/**************************************************************************//**
++ * Set the Delta Octets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_octets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_octets_delta);
++/**************************************************************************//**
++ * Set the Accumulated Total Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_total_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_total_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Total Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_total_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_total_packets_delta);
++/**************************************************************************//**
++ * Set the Accumulated Unicast Packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_ucast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_rx_ucast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_ucast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Unicast packets Received in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param recvd_ucast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_rx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double recvd_ucast_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Broadcast Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_bcast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_bcast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Broadcast packets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_bcast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_bcast_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Discarded Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_discarded_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_discarded_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_discarded_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Discarded packets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_discarded_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_discarded_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_discarded_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Errored Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_error_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_error_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Errored packets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_error_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_error_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Multicast Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_mcast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_mcast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Multicast packets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_mcast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_mcast_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Octets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_octets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_octets_acc);
++/**************************************************************************//**
++ * Set the Delta Octets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_octets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_octets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Total Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_total_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_total_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Total Packets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_total_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_total_packets_delta);
++/**************************************************************************//**
++ * Set the Transmitted Unicast Packets in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_ucast_packets_acc
++ *****************************************************************************/
++void evel_vnic_performance_tx_ucast_packets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_ucast_packets_acc);
++/**************************************************************************//**
++ * Set the Delta Octets Transmitted in measurement interval
++ * property of the vNIC performance.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param vnic_performance      Pointer to the vNIC Use.
++ * @param tx_ucast_packets_delta
++ *****************************************************************************/
++void evel_vnic_performance_tx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance,
++                                    const double tx_ucast_packets_delta);
++
++/**************************************************************************//**
++ * Add an additional vNIC Use to the specified Measurement event.
++ *
++ * @param measurement   Pointer to the measurement.
++ * @param vnic_performance      Pointer to the vNIC Use to add.
++ *****************************************************************************/
++void evel_meas_vnic_performance_add(EVENT_MEASUREMENT * const measurement,
++                            MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance);
++
++/**************************************************************************//**
++ * Add an additional vNIC usage record Measurement.
++ *
++ * This function implements the previous API, purely for convenience.
++ *
++ * The ID is null delimited ASCII string.  The library takes a copy so the
++ * caller does not have to preserve values after the function returns.
++ *
++ * @param measurement           Pointer to the measurement.
++ * @param vnic_id               ASCIIZ string with the vNIC's ID.
++ * @param valset                true or false confidence level
++ * @param recvd_bcast_packets_acc         Recieved broadcast packets
++ * @param recvd_bcast_packets_delta       Received delta broadcast packets
++ * @param recvd_discarded_packets_acc     Recieved discarded packets
++ * @param recvd_discarded_packets_delta   Received discarded delta packets
++ * @param recvd_error_packets_acc         Received error packets
++ * @param recvd_error_packets_delta,      Received delta error packets
++ * @param recvd_mcast_packets_acc         Received multicast packets
++ * @param recvd_mcast_packets_delta       Received delta multicast packets
++ * @param recvd_octets_acc                Received octets
++ * @param recvd_octets_delta              Received delta octets
++ * @param recvd_total_packets_acc         Received total packets
++ * @param recvd_total_packets_delta       Received delta total packets
++ * @param recvd_ucast_packets_acc         Received Unicast packets
++ * @param recvd_ucast_packets_delta       Received delta unicast packets
++ * @param tx_bcast_packets_acc            Transmitted broadcast packets
++ * @param tx_bcast_packets_delta          Transmitted delta broadcast packets
++ * @param tx_discarded_packets_acc        Transmitted packets discarded
++ * @param tx_discarded_packets_delta      Transmitted delta discarded packets
++ * @param tx_error_packets_acc            Transmitted error packets
++ * @param tx_error_packets_delta          Transmitted delta error packets
++ * @param tx_mcast_packets_acc            Transmitted multicast packets accumulated
++ * @param tx_mcast_packets_delta          Transmitted delta multicast packets
++ * @param tx_octets_acc                   Transmitted octets
++ * @param tx_octets_delta                 Transmitted delta octets
++ * @param tx_total_packets_acc            Transmitted total packets
++ * @param tx_total_packets_delta          Transmitted delta total packets
++ * @param tx_ucast_packets_acc            Transmitted Unicast packets
++ * @param tx_ucast_packets_delta          Transmitted delta Unicast packets
++ *****************************************************************************/
++void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement,
++                               char * const vnic_id,
++                               char * valset,
++                               double recvd_bcast_packets_acc,
++                               double recvd_bcast_packets_delta,
++                               double recvd_discarded_packets_acc,
++                               double recvd_discarded_packets_delta,
++                               double recvd_error_packets_acc,
++                               double recvd_error_packets_delta,
++                               double recvd_mcast_packets_acc,
++                               double recvd_mcast_packets_delta,
++                               double recvd_octets_acc,
++                               double recvd_octets_delta,
++                               double recvd_total_packets_acc,
++                               double recvd_total_packets_delta,
++                               double recvd_ucast_packets_acc,
++                               double recvd_ucast_packets_delta,
++                               double tx_bcast_packets_acc,
++                               double tx_bcast_packets_delta,
++                               double tx_discarded_packets_acc,
++                               double tx_discarded_packets_delta,
++                               double tx_error_packets_acc,
++                               double tx_error_packets_delta,
++                               double tx_mcast_packets_acc,
++                               double tx_mcast_packets_delta,
++                               double tx_octets_acc,
++                               double tx_octets_delta,
++                               double tx_total_packets_acc,
++                               double tx_total_packets_delta,
++                               double tx_ucast_packets_acc,
++                               double tx_ucast_packets_delta);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   REPORT                                                                  */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new Report event.
++ *
++ * @note    The mandatory fields on the Report must be supplied to this
++ *          factory function and are immutable once set.  Optional fields have
++ *          explicit setter functions, but again values may only be set once so
++ *          that the Report has immutable properties.
++ *
++ * @param   measurement_interval
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ *
++ * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
++ *          not used (i.e. posted) it must be released using
++ *          ::evel_free_report.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_REPORT * evel_new_report(double measurement_interval,const char* ev_name, const char *ev_id);
++
++/**************************************************************************//**
++ * Free a Report.
++ *
++ * Free off the Report supplied.  Will free all the contained allocated memory.
++ *
++ * @note It does not free the Report itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_report(EVENT_REPORT * event);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Report.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param report Pointer to the Report.
++ * @param type        The Event Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_report_type_set(EVENT_REPORT * report, const char * const type);
++
++/**************************************************************************//**
++ * Add a Feature usage value name/value pair to the Report.
++ *
++ * The name is null delimited ASCII string.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param report          Pointer to the report.
++ * @param feature         ASCIIZ string with the feature's name.
++ * @param utilization     Utilization of the feature.
++ *****************************************************************************/
++void evel_report_feature_use_add(EVENT_REPORT * report,
++                                 char * feature,
++                                 int utilization);
++
++/**************************************************************************//**
++ * Add a Additional Measurement value name/value pair to the Report.
++ *
++ * The name is null delimited ASCII string.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param report   Pointer to the report.
++ * @param group    ASCIIZ string with the measurement group's name.
++ * @param name     ASCIIZ string containing the measurement's name.
++ * @param value    ASCIIZ string containing the measurement's value.
++ *****************************************************************************/
++void evel_report_custom_measurement_add(EVENT_REPORT * report,
++                                        const char * const group,
++                                        const char * const name,
++                                        const char * const value);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   MOBILE_FLOW                                                             */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new Mobile Flow event.
++ *
++ * @note    The mandatory fields on the Mobile Flow must be supplied to this
++ *          factory function and are immutable once set.  Optional fields have
++ *          explicit setter functions, but again values may only be set once so
++ *          that the Mobile Flow has immutable properties.
++ *
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param   flow_direction
++ * @param   gtp_per_flow_metrics
++ * @param   ip_protocol_type
++ * @param   ip_version
++ * @param   other_endpoint_ip_address
++ * @param   other_endpoint_port
++ * @param   reporting_endpoint_ip_addr
++ * @param   reporting_endpoint_port
++ *
++ * @returns pointer to the newly manufactured ::EVENT_MOBILE_FLOW.  If the
++ *          event is not used (i.e. posted) it must be released using
++ *          ::evel_free_mobile_flow.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_MOBILE_FLOW * evel_new_mobile_flow(
++                    const char* ev_name, const char *ev_id,
++                      const char * const flow_direction,
++                      MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics,
++                      const char * const ip_protocol_type,
++                      const char * const ip_version,
++                      const char * const other_endpoint_ip_address,
++                      int other_endpoint_port,
++                      const char * const reporting_endpoint_ip_addr,
++                      int reporting_endpoint_port);
++
++/**************************************************************************//**
++ * Free a Mobile Flow.
++ *
++ * Free off the Mobile Flow supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the Mobile Flow itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_mobile_flow(EVENT_MOBILE_FLOW * event);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param type        The Event Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_flow_type_set(EVENT_MOBILE_FLOW * mobile_flow,
++                               const char * const type);
++
++/**************************************************************************//**
++ * Set the Application Type property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param type        The Application Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_flow_app_type_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                   const char * const type);
++
++/**************************************************************************//**
++ * Set the Application Protocol Type property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param type        The Application Protocol Type to be set. ASCIIZ string.
++ *                    The caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_flow_app_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                        const char * const type);
++
++/**************************************************************************//**
++ * Set the Application Protocol Version property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param version     The Application Protocol Version to be set. ASCIIZ
++ *                    string.  The caller does not need to preserve the value
++ *                    once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_app_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                       const char * const version);
++
++/**************************************************************************//**
++ * Set the CID property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param cid         The CID to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_cid_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const cid);
++
++/**************************************************************************//**
++ * Set the Connection Type property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param type        The Connection Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_flow_con_type_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                   const char * const type);
++
++/**************************************************************************//**
++ * Set the ECGI property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param ecgi        The ECGI to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_ecgi_set(EVENT_MOBILE_FLOW * mobile_flow,
++                               const char * const ecgi);
++
++/**************************************************************************//**
++ * Set the GTP Protocol Type property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param type        The GTP Protocol Type to be set. ASCIIZ string.  The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_flow_gtp_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                        const char * const type);
++
++/**************************************************************************//**
++ * Set the GTP Protocol Version property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param version     The GTP Protocol Version to be set. ASCIIZ string.  The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_flow_gtp_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                       const char * const version);
++
++/**************************************************************************//**
++ * Set the HTTP Header property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param header      The HTTP header to be set. ASCIIZ string. The caller does
++ *                    not need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_http_header_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                      const char * const header);
++
++/**************************************************************************//**
++ * Set the IMEI property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param imei        The IMEI to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_imei_set(EVENT_MOBILE_FLOW * mobile_flow,
++                               const char * const imei);
++
++/**************************************************************************//**
++ * Set the IMSI property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param imsi        The IMSI to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_imsi_set(EVENT_MOBILE_FLOW * mobile_flow,
++                               const char * const imsi);
++
++/**************************************************************************//**
++ * Set the LAC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param lac         The LAC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_lac_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const lac);
++
++/**************************************************************************//**
++ * Set the MCC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param mcc         The MCC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_mcc_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const mcc);
++
++/**************************************************************************//**
++ * Set the MNC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param mnc         The MNC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_mnc_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const mnc);
++
++/**************************************************************************//**
++ * Set the MSISDN property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param msisdn      The MSISDN to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_msisdn_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                 const char * const msisdn);
++
++/**************************************************************************//**
++ * Set the Other Functional Role property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param role        The Other Functional Role to be set. ASCIIZ string. The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_flow_other_func_role_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                          const char * const role);
++
++/**************************************************************************//**
++ * Set the RAC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param rac         The RAC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_rac_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const rac);
++
++/**************************************************************************//**
++ * Set the Radio Access Technology property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param tech        The Radio Access Technology to be set. ASCIIZ string. The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_flow_radio_acc_tech_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                         const char * const tech);
++
++/**************************************************************************//**
++ * Set the SAC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param sac         The SAC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_sac_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const sac);
++
++/**************************************************************************//**
++ * Set the Sampling Algorithm property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param algorithm   The Sampling Algorithm to be set.
++ *****************************************************************************/
++void evel_mobile_flow_samp_alg_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                   int algorithm);
++
++/**************************************************************************//**
++ * Set the TAC property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param tac         The TAC to be set. ASCIIZ string.  The caller does not
++ *                    need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_tac_set(EVENT_MOBILE_FLOW * mobile_flow,
++                              const char * const tac);
++
++/**************************************************************************//**
++ * Set the Tunnel ID property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param tunnel_id   The Tunnel ID to be set. ASCIIZ string.  The caller does
++ *                    not need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_tunnel_id_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                    const char * const tunnel_id);
++
++/**************************************************************************//**
++ * Set the VLAN ID property of the Mobile Flow.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param mobile_flow Pointer to the Mobile Flow.
++ * @param vlan_id     The VLAN ID to be set. ASCIIZ string.  The caller does
++ *                    not need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_mobile_flow_vlan_id_set(EVENT_MOBILE_FLOW * mobile_flow,
++                                  const char * const vlan_id);
++
++/**************************************************************************//**
++ * Create a new Mobile GTP Per Flow Metrics.
++ *
++ * @note    The mandatory fields on the Mobile GTP Per Flow Metrics must be
++ *          supplied to this factory function and are immutable once set.
++ *          Optional fields have explicit setter functions, but again values
++ *          may only be set once so that the Mobile GTP Per Flow Metrics has
++ *          immutable properties.
++ *
++ * @param   avg_bit_error_rate
++ * @param   avg_packet_delay_variation
++ * @param   avg_packet_latency
++ * @param   avg_receive_throughput
++ * @param   avg_transmit_throughput
++ * @param   flow_activation_epoch
++ * @param   flow_activation_microsec
++ * @param   flow_deactivation_epoch
++ * @param   flow_deactivation_microsec
++ * @param   flow_deactivation_time
++ * @param   flow_status
++ * @param   max_packet_delay_variation
++ * @param   num_activation_failures
++ * @param   num_bit_errors
++ * @param   num_bytes_received
++ * @param   num_bytes_transmitted
++ * @param   num_dropped_packets
++ * @param   num_l7_bytes_received
++ * @param   num_l7_bytes_transmitted
++ * @param   num_lost_packets
++ * @param   num_out_of_order_packets
++ * @param   num_packet_errors
++ * @param   num_packets_received_excl_retrans
++ * @param   num_packets_received_incl_retrans
++ * @param   num_packets_transmitted_incl_retrans
++ * @param   num_retries
++ * @param   num_timeouts
++ * @param   num_tunneled_l7_bytes_received
++ * @param   round_trip_time
++ * @param   time_to_first_byte
++ *
++ * @returns pointer to the newly manufactured ::MOBILE_GTP_PER_FLOW_METRICS.
++ *          If the structure is not used it must be released using
++ *          ::evel_free_mobile_gtp_flow_metrics.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++MOBILE_GTP_PER_FLOW_METRICS * evel_new_mobile_gtp_flow_metrics(
++                                      double avg_bit_error_rate,
++                                      double avg_packet_delay_variation,
++                                      int avg_packet_latency,
++                                      int avg_receive_throughput,
++                                      int avg_transmit_throughput,
++                                      int flow_activation_epoch,
++                                      int flow_activation_microsec,
++                                      int flow_deactivation_epoch,
++                                      int flow_deactivation_microsec,
++                                      time_t flow_deactivation_time,
++                                      const char * const flow_status,
++                                      int max_packet_delay_variation,
++                                      int num_activation_failures,
++                                      int num_bit_errors,
++                                      int num_bytes_received,
++                                      int num_bytes_transmitted,
++                                      int num_dropped_packets,
++                                      int num_l7_bytes_received,
++                                      int num_l7_bytes_transmitted,
++                                      int num_lost_packets,
++                                      int num_out_of_order_packets,
++                                      int num_packet_errors,
++                                      int num_packets_received_excl_retrans,
++                                      int num_packets_received_incl_retrans,
++                                      int num_packets_transmitted_incl_retrans,
++                                      int num_retries,
++                                      int num_timeouts,
++                                      int num_tunneled_l7_bytes_received,
++                                      int round_trip_time,
++                                      int time_to_first_byte);
++
++/**************************************************************************//**
++ * Free a Mobile GTP Per Flow Metrics.
++ *
++ * Free off the Mobile GTP Per Flow Metrics supplied.  Will free all the
++ * contained allocated memory.
++ *
++ * @note It does not free the Mobile GTP Per Flow Metrics itself, since that
++ * may be part of a larger structure.
++ *****************************************************************************/
++void evel_free_mobile_gtp_flow_metrics(MOBILE_GTP_PER_FLOW_METRICS * metrics);
++
++/**************************************************************************//**
++ * Set the Duration of Connection Failed Status property of the Mobile GTP Per
++ * Flow Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param duration    The Duration of Connection Failed Status to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_dur_con_fail_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int duration);
++
++/**************************************************************************//**
++ * Set the Duration of Tunnel Failed Status property of the Mobile GTP Per Flow
++ * Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param duration    The Duration of Tunnel Failed Status to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_dur_tun_fail_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int duration);
++
++/**************************************************************************//**
++ * Set the Activated By property of the Mobile GTP Per Flow metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param act_by      The Activated By to be set.  ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_act_by_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                        const char * const act_by);
++
++/**************************************************************************//**
++ * Set the Activation Time property of the Mobile GTP Per Flow metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param act_time    The Activation Time to be set.  ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_act_time_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         time_t act_time);
++
++/**************************************************************************//**
++ * Set the Deactivated By property of the Mobile GTP Per Flow metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param deact_by    The Deactivated By to be set.  ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_deact_by_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         const char * const deact_by);
++
++/**************************************************************************//**
++ * Set the GTP Connection Status property of the Mobile GTP Per Flow metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param status      The GTP Connection Status to be set.  ASCIIZ string. The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_con_status_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         const char * const status);
++
++/**************************************************************************//**
++ * Set the GTP Tunnel Status property of the Mobile GTP Per Flow metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param status      The GTP Tunnel Status to be set.  ASCIIZ string. The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_tun_status_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         const char * const status);
++
++/**************************************************************************//**
++ * Set an IP Type-of-Service count property of the Mobile GTP Per Flow metrics.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param index       The index of the IP Type-of-Service.
++ * @param count       The count.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_iptos_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                       int index,
++                                       int count);
++
++/**************************************************************************//**
++ * Set the Large Packet Round-Trip Time property of the Mobile GTP Per Flow
++ * Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param rtt         The Large Packet Round-Trip Time to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_large_pkt_rtt_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int rtt);
++
++/**************************************************************************//**
++ * Set the Large Packet Threshold property of the Mobile GTP Per Flow Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param threshold   The Large Packet Threshold to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_large_pkt_thresh_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         double threshold);
++
++/**************************************************************************//**
++ * Set the Max Receive Bit Rate property of the Mobile GTP Per Flow Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param rate        The Max Receive Bit Rate to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_max_rcv_bit_rate_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int rate);
++
++/**************************************************************************//**
++ * Set the Max Transmit Bit Rate property of the Mobile GTP Per Flow Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param rate        The Max Transmit Bit Rate to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_max_trx_bit_rate_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int rate);
++
++/**************************************************************************//**
++ * Set the Number of GTP Echo Failures property of the Mobile GTP Per Flow
++ * Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param num         The Number of GTP Echo Failures to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_num_echo_fail_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int num);
++
++/**************************************************************************//**
++ * Set the Number of GTP Tunnel Errors property of the Mobile GTP Per Flow
++ * Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param num         The Number of GTP Tunnel Errors to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_num_tun_fail_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int num);
++
++/**************************************************************************//**
++ * Set the Number of HTTP Errors property of the Mobile GTP Per Flow Metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
++ * @param num         The Number of HTTP Errors to be set.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_num_http_errors_set(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         int num);
++
++/**************************************************************************//**
++ * Add a TCP flag count to the metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
++ * @param tcp_flag      The TCP flag count to be updated.
++ * @param count         The associated flag count.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_tcp_flag_count_add(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         const EVEL_TCP_FLAGS tcp_flag,
++                                         const int count);
++
++/**************************************************************************//**
++ * Add a QCI COS count to the metrics.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
++ * @param qci_cos       The QCI COS count to be updated.
++ * @param count         The associated QCI COS count.
++ *****************************************************************************/
++void evel_mobile_gtp_metrics_qci_cos_count_add(
++                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
++                                         const EVEL_QCI_COS_TYPES qci_cos,
++                                         const int count);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   SIGNALING                                                               */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new Signaling event.
++ *
++ * @note    The mandatory fields on the Signaling must be supplied to
++ *          this factory function and are immutable once set.  Optional fields
++ *          have explicit setter functions, but again values may only be set
++ *          once so that the event has immutable properties.
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param vendor_name   The vendor id to encode in the event vnf field.
++ * @param module        The module to encode in the event.
++ * @param vnfname       The Virtual network function to encode in the event.
++ * @returns pointer to the newly manufactured ::EVENT_SIGNALING.  If the event
++ *          is not used (i.e. posted) it must be released using
++ *          ::evel_free_signaling.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_SIGNALING * evel_new_signaling(const char* ev_name, const char *ev_id,
++                                   const char * const vendor_name,
++                                     const char * const correlator,
++                                   const char * const local_ip_address,
++                                   const char * const local_port,
++                                   const char * const remote_ip_address,
++                                   const char * const remote_port);
++
++/**************************************************************************//**
++ * Free a Signaling event.
++ *
++ * Free off the event supplied.  Will free all the contained allocated memory.
++ *
++ * @note It does not free the event itself, since that may be part of a larger
++ * structure.
++ *****************************************************************************/
++void evel_free_signaling(EVENT_SIGNALING * const event);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param type          The Event Type to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_type_set(EVENT_SIGNALING * const event,
++                             const char * const type);
++
++/**************************************************************************//**
++ * Add an additional value name/value pair to the SIP signaling.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param event     Pointer to the fault.
++ * @param name      ASCIIZ string with the attribute's name.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ * @param value     ASCIIZ string with the attribute's value.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ *****************************************************************************/
++void evel_signaling_addl_info_add(EVENT_SIGNALING * event, char * name, char * value);
++
++/**************************************************************************//**
++ * Set the Correlator property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param correlator    The correlator to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_correlator_set(EVENT_SIGNALING * const event,
++                                   const char * const correlator);
++
++/**************************************************************************//**
++ * Set the Local Ip Address property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param local_ip_address
++ *                      The Local Ip Address to be set. ASCIIZ string. The
++ *                      caller does not need to preserve the value once the
++ *                      function returns.
++ *****************************************************************************/
++void evel_signaling_local_ip_address_set(EVENT_SIGNALING * const event,
++                                         const char * const local_ip_address);
++
++/**************************************************************************//**
++ * Set the Local Port property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param local_port    The Local Port to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_local_port_set(EVENT_SIGNALING * const event,
++                                   const char * const local_port);
++
++/**************************************************************************//**
++ * Set the Remote Ip Address property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param remote_ip_address
++ *                      The Remote Ip Address to be set. ASCIIZ string. The
++ *                      caller does not need to preserve the value once the
++ *                      function returns.
++ *****************************************************************************/
++void evel_signaling_remote_ip_address_set(EVENT_SIGNALING * const event,
++                                         const char * const remote_ip_address);
++
++/**************************************************************************//**
++ * Set the Remote Port property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param remote_port   The Remote Port to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_remote_port_set(EVENT_SIGNALING * const event,
++                                    const char * const remote_port);
++/**************************************************************************//**
++ * Set the Vendor module property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param modulename    The module name to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_vnfmodule_name_set(EVENT_SIGNALING * const event,
++                                    const char * const module_name);
++/**************************************************************************//**
++ * Set the Vendor module property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param vnfname       The Virtual Network function to be set. ASCIIZ string.
++ *                      The caller does not need to preserve the value once
++ *                      the function returns.
++ *****************************************************************************/
++void evel_signaling_vnfname_set(EVENT_SIGNALING * const event,
++                                    const char * const vnfname);
++
++/**************************************************************************//**
++ * Set the Compressed SIP property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param compressed_sip
++ *                      The Compressed SIP to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_compressed_sip_set(EVENT_SIGNALING * const event,
++                                       const char * const compressed_sip);
++
++/**************************************************************************//**
++ * Set the Summary SIP property of the Signaling event.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param event         Pointer to the Signaling event.
++ * @param summary_sip   The Summary SIP to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event,
++                                    const char * const summary_sip);
++
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   STATE CHANGE                                                            */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new State Change event.
++ *
++ * @note    The mandatory fields on the Syslog must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Syslog has immutable properties.
++ *
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param new_state     The new state of the reporting entity.
++ * @param old_state     The old state of the reporting entity.
++ * @param interface     The card or port name of the reporting entity.
++ *
++ * @returns pointer to the newly manufactured ::EVENT_STATE_CHANGE.  If the
++ *          event is not used it must be released using
++ *          ::evel_free_state_change
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_STATE_CHANGE * evel_new_state_change(const char* ev_name, const char *ev_id,
++                                         const EVEL_ENTITY_STATE new_state,
++                                           const EVEL_ENTITY_STATE old_state,
++                                           const char * const interface);
++
++/**************************************************************************//**
++ * Free a State Change.
++ *
++ * Free off the State Change supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the State Change itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_state_change(EVENT_STATE_CHANGE * const state_change);
++
++/**************************************************************************//**
++ * Set the Event Type property of the State Change.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
++ * @param type          The Event Type to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_state_change_type_set(EVENT_STATE_CHANGE * const state_change,
++                                const char * const type);
++
++/**************************************************************************//**
++ * Add an additional field name/value pair to the State Change.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
++ * @param name          ASCIIZ string with the attribute's name.  The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ * @param value         ASCIIZ string with the attribute's value.  The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change,
++                                      const char * const name,
++                                      const char * const value);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   SYSLOG                                                                  */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new syslog event.
++ *
++ * @note    The mandatory fields on the Syslog must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Syslog has immutable properties.
++ *
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param   event_source_type
++ * @param   syslog_msg
++ * @param   syslog_tag
++ * @param   version
++ *
++ * @returns pointer to the newly manufactured ::EVENT_SYSLOG.  If the event is
++ *          not used it must be released using ::evel_free_syslog
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_SYSLOG * evel_new_syslog(const char* ev_name, const char *ev_id,
++                              EVEL_SOURCE_TYPES event_source_type,
++                               const char * const syslog_msg,
++                               const char * const syslog_tag);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the syslog.
++ * @param type        The Event Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_syslog_type_set(EVENT_SYSLOG * syslog,
++                          const char * const type);
++
++/**************************************************************************//**
++ * Free a Syslog.
++ *
++ * Free off the Syslog supplied.  Will free all the contained allocated memory.
++ *
++ * @note It does not free the Syslog itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_syslog(EVENT_SYSLOG * event);
++
++/**************************************************************************//**
++ * Add an additional field name/value pair to the Syslog.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param syslog    Pointer to the syslog.
++ * @param name      ASCIIZ string with the attribute's name.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ * @param value     ASCIIZ string with the attribute's value.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ *****************************************************************************/
++void evel_syslog_addl_field_add(EVENT_SYSLOG * syslog,
++                                char * name,
++                                char * value);
++
++/**************************************************************************//**
++ * Set the Event Source Host property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param host        The Event Source Host to be set.  ASCIIZ string. The
++ *                    caller does not need to preserve the value once the
++ *                    function returns.
++ *****************************************************************************/
++void evel_syslog_event_source_host_set(EVENT_SYSLOG * syslog,
++                                       const char * const host);
++
++/**************************************************************************//**
++ * Set the Syslog Facility property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param facility    The Syslog Facility to be set.  ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_syslog_facility_set(EVENT_SYSLOG * syslog,
++                              EVEL_SYSLOG_FACILITIES facility);
++
++/**************************************************************************//**
++ * Set the Process property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param proc        The Process to be set.  ASCIIZ string. The caller does
++ *                    not need to preserve the value once the function returns.
++ *****************************************************************************/
++void evel_syslog_proc_set(EVENT_SYSLOG * syslog, const char * const proc);
++
++/**************************************************************************//**
++ * Set the Process ID property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param proc_id     The Process ID to be set.
++ *****************************************************************************/
++void evel_syslog_proc_id_set(EVENT_SYSLOG * syslog, int proc_id);
++
++/**************************************************************************//**
++ * Set the Version property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param version     The Version to be set.
++ *****************************************************************************/
++void evel_syslog_version_set(EVENT_SYSLOG * syslog, int version);
++
++/**************************************************************************//**
++ * Set the Structured Data property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog      Pointer to the Syslog.
++ * @param s_data      The Structured Data to be set.  ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_syslog_s_data_set(EVENT_SYSLOG * syslog, const char * const s_data);
++
++/**************************************************************************//**
++ * Set the Structured SDID property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog     Pointer to the Syslog.
++ * @param sdid     The Structured Data to be set. ASCIIZ string. name@number
++ *                 Caller does not need to preserve the value once the function
++ *                   returns.
++ *****************************************************************************/
++void evel_syslog_sdid_set(EVENT_SYSLOG * syslog, const char * const sdid);
++
++/**************************************************************************//**
++ * Set the Structured Severity property of the Syslog.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param syslog     Pointer to the Syslog.
++ * @param sdid     The Structured Data to be set. ASCIIZ string. 
++ *                 Caller does not need to preserve the value once the function
++ *                   returns.
++ *****************************************************************************/
++void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty);
++
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   OTHER                                                                   */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Create a new other event.
++ *
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ *
++ * @returns pointer to the newly manufactured ::EVENT_OTHER.  If the event is
++ *          not used it must be released using ::evel_free_other.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_OTHER * evel_new_other(const char* ev_name, const char *ev_id);
++
++/**************************************************************************//**
++ * Free an Other.
++ *
++ * Free off the Other supplied.  Will free all the contained allocated memory.
++ *
++ * @note It does not free the Other itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_other(EVENT_OTHER * event);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Other.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param other       Pointer to the Other.
++ * @param type        The Event Type to be set. ASCIIZ string. The caller
++ *                    does not need to preserve the value once the function
++ *                    returns.
++ *****************************************************************************/
++void evel_other_type_set(EVENT_OTHER * other,
++                         const char * const type);
++
++/**************************************************************************//**
++ * Add a value name/value pair to the Other.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param other     Pointer to the Other.
++ * @param name      ASCIIZ string with the attribute's name.
++ * @param value     ASCIIZ string with the attribute's value.
++ *****************************************************************************/
++void evel_other_field_add(EVENT_OTHER * other,
++                          char * name,
++                          char * value);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   THROTTLING                                                              */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/**************************************************************************//**
++ * Return the current measurement interval provided by the Event Listener.
++ *
++ * @returns The current measurement interval
++ * @retval  EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
++ *          specified
++ *****************************************************************************/
++int evel_get_measurement_interval();
++
++/*****************************************************************************/
++/* Supported Report version.                                                 */
++/*****************************************************************************/
++#define EVEL_VOICEQ_MAJOR_VERSION 1
++#define EVEL_VOICEQ_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * End of Call Voice Quality Metrices
++ * JSON equivalent field: endOfCallVqmSummaries
++ *****************************************************************************/
++typedef struct end_of_call_vqm_summaries {
++      /***************************************************************************/
++      /* Mandatory fields                                                        */
++      /***************************************************************************/
++      char* adjacencyName;
++      char* endpointDescription;
++
++      /***************************************************************************/
++      /* Optional fields                                                         */
++      /***************************************************************************/
++      EVEL_OPTION_INT endpointJitter;
++      EVEL_OPTION_INT endpointRtpOctetsDiscarded;
++      EVEL_OPTION_INT endpointRtpOctetsReceived;
++      EVEL_OPTION_INT endpointRtpOctetsSent;
++      EVEL_OPTION_INT endpointRtpPacketsDiscarded;
++      EVEL_OPTION_INT endpointRtpPacketsReceived;
++      EVEL_OPTION_INT endpointRtpPacketsSent;
++      EVEL_OPTION_INT localJitter;
++      EVEL_OPTION_INT localRtpOctetsDiscarded;
++      EVEL_OPTION_INT localRtpOctetsReceived;
++      EVEL_OPTION_INT localRtpOctetsSent;
++      EVEL_OPTION_INT localRtpPacketsDiscarded;
++      EVEL_OPTION_INT localRtpPacketsReceived;
++      EVEL_OPTION_INT localRtpPacketsSent;
++      EVEL_OPTION_INT mosCqe;
++      EVEL_OPTION_INT packetsLost;
++      EVEL_OPTION_INT packetLossPercent;
++      EVEL_OPTION_INT rFactor;
++      EVEL_OPTION_INT roundTripDelay;
++
++} END_OF_CALL_VOICE_QUALITY_METRICS;
++
++/**************************************************************************//**
++* Voice QUality.
++* JSON equivalent field: voiceQualityFields
++*****************************************************************************/
++
++typedef struct event_voiceQuality {
++      /***************************************************************************/
++      /* Header and version                                                      */
++      /***************************************************************************/
++      EVENT_HEADER header;
++      int major_version;
++      int minor_version;
++
++      /***************************************************************************/
++      /* Mandatory fields                                                        */
++      /***************************************************************************/
++      
++      char *calleeSideCodec;
++      char *callerSideCodec;
++      char *correlator;
++      char *midCallRtcp;
++      VENDOR_VNFNAME_FIELD vendorVnfNameFields;
++      END_OF_CALL_VOICE_QUALITY_METRICS *endOfCallVqmSummaries;
++
++      /***************************************************************************/
++      /* Optional fields                                                         */
++      /***************************************************************************/
++      EVEL_OPTION_STRING phoneNumber;
++      DLIST additionalInformation;
++
++} EVENT_VOICE_QUALITY;
++/**************************************************************************//**
++ * Voice Quality Additional Info.
++ * JSON equivalent field: additionalInformation
++ *****************************************************************************/
++typedef struct voice_quality_additional_info {
++  char * name;
++  char * value;
++} VOICE_QUALITY_ADDL_INFO;
++
++/**************************************************************************//**
++ * Create a new voice quality event.
++ *
++ * @note    The mandatory fields on the Voice Quality must be supplied to this 
++ *          factory function and are immutable once set.  Optional fields have 
++ *          explicit setter functions, but again values may only be set once 
++ *          so that the Voice Quality has immutable properties.
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param   calleeSideCodec                   Callee codec for the call.
++ * @param   callerSideCodec                   Caller codec for the call.
++ * @param   correlator                                Constant across all events on this call.
++ * @param   midCallRtcp                               Base64 encoding of the binary RTCP data
++ *                                                                    (excluding Eth/IP/UDP headers).
++ * @param   vendorVnfNameFields               Vendor, VNF and VfModule names.
++ * @returns pointer to the newly manufactured ::EVENT_VOICE_QUALITY.  If the 
++ *          event is not used (i.e. posted) it must be released using
++                      ::evel_free_voice_quality.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id,
++      const char * const calleeSideCodec,
++      const char * const callerSideCodec, const char * const correlator,
++      const char * const midCallRtcp, const char * const vendorVnfNameFields);
++
++/**************************************************************************//**
++ * Set the Callee side codec for Call for domain Voice Quality
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param voiceQuality                                Pointer to the Voice Quality Event.
++ * @param calleeCodecForCall          The Callee Side Codec to be set.  ASCIIZ 
++ *                                                                    string. The caller does not need to 
++ *                                                                    preserve the value once the function
++ *                                                                    returns.
++ *****************************************************************************/
++void evel_voice_quality_callee_codec_set(EVENT_VOICE_QUALITY * voiceQuality,
++                                                                      const char * const calleeCodecForCall);
++
++/**************************************************************************//**
++ * Set the Caller side codec for Call for domain Voice Quality
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param voiceQuality                                Pointer to the Voice Quality Event.
++ * @param callerCodecForCall          The Caller Side Codec to be set.  ASCIIZ 
++ *                                                                    string. The caller does not need to 
++ *                                                                    preserve the value once the function
++ *                                                                    returns.
++ *****************************************************************************/
++void evel_voice_quality_caller_codec_set(EVENT_VOICE_QUALITY * voiceQuality,
++                                                                      const char * const callerCodecForCall);
++
++/**************************************************************************//**
++ * Set the correlator for domain Voice Quality
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param voiceQuality                                Pointer to the Voice Quality Event.
++ * @param correlator                          The correlator value to be set.  ASCIIZ 
++ *                                                                    string. The caller does not need to 
++ *                                                                    preserve the value once the function
++ *                                                                    returns.
++ *****************************************************************************/
++void evel_voice_quality_correlator_set(EVENT_VOICE_QUALITY * voiceQuality,
++                                                                      const char * const vCorrelator);
++
++/**************************************************************************//**
++ * Set the RTCP Call Data for domain Voice Quality
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param voiceQuality                                Pointer to the Voice Quality Event.
++ * @param rtcpCallData                        The RTCP Call Data to be set.  ASCIIZ 
++ *                                                                    string. The caller does not need to 
++ *                                                                    preserve the value once the function
++ *                                                                    returns.
++ *****************************************************************************/
++void evel_voice_quality_rtcp_data_set(EVENT_VOICE_QUALITY * voiceQuality,
++                                                                      const char * const rtcpCallData);
++
++/**************************************************************************//**
++ * Set the Vendor VNF Name fields for domain Voice Quality
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param voiceQuality                                Pointer to the Voice Quality Event.
++ * @param nameFields                  The Vendor, VNF and VfModule names to be set.   
++ *                                                                    ASCIIZ string. The caller does not need to 
++ *                                                                    preserve the value once the function
++ *                                                                    returns.
++ *****************************************************************************/
++void evel_voice_quality_name_fields_set(EVENT_VOICE_QUALITY * voiceQuality,
++                                                                      const char * const nameFields);
++
++/**************************************************************************//**
++ * Add an End of Call Voice Quality Metrices
++
++ * The adjacencyName and endpointDescription is null delimited ASCII string.  
++ * The library takes a copy so the caller does not have to preserve values
++ * after the function returns.
++ *
++ * @param voiceQuality     Pointer to the measurement.
++ * @param adjacencyName                                               Adjacency name
++ * @param endpointDescription                         Enumeration: â€˜Caller’, â€˜Callee’.
++ * @param endpointJitter                                      Endpoint jitter
++ * @param endpointRtpOctetsDiscarded        Endpoint RTP octets discarded.
++ * @param endpointRtpOctetsReceived                   Endpoint RTP octets received.
++ * @param endpointRtpOctetsSent                               Endpoint RTP octets sent
++ * @param endpointRtpPacketsDiscarded         Endpoint RTP packets discarded.
++ * @param endpointRtpPacketsReceived          Endpoint RTP packets received.
++ * @param endpointRtpPacketsSent                      Endpoint RTP packets sent.
++ * @param localJitter                                         Local jitter.
++ * @param localRtpOctetsDiscarded                     Local RTP octets discarded.
++ * @param localRtpOctetsReceived                      Local RTP octets received.
++ * @param localRtpOctetsSent                          Local RTP octets sent.
++ * @param localRtpPacketsDiscarded                    Local RTP packets discarded.
++ * @param localRtpPacketsReceived                     Local RTP packets received.
++ * @param localRtpPacketsSent                         Local RTP packets sent.
++ * @param mosCqe                                                      Decimal range from 1 to 5
++ *                                                                                    (1 decimal place)
++ * @param packetsLost                                         No      Packets lost
++ * @param packetLossPercent                                   Calculated percentage packet loss 
++ * @param rFactor                                                     rFactor from 0 to 100
++ * @param roundTripDelay                                      Round trip delay in milliseconds
++ *****************************************************************************/
++void evel_voice_quality_end_metrics_add(EVENT_VOICE_QUALITY * voiceQuality,
++      const char * adjacencyName, EVEL_SERVICE_ENDPOINT_DESC endpointDescription,
++      int endpointJitter,
++      int endpointRtpOctetsDiscarded,
++      int endpointRtpOctetsReceived,
++      int endpointRtpOctetsSent,
++      int endpointRtpPacketsDiscarded,
++      int endpointRtpPacketsReceived,
++      int endpointRtpPacketsSent,
++      int localJitter,
++      int localRtpOctetsDiscarded,
++      int localRtpOctetsReceived,
++      int localRtpOctetsSent,
++      int localRtpPacketsDiscarded,
++      int localRtpPacketsReceived,
++      int localRtpPacketsSent,
++      int mosCqe,
++      int packetsLost,
++      int packetLossPercent,
++      int rFactor,
++      int roundTripDelay);
++
++/**************************************************************************//**
++ * Free a Voice Quality.
++ *
++ * Free off the Voce Quality supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the Voice Quality itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_voice_quality(EVENT_VOICE_QUALITY * voiceQuality);
++
++/**************************************************************************//**
++ * Add an additional value name/value pair to the Voice Quality.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param fault     Pointer to the fault.
++ * @param name      ASCIIZ string with the attribute's name.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ * @param value     ASCIIZ string with the attribute's value.  The caller
++ *                  does not need to preserve the value once the function
++ *                  returns.
++ *****************************************************************************/
++void evel_voice_quality_addl_info_add(EVENT_VOICE_QUALITY * voiceQuality, char * name, char * value);
++
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   THRESHOLD CROSSING ALERT                                                */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++typedef enum evel_event_action {
++        EVEL_EVENT_ACTION_CLEAR,
++        EVEL_EVENT_ACTION_CONTINUE,
++        EVEL_EVENT_ACTION_SET,
++        EVEL_MAX_EVENT_ACTION
++}EVEL_EVENT_ACTION;
++      
++typedef enum evel_alert_type {
++         EVEL_CARD_ANOMALY, 
++       EVEL_ELEMENT_ANOMALY, 
++       EVEL_INTERFACE_ANOMALY, 
++       EVEL_SERVICE_ANOMALY,
++         EVEL_MAX_ANOMALY
++}EVEL_ALERT_TYPE;
++
++
++typedef struct perf_counter {
++      char * criticality;
++      char * name;
++      char * thresholdCrossed;
++      char * value;
++}PERF_COUNTER;
++
++
++/*****************************************************************************/
++/* Supported Threshold Crossing version.                                     */
++/*****************************************************************************/
++#define EVEL_THRESHOLD_CROSS_MAJOR_VERSION 1
++#define EVEL_THRESHOLD_CROSS_MINOR_VERSION 1
++
++/**************************************************************************//**
++ * Threshold Crossing.
++ * JSON equivalent field: Threshold Cross Fields
++ *****************************************************************************/
++typedef struct event_threshold_cross {
++  /***************************************************************************/
++  /* Header and version                                                      */
++  /***************************************************************************/
++  EVENT_HEADER header;
++  int major_version;
++  int minor_version;
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /***************************************************************************/
++  PERF_COUNTER additionalParameters;
++  EVEL_EVENT_ACTION  alertAction;
++  char *             alertDescription; 
++  EVEL_ALERT_TYPE    alertType;
++  unsigned long long collectionTimestamp; 
++  EVEL_SEVERITIES    eventSeverity;
++  unsigned long long eventStartTimestamp;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /***************************************************************************/
++  DLIST additional_info;
++  EVEL_OPTION_STRING    alertValue;
++  DLIST     alertidList;
++  EVEL_OPTION_STRING    dataCollector;
++  EVEL_OPTION_STRING    elementType;
++  EVEL_OPTION_STRING    interfaceName;
++  EVEL_OPTION_STRING    networkService;
++  EVEL_OPTION_STRING    possibleRootCause;
++
++} EVENT_THRESHOLD_CROSS;
++
++
++/**************************************************************************//**
++ * Create a new Threshold Crossing Alert event.
++ *
++ * @note    The mandatory fields on the TCA must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          TCA has immutable properties.
++ *
++ * @param event_name    Unique Event Name
++ * @param event_id    A universal identifier of the event for analysis etc
++ * @param char* tcriticality   Performance Counter Criticality MAJ MIN,
++ * @param char* tname          Performance Counter Threshold name
++ * @param char* tthresholdCrossed  Counter Threshold crossed value
++ * @param char* tvalue             Counter actual value
++ * @param EVEL_EVENT_ACTION talertAction   Alert set continue or clear
++ * @param char*  talertDescription
++ * @param EVEL_ALERT_TYPE     talertType    Kind of anamoly
++ * @param unsigned long long  tcollectionTimestamp time at which alert was collected
++ * @param EVEL_SEVERITIES     teventSeverity  Severity of Alert
++ * @param unsigned long long  teventStartTimestamp Time when this alert started
++ *
++ * @returns pointer to the newly manufactured ::EVENT_THRESHOLD_CROSS.  If the
++ *          event is not used it must be released using
++ *          ::evel_free_threshold_cross
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_THRESHOLD_CROSS * evel_new_threshold_cross(
++                              const char* ev_name, const char *ev_id,
++                               char * tcriticality,
++                             char * tname,
++                             char * tthresholdCrossed,
++                             char * tvalue,
++                               EVEL_EVENT_ACTION  talertAction,
++                               char *             talertDescription, 
++                               EVEL_ALERT_TYPE    talertType,
++                               unsigned long long tcollectionTimestamp, 
++                               EVEL_SEVERITIES    teventSeverity,
++                               unsigned long long teventStartTimestamp);
++
++/**************************************************************************//**
++ * Free a Threshold cross event.
++ *
++ * Free off the Threshold crossing event supplied.  Will free all the contained allocated
++ * memory.
++ *
++ * @note It does not free the Threshold Cross itself, since that may be part of a
++ * larger structure.
++ *****************************************************************************/
++void evel_free_threshold_cross(EVENT_THRESHOLD_CROSS * const tcp);
++
++/**************************************************************************//**
++ * Set the Event Type property of the Threshold Cross.
++ *
++ * @note  The property is treated as immutable: it is only valid to call
++ *        the setter once.  However, we don't assert if the caller tries to
++ *        overwrite, just ignoring the update instead.
++ *
++ * @param tcp  Pointer to the ::EVENT_THRESHOLD_CROSS.
++ * @param type          The Event Type to be set. ASCIIZ string. The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_threshold_cross_type_set(EVENT_THRESHOLD_CROSS * const tcp, char * type);
++
++/**************************************************************************//**
++ * Add an optional additional alertid value to Alert.
++ *
++ * @param alertid  Adds Alert ID
++ *****************************************************************************/
++void evel_threshold_cross_alertid_add(EVENT_THRESHOLD_CROSS * const event,char *  alertid);
++
++  /**************************************************************************//**
++   * Set the TCA probable Root cause.
++   *
++   * @param sheader     Possible root cause to Threshold
++   *****************************************************************************/
++  void evel_threshold_cross_possible_rootcause_set(EVENT_THRESHOLD_CROSS * const event, char *  sheader);
++  /**************************************************************************//**
++   * Set the TCA networking cause.
++   *
++   * @param sheader     Possible networking service value to Threshold
++   *****************************************************************************/
++  void evel_threshold_cross_networkservice_set(EVENT_THRESHOLD_CROSS * const event, char *  sheader);
++  /**************************************************************************//**
++   * Set the TCA Interface name.
++   *
++   * @param sheader     Interface name to threshold
++   *****************************************************************************/
++  void evel_threshold_cross_interfacename_set(EVENT_THRESHOLD_CROSS * const event,char *  sheader);
++  /**************************************************************************//**
++   * Set the TCA Data element type.
++   *
++   * @param sheader     element type of Threshold
++   *****************************************************************************/
++  void evel_threshold_cross_data_elementtype_set(EVENT_THRESHOLD_CROSS * const event,char *  sheader);
++  /**************************************************************************//**
++   * Set the TCA Data collector value.
++   *
++   * @param sheader     Data collector value
++   *****************************************************************************/
++  void evel_threshold_cross_data_collector_set(EVENT_THRESHOLD_CROSS * const event,char *  sheader);
++  /**************************************************************************//**
++   * Set the TCA alert value.
++   *
++   * @param sheader     Possible alert value
++   *****************************************************************************/
++  void evel_threshold_cross_alertvalue_set(EVENT_THRESHOLD_CROSS * const event,char *  sheader);
++
++/**************************************************************************//**
++ * Add an additional field name/value pair to the THRESHOLD CROSS event.
++ *
++ * The name and value are null delimited ASCII strings.  The library takes
++ * a copy so the caller does not have to preserve values after the function
++ * returns.
++ *
++ * @param state_change  Pointer to the ::EVENT_THRESHOLD_CROSS.
++ * @param name          ASCIIZ string with the attribute's name.  The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ * @param value         ASCIIZ string with the attribute's value.  The caller
++ *                      does not need to preserve the value once the function
++ *                      returns.
++ *****************************************************************************/
++void evel_threshold_cross_addl_info_add(EVENT_THRESHOLD_CROSS * const tcp,
++                                      const char * const name,
++                                      const char * const value);
++
++/*****************************************************************************/
++/*****************************************************************************/
++/*                                                                           */
++/*   LOGGING                                                                 */
++/*                                                                           */
++/*****************************************************************************/
++/*****************************************************************************/
++
++/*****************************************************************************/
++/* Debug macros.                                                             */
++/*****************************************************************************/
++#define EVEL_DEBUG(FMT, ...)   log_debug(EVEL_LOG_DEBUG, (FMT), ##__VA_ARGS__)
++#define EVEL_INFO(FMT, ...)    log_debug(EVEL_LOG_INFO, (FMT), ##__VA_ARGS__)
++#define EVEL_SPAMMY(FMT, ...)  log_debug(EVEL_LOG_SPAMMY, (FMT), ##__VA_ARGS__)
++#define EVEL_ERROR(FMT, ...)   log_debug(EVEL_LOG_ERROR, "ERROR: " FMT, \
++                                         ##__VA_ARGS__)
++#define EVEL_ENTER()                                                          \
++        {                                                                     \
++          log_debug(EVEL_LOG_DEBUG, "Enter %s {", __FUNCTION__);              \
++          debug_indent += 2;                                                  \
++        }
++#define EVEL_EXIT()                                                           \
++        {                                                                     \
++          debug_indent -= 2;                                                  \
++          log_debug(EVEL_LOG_DEBUG, "Exit %s }", __FUNCTION__);               \
++        }
++
++#define INDENT_SEPARATORS                                                     \
++        "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "
++
++extern EVEL_LOG_LEVELS debug_level;
++extern int debug_indent;
++extern FILE * fout;
++
++#define EVEL_DEBUG_ON() ((debug_level) >= EVEL_LOG_DEBUG)
++
++/**************************************************************************//**
++ * Initialize logging
++ *
++ * @param[in] level  The debugging level - one of ::EVEL_LOG_LEVELS.
++ * @param[in] ident  The identifier for our logs.
++ *****************************************************************************/
++void log_initialize(EVEL_LOG_LEVELS level, const char * ident);
++
++/**************************************************************************//**
++ * Log debug information
++ *
++ * Logs debugging information in a platform independent manner.
++ *
++ * @param[in] level   The debugging level - one of ::EVEL_LOG_LEVELS.
++ * @param[in] format  Log formatting string in printf format.
++ * @param[in] ...     Variable argument list.
++ *****************************************************************************/
++void log_debug(EVEL_LOG_LEVELS level, char * format, ...);
++
++/***************************************************************************//*
++ * Store the formatted string into the static error string and log the error.
++ *
++ * @param format  Error string in standard printf format.
++ * @param ...     Variable parameters to be substituted into the format string.
++ *****************************************************************************/
++void log_error_state(char * format, ...);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
++
+diff --git a/src/plugins/ves/include/evel_internal.h b/src/plugins/ves/include/evel_internal.h
+new file mode 100644
+index 00000000..46f71af1
+--- /dev/null
++++ b/src/plugins/ves/include/evel_internal.h
+@@ -0,0 +1,858 @@
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++/**************************************************************************//**
++ * @file
++ * EVEL internal definitions.
++ *
++ * These are internal definitions which need to be shared between modules
++ * within the library but are not intended for external consumption.
++ *
++ ****************************************************************************/
++
++#ifndef EVEL_INTERNAL_INCLUDED
++#define EVEL_INTERNAL_INCLUDED
++
++#include "evel.h"
++
++/*****************************************************************************/
++/* Define some type-safe min/max macros.                                     */
++/*****************************************************************************/
++#define max(a,b) \
++   ({ __typeof__ (a) _a = (a); \
++       __typeof__ (b) _b = (b); \
++     _a > _b ? _a : _b; })
++
++#define min(a,b) \
++   ({ __typeof__ (a) _a = (a); \
++       __typeof__ (b) _b = (b); \
++     _a < _b ? _a : _b; })
++
++
++/**************************************************************************//**
++ * Compile-time assertion.
++ *****************************************************************************/
++#define EVEL_CT_ASSERT(X) switch (0) {case 0: case (X):;}
++
++/**************************************************************************//**
++ * The Functional Role of the equipment represented by this VNF.
++ *****************************************************************************/
++extern char * functional_role;
++
++/**************************************************************************//**
++ * The type of equipment represented by this VNF.
++ *****************************************************************************/
++extern EVEL_SOURCE_TYPES event_source_type;
++
++/**************************************************************************//**
++ * A chunk of memory used in the cURL functions.
++ *****************************************************************************/
++typedef struct memory_chunk {
++  char * memory;
++  size_t size;
++} MEMORY_CHUNK;
++
++/**************************************************************************//**
++ * Global commands that may be sent to the Event Handler thread.
++ *****************************************************************************/
++typedef enum {
++  EVT_CMD_TERMINATE,
++  EVT_CMD_MAX_COMMANDS
++} EVT_HANDLER_COMMAND;
++
++/**************************************************************************//**
++ * State of the Event Handler thread.
++ *****************************************************************************/
++typedef enum {
++  EVT_HANDLER_UNINITIALIZED,      /** The library cannot handle events.      */
++  EVT_HANDLER_INACTIVE,           /** The event handler thread not started.  */
++  EVT_HANDLER_ACTIVE,             /** The event handler thread is started.   */
++  EVT_HANDLER_REQUEST_TERMINATE,  /** Initial stages of shutdown.            */
++  EVT_HANDLER_TERMINATING,        /** The ring-buffer is being depleted.     */
++  EVT_HANDLER_TERMINATED,         /** The library is exited.                 */
++  EVT_HANDLER_MAX_STATES          /** Maximum number of valid states.        */
++} EVT_HANDLER_STATE;
++
++/**************************************************************************//**
++ * Internal event.
++ * Pseudo-event used for routing internal commands.
++ *****************************************************************************/
++typedef struct event_internal {
++  EVENT_HEADER header;
++  EVT_HANDLER_COMMAND command;
++} EVENT_INTERNAL;
++
++/**************************************************************************//**
++ * Suppressed NV pairs list entry.
++ * JSON equivalent field: suppressedNvPairs
++ *****************************************************************************/
++typedef struct evel_suppressed_nv_pairs {
++
++  /***************************************************************************/
++  /* Mandatory fields                                                        */
++  /* JSON equivalent field: nvPairFieldName                                  */
++  /***************************************************************************/
++  char * nv_pair_field_name;
++
++  /***************************************************************************/
++  /* Optional fields                                                         */
++  /* JSON equivalent field: suppressedNvPairNames                            */
++  /* Type of each list entry: char *                                         */
++  /***************************************************************************/
++  DLIST suppressed_nv_pair_names;
++
++  /***************************************************************************/
++  /* Hash table containing suppressed_nv_pair_names as keys.                 */
++  /***************************************************************************/
++  struct hsearch_data * hash_nv_pair_names;
++
++} EVEL_SUPPRESSED_NV_PAIRS;
++
++/**************************************************************************//**
++ * Event Throttling Specification for a domain which is in a throttled state.
++ * JSON equivalent object: eventThrottlingState
++ *****************************************************************************/
++typedef struct evel_throttle_spec {
++
++  /***************************************************************************/
++  /* List of field names to be suppressed.                                   */
++  /* JSON equivalent field: suppressedFieldNames                             */
++  /* Type of each list entry: char *                                         */
++  /***************************************************************************/
++  DLIST suppressed_field_names;
++
++  /***************************************************************************/
++  /* List of name-value pairs to be suppressed.                              */
++  /* JSON equivalent field: suppressedNvPairsList                            */
++  /* Type of each list entry: EVEL_SUPPRESSED_NV_PAIRS *                     */
++  /***************************************************************************/
++  DLIST suppressed_nv_pairs_list;
++
++  /***************************************************************************/
++  /* Hash table containing suppressed_nv_pair_names as keys.                 */
++  /***************************************************************************/
++  struct hsearch_data * hash_field_names;
++
++  /***************************************************************************/
++  /* Hash table containing nv_pair_field_name as keys, and                   */
++  /* suppressed_nv_pairs_list as values.                                     */
++  /***************************************************************************/
++  struct hsearch_data * hash_nv_pairs_list;
++
++} EVEL_THROTTLE_SPEC;
++
++/*****************************************************************************/
++/* RFC2822 format string for strftime.                                       */
++/*****************************************************************************/
++#define EVEL_RFC2822_STRFTIME_FORMAT "%a, %d %b %Y %T %z"
++
++/*****************************************************************************/
++/* EVEL_JSON_BUFFER depth at which we throttle fields.                       */
++/*****************************************************************************/
++#define EVEL_THROTTLE_FIELD_DEPTH 3
++
++/**************************************************************************//**
++ * Initialize the event handler.
++ *
++ * Primarily responsible for getting cURL ready for use.
++ *
++ * @param[in] event_api_url
++ *                      The URL where the Vendor Event Listener API is expected
++ *                      to be.
++ * @param[in] throt_api_url
++ *                      The URL where the Throttling API is expected to be.
++ * @param[in] username  The username for the Basic Authentication of requests.
++ * @param[in] password  The password for the Basic Authentication of requests.
++ * @param     verbosity 0 for normal operation, positive values for chattier
++ *                        logs.
++ *****************************************************************************/
++EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
++                                        const char * const throt_api_url,
++                                        const char * const username,
++                                        const char * const password,
++                                        int verbosity);
++
++/**************************************************************************//**
++ * Terminate the event handler.
++ *
++ * Shuts down the event handler thread in as clean a way as possible. Sets the
++ * global exit flag and then signals the thread to interrupt it since it's
++ * most likely waiting on the ring-buffer.
++ *
++ * Having achieved an orderly shutdown of the event handler thread, clean up
++ * the cURL library's resources cleanly.
++ *
++ *  @return Status code.
++ *  @retval ::EVEL_SUCCESS if everything OK.
++ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
++ *****************************************************************************/
++EVEL_ERR_CODES event_handler_terminate();
++
++/**************************************************************************//**
++ * Run the event handler.
++ *
++ * Spawns the thread responsible for handling events and sending them to the
++ * API.
++ *
++ *  @return Status code.
++ *  @retval ::EVEL_SUCCESS if everything OK.
++ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
++ *****************************************************************************/
++EVEL_ERR_CODES event_handler_run();
++
++/**************************************************************************//**
++ * Create a new internal event.
++ *
++ * @note    The mandatory fields on the Fault must be supplied to this factory
++ *          function and are immutable once set.  Optional fields have explicit
++ *          setter functions, but again values may only be set once so that the
++ *          Fault has immutable properties.
++ * @param   command   The condition indicated by the event.
++ * @returns pointer to the newly manufactured ::EVENT_INTERNAL.  If the event
++ *          is not used (i.e. posted) it must be released using
++ *          ::evel_free_event.
++ * @retval  NULL  Failed to create the event.
++ *****************************************************************************/
++EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command,const char* ev_name, const char *ev_id);
++
++/**************************************************************************//**
++ * Free an internal event.
++ *
++ * Free off the event supplied.  Will free all the contained* allocated memory.
++ *
++ * @note It does not free the internal event itself, since that may be part of
++ * a larger structure.
++ *****************************************************************************/
++void evel_free_internal_event(EVENT_INTERNAL * event);
++
++/*****************************************************************************/
++/* Structure to hold JSON buffer and associated tracking, as it is written.  */
++/*****************************************************************************/
++typedef struct evel_json_buffer
++{
++  char * json;
++  int offset;
++  int max_size;
++
++  /***************************************************************************/
++  /* The working throttle specification, which can be NULL.                  */
++  /***************************************************************************/
++  EVEL_THROTTLE_SPEC * throttle_spec;
++
++  /***************************************************************************/
++  /* Current object/list nesting depth.                                      */
++  /***************************************************************************/
++  int depth;
++
++  /***************************************************************************/
++  /* The checkpoint.                                                         */
++  /***************************************************************************/
++  int checkpoint;
++
++} EVEL_JSON_BUFFER;
++
++/**************************************************************************//**
++ * Encode the event as a JSON event object according to AT&T's schema.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_header(EVEL_JSON_BUFFER * jbuf,
++                             EVENT_HEADER * event);
++
++/**************************************************************************//**
++ * Encode the fault in JSON according to AT&T's schema for the fault type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_fault(EVEL_JSON_BUFFER * jbuf,
++                            EVENT_FAULT * event);
++
++/**************************************************************************//**
++ * Encode the measurement as a JSON measurement.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf,
++                                  EVENT_MEASUREMENT * event);
++
++/**************************************************************************//**
++ * Encode the Mobile Flow in JSON according to AT&T's schema for the event
++ * type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_mobile_flow(EVEL_JSON_BUFFER * jbuf,
++                                  EVENT_MOBILE_FLOW * event);
++
++/**************************************************************************//**
++ * Encode the report as a JSON report.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
++                             EVENT_REPORT * event);
++
++/**************************************************************************//**
++ * Encode the Heartbeat fields in JSON according to AT&T's schema for the
++ * event type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_hrtbt_field(EVEL_JSON_BUFFER * const jbuf,
++                                EVENT_HEARTBEAT_FIELD * const event);
++
++/**************************************************************************//**
++ * Encode the Signaling in JSON according to AT&T's schema for the event type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_signaling(EVEL_JSON_BUFFER * const jbuf,
++                                EVENT_SIGNALING * const event);
++
++/**************************************************************************//**
++ * Encode the state change as a JSON state change.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE to encode.
++ *****************************************************************************/
++void evel_json_encode_state_change(EVEL_JSON_BUFFER * jbuf,
++                                   EVENT_STATE_CHANGE * state_change);
++
++/**************************************************************************//**
++ * Encode the Syslog in JSON according to AT&T's schema for the event type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_syslog(EVEL_JSON_BUFFER * jbuf,
++                             EVENT_SYSLOG * event);
++
++/**************************************************************************//**
++ * Encode the Other in JSON according to AT&T's schema for the event type.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
++ * @param event         Pointer to the ::EVENT_HEADER to encode.
++ *****************************************************************************/
++void evel_json_encode_other(EVEL_JSON_BUFFER * jbuf,
++                            EVENT_OTHER * event);
++
++/**************************************************************************//**
++ * Set the next event_sequence to use.
++ *
++ * @param sequence      The next sequence number to use.
++ *****************************************************************************/
++void evel_set_next_event_sequence(const int sequence);
++
++/**************************************************************************//**
++ * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK.
++ *
++ * Tokenize the response, and decode any tokens found.
++ *
++ * @param chunk         The memory chunk containing the response.
++ * @param post          The memory chunk in which to place any resulting POST.
++ *****************************************************************************/
++void evel_handle_event_response(const MEMORY_CHUNK * const chunk,
++                                MEMORY_CHUNK * const post);
++
++/**************************************************************************//**
++ * Initialize a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to initialise.
++ * @param json          Pointer to the underlying working buffer to use.
++ * @param max_size      Size of storage available in the JSON buffer.
++ * @param throttle_spec Pointer to throttle specification. Can be NULL.
++ *****************************************************************************/
++void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
++                           char * const json,
++                           const int max_size,
++                           EVEL_THROTTLE_SPEC * throttle_spec);
++
++/**************************************************************************//**
++ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param option        Pointer to holder of the corresponding value to encode.
++ * @return true if the key, value was added, false if it was suppressed.
++ *****************************************************************************/
++bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
++                            const char * const key,
++                            const EVEL_OPTION_STRING * const option);
++
++/**************************************************************************//**
++ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param value         Pointer to the corresponding value to encode.
++ *****************************************************************************/
++void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
++                        const char * const key,
++                        const char * const value);
++
++/**************************************************************************//**
++ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param option        Pointer to holder of the corresponding value to encode.
++ * @return true if the key, value was added, false if it was suppressed.
++ *****************************************************************************/
++bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
++                         const char * const key,
++                         const EVEL_OPTION_INT * const option);
++
++/**************************************************************************//**
++ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param value         The corresponding value to encode.
++ *****************************************************************************/
++void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
++                     const char * const key,
++                     const int value);
++
++/**************************************************************************//**
++ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param option        Pointer to holder of the corresponding value to encode.
++ * @return true if the key, value was added, false if it was suppressed.
++ *****************************************************************************/
++bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
++                            const char * const key,
++                            const EVEL_OPTION_DOUBLE * const option);
++
++/**************************************************************************//**
++ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param value         The corresponding value to encode.
++ *****************************************************************************/
++void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
++                        const char * const key,
++                        const double value);
++
++/**************************************************************************//**
++ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param option        Pointer to holder of the corresponding value to encode.
++ * @return true if the key, value was added, false if it was suppressed.
++ *****************************************************************************/
++bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
++                         const char * const key,
++                         const EVEL_OPTION_ULL * const option);
++
++/**************************************************************************//**
++ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param value         The corresponding value to encode.
++ *****************************************************************************/
++void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
++                     const char * const key,
++                     const unsigned long long value);
++
++/**************************************************************************//**
++ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param option        Pointer to holder of the corresponding value to encode.
++ * @return true if the key, value was added, false if it was suppressed.
++ *****************************************************************************/
++bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
++                          const char * const key,
++                          const EVEL_OPTION_TIME * const option);
++
++/**************************************************************************//**
++ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param time          Pointer to the time to encode.
++ *****************************************************************************/
++void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
++                      const char * const key,
++                      const time_t * time);
++
++/**************************************************************************//**
++ * Encode a key and version.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @param major_version The major version to encode.
++ * @param minor_version The minor version to encode.
++ *****************************************************************************/
++void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
++                      const char * const key,
++                      const int major_version,
++                      const int minor_version);
++
++/**************************************************************************//**
++ * Add the key and opening bracket of an optional named list to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @return true if the list was opened, false if it was suppressed.
++ *****************************************************************************/
++bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
++                                   const char * const key);
++
++/**************************************************************************//**
++ * Add the key and opening bracket of a named list to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ *****************************************************************************/
++void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
++                               const char * const key);
++
++/**************************************************************************//**
++ * Add the closing bracket of a list to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ *****************************************************************************/
++void evel_json_close_list(EVEL_JSON_BUFFER * jbuf);
++
++/**************************************************************************//**
++ * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param format        Format string in standard printf format.
++ * @param ...           Variable parameters for format string.
++ *****************************************************************************/
++void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
++                        const char * const format,
++                        ...);
++
++/**************************************************************************//**
++ * Add the opening bracket of an optional named object to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ *****************************************************************************/
++bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
++                                     const char * const key);
++
++/**************************************************************************//**
++ * Add the opening bracket of an object to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ * @param key           Pointer to the key to encode.
++ * @return true if the object was opened, false if it was suppressed.
++ *****************************************************************************/
++void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
++                                 const char * const key);
++
++/**************************************************************************//**
++ * Add the opening bracket of an object to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ *****************************************************************************/
++void evel_json_open_object(EVEL_JSON_BUFFER * jbuf);
++
++/**************************************************************************//**
++ * Add the closing bracket of an object to a JSON buffer.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ *****************************************************************************/
++void evel_json_close_object(EVEL_JSON_BUFFER * jbuf);
++
++/**************************************************************************//**
++ * Add a checkpoint - a stake in the ground to which we can rewind.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ *****************************************************************************/
++void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf);
++
++/**************************************************************************//**
++ * Rewind to the latest checkoint.
++ *
++ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
++ *****************************************************************************/
++void evel_json_rewind(EVEL_JSON_BUFFER * jbuf);
++
++/**************************************************************************//**
++ * Free the underlying resources of an ::EVEL_OPTION_STRING.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_STRING.
++ *****************************************************************************/
++void evel_free_option_string(EVEL_OPTION_STRING * const option);
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_STRING to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_STRING.
++ *****************************************************************************/
++void evel_init_option_string(EVEL_OPTION_STRING * const option);
++
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_STRING.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_STRING.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_string(EVEL_OPTION_STRING * const option,
++                            const char * const value,
++                            const char * const description);
++
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_STRING.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_STRING.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_string(EVEL_OPTION_STRING * const option,
++                              const char * const value);
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_INT to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INT.
++ *****************************************************************************/
++void evel_init_option_int(EVEL_OPTION_INT * const option);
++
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_INT.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INT.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_int(EVEL_OPTION_INT * const option,
++                           const int value);
++
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_INT.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INT.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_int(EVEL_OPTION_INT * const option,
++                         const int value,
++                         const char * const description);
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_DOUBLE to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
++ *****************************************************************************/
++void evel_init_option_double(EVEL_OPTION_DOUBLE * const option);
++
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_DOUBLE.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_double(EVEL_OPTION_DOUBLE * const option,
++                              const double value);
++
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_DOUBLE.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_double(EVEL_OPTION_DOUBLE * const option,
++                            const double value,
++                            const char * const description);
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_ULL to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_ULL.
++ *****************************************************************************/
++void evel_init_option_ull(EVEL_OPTION_ULL * const option);
++
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_ULL.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_ULL.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_ull(EVEL_OPTION_ULL * const option,
++                           const unsigned long long value);
++
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_ULL.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_ULL.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_ull(EVEL_OPTION_ULL * const option,
++                         const unsigned long long value,
++                         const char * const description);
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_TIME to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_TIME.
++ *****************************************************************************/
++void evel_init_option_time(EVEL_OPTION_TIME * const option);
++
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_TIME.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_TIME.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_time(EVEL_OPTION_TIME * const option,
++                            const time_t value);
++
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_TIME.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_TIME.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_time(EVEL_OPTION_TIME * const option,
++                          const time_t value,
++                          const char * const description);
++
++/**************************************************************************//**
++ * Map an ::EVEL_COUNTER_CRITICALITIES enum value to the equivalent string.
++ *
++ * @param criticality   The criticality to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_criticality(const EVEL_COUNTER_CRITICALITIES criticality);
++
++/**************************************************************************//**
++ * Map an ::EVEL_SEVERITIES enum value to the equivalent string.
++ *
++ * @param severity      The severity to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_severity(const EVEL_SEVERITIES severity);
++
++/**************************************************************************//**
++ * Map an ::EVEL_ALERT_ACTIONS enum value to the equivalent string.
++ *
++ * @param alert_action  The alert_action to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_alert_action(const EVEL_ALERT_ACTIONS alert_action);
++
++/**************************************************************************//**
++ * Map an ::EVEL_ALERT_TYPES enum value to the equivalent string.
++ *
++ * @param alert_type    The alert_type to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_alert_type(const EVEL_ALERT_TYPES alert_type);
++
++/**************************************************************************//**
++ * Map an ::EVEL_EVENT_DOMAINS enum value to the equivalent string.
++ *
++ * @param domain        The domain to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_event_domain(const EVEL_EVENT_DOMAINS domain);
++
++/**************************************************************************//**
++ * Map an ::EVEL_EVENT_PRIORITIES enum value to the equivalent string.
++ *
++ * @param priority      The priority to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_event_priority(const EVEL_EVENT_PRIORITIES priority);
++
++/**************************************************************************//**
++ * Map an ::EVEL_SOURCE_TYPES enum value to the equivalent string.
++ *
++ * @param source_type   The source type to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_source_type(const EVEL_SOURCE_TYPES source_type);
++
++/**************************************************************************//**
++ * Map an ::EVEL_VF_STATUSES enum value to the equivalent string.
++ *
++ * @param vf_status     The vf_status to convert.
++ * @returns The equivalent string.
++ *****************************************************************************/
++char * evel_vf_status(const EVEL_VF_STATUSES vf_status);
++
++/**************************************************************************//**
++ * Convert a ::EVEL_ENTITY_STATE to it's string form for JSON encoding.
++ *
++ * @param state         The entity state to encode.
++ *
++ * @returns the corresponding string
++ *****************************************************************************/
++char * evel_entity_state(const EVEL_ENTITY_STATE state);
++
++/**************************************************************************//**
++ * Convert a ::EVEL_SERVICE_ENDPOINT_DESC to string form for JSON encoding.
++ *
++ * @param endpoint_desc endpoint description to encode.
++ *
++ * @returns the corresponding string
++ *****************************************************************************/
++char * evel_service_endpoint_desc(const EVEL_ENTITY_STATE endpoint_desc);
++
++
++/**************************************************************************//**
++ * Initialize an ::EVEL_OPTION_INTHEADER_FIELDS to a not-set state.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS.
++ *****************************************************************************/
++void evel_init_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option);
++/**************************************************************************//**
++ * Force the value of an ::EVEL_OPTION_INTHEADER_FIELDS.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS.
++ * @param value         The value to set.
++ *****************************************************************************/
++void evel_force_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option,
++                           const void* value);
++/**************************************************************************//**
++ * Set the value of an ::EVEL_OPTION_INTHEADER_FIELDS.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS.
++ * @param value         The value to set.
++ * @param description   Description to be used in logging.
++ *****************************************************************************/
++void evel_set_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option,
++                         const void * value,
++                         const char * const description);
++/**************************************************************************//**
++ * Free the underlying resources of an ::EVEL_OPTION_INTHEADER_FIELDS.
++ *
++ * @param option        Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS.
++ *****************************************************************************/
++void evel_free_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option);
++
++#endif
+diff --git a/src/plugins/ves/include/evel_throttle.h b/src/plugins/ves/include/evel_throttle.h
+new file mode 100644
+index 00000000..c97b3c37
+--- /dev/null
++++ b/src/plugins/ves/include/evel_throttle.h
+@@ -0,0 +1,214 @@
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++/**************************************************************************//**
++ * @file
++ * EVEL throttle definitions.
++ *
++ * These are internal definitions related to throttling specicications, which
++ * are required within the library but are not intended for external
++ * consumption.
++ *
++ ****************************************************************************/
++
++#ifndef EVEL_THROTTLE_INCLUDED
++#define EVEL_THROTTLE_INCLUDED
++
++#include "evel_internal.h"
++#include "jsmn.h"
++
++/*****************************************************************************/
++/* Maximum depth of JSON response that we can handle.                        */
++/*****************************************************************************/
++#define EVEL_JSON_STACK_DEPTH           10
++
++/**************************************************************************//**
++ * Maximum number of tokens that we allow for in a JSON response.
++ *****************************************************************************/
++#define EVEL_MAX_RESPONSE_TOKENS        1024
++
++/**************************************************************************//**
++ * The nature of the next token that we are iterating through.  Within an
++ * object, we alternate between collecting keys and values.  Within an array,
++ * we only collect items.
++ *****************************************************************************/
++typedef enum {
++  EVEL_JSON_KEY,
++  EVEL_JSON_VALUE,
++  EVEL_JSON_ITEM
++} EVEL_JSON_STATE;
++
++/**************************************************************************//**
++ * States which we move through during JSON processing, tracking our way
++ * through the supported JSON structure.
++ *****************************************************************************/
++typedef enum
++{
++  /***************************************************************************/
++  /* Initial state.                                                          */
++  /***************************************************************************/
++  EVEL_JCS_START,
++
++  /***************************************************************************/
++  /* {"commandList": [                                                       */
++  /***************************************************************************/
++  EVEL_JCS_COMMAND_LIST,
++
++  /***************************************************************************/
++  /* {"commandList": [{                                                      */
++  /***************************************************************************/
++  EVEL_JCS_COMMAND_LIST_ENTRY,
++
++  /***************************************************************************/
++  /* {"commandList": [{"command": {                                          */
++  /***************************************************************************/
++  EVEL_JCS_COMMAND,
++
++  /***************************************************************************/
++  /* ... "eventDomainThrottleSpecification": {                               */
++  /***************************************************************************/
++  EVEL_JCS_SPEC,
++
++  /***************************************************************************/
++  /* ... "suppressedFieldNames": [                                           */
++  /***************************************************************************/
++  EVEL_JCS_FIELD_NAMES,
++
++  /***************************************************************************/
++  /* ... "suppressedNvPairsList": [                                          */
++  /***************************************************************************/
++  EVEL_JCS_PAIRS_LIST,
++
++  /***************************************************************************/
++  /* ... "suppressedNvPairsList": [{                                         */
++  /***************************************************************************/
++  EVEL_JCS_PAIRS_LIST_ENTRY,
++
++  /***************************************************************************/
++  /* ... "suppressedNvPairNames": [                                          */
++  /***************************************************************************/
++  EVEL_JCS_NV_PAIR_NAMES,
++
++  EVEL_JCS_MAX
++} EVEL_JSON_COMMAND_STATE;
++
++/**************************************************************************//**
++ * An entry in the JSON stack.
++ *****************************************************************************/
++typedef struct evel_json_stack_entry {
++
++  /***************************************************************************/
++  /* The number of elements required at this level.                          */
++  /***************************************************************************/
++  int num_required;
++
++  /***************************************************************************/
++  /* The number of elements collected at this level.                         */
++  /***************************************************************************/
++  int json_count;
++
++  /***************************************************************************/
++  /* The collection state at this level in the JSON stack.                   */
++  /***************************************************************************/
++  EVEL_JSON_STATE json_state;
++
++  /***************************************************************************/
++  /* The key being collected (if json_state is EVEL_JSON_VALUE), or NULL.    */
++  /***************************************************************************/
++  char * json_key;
++
++} EVEL_JSON_STACK_ENTRY;
++
++/**************************************************************************//**
++ * The JSON stack.
++ *****************************************************************************/
++typedef struct evel_json_stack {
++
++  /***************************************************************************/
++  /* The current position of the stack - starting at zero.                   */
++  /***************************************************************************/
++  int level;
++
++  /***************************************************************************/
++  /* The stack itself.                                                       */
++  /***************************************************************************/
++  EVEL_JSON_STACK_ENTRY entry[EVEL_JSON_STACK_DEPTH];
++
++  /***************************************************************************/
++  /* The underlying memory chunk.                                            */
++  /***************************************************************************/
++  const MEMORY_CHUNK * chunk;
++
++} EVEL_JSON_STACK;
++
++/**************************************************************************//**
++ * Initialize event throttling to the default state.
++ *
++ * Called from ::evel_initialize.
++ *****************************************************************************/
++void evel_throttle_initialize();
++
++/**************************************************************************//**
++ * Clean up event throttling.
++ *
++ * Called from ::evel_terminate.
++ *****************************************************************************/
++void evel_throttle_terminate();
++
++/**************************************************************************//**
++ * Handle a JSON response from the listener, as a list of tokens from JSMN.
++ *
++ * @param chunk         Memory chunk containing the JSON buffer.
++ * @param json_tokens   Array of tokens to handle.
++ * @param num_tokens    The number of tokens to handle.
++ * @param post          The memory chunk in which to place any resulting POST.
++ * @return true if the command was handled, false otherwise.
++ *****************************************************************************/
++bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
++                              const jsmntok_t * const json_tokens,
++                              const int num_tokens,
++                              MEMORY_CHUNK * const post);
++
++/**************************************************************************//**
++ * Return the ::EVEL_THROTTLE_SPEC for a given domain.
++ *
++ * @param domain        The domain for which to return state.
++ *****************************************************************************/
++EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain);
++
++/**************************************************************************//**
++ * Determine whether a field_name should be suppressed.
++ *
++ * @param throttle_spec Throttle specification for the domain being encoded.
++ * @param field_name    The field name to encoded or suppress.
++ * @return true if the field_name should be suppressed, false otherwise.
++ *****************************************************************************/
++bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
++                                  const char * const field_name);
++
++/**************************************************************************//**
++ * Determine whether a name-value pair should be allowed (not suppressed).
++ *
++ * @param throttle_spec Throttle specification for the domain being encoded.
++ * @param field_name    The field name holding the name-value pairs.
++ * @param name          The name of the name-value pair to encoded or suppress.
++ * @return true if the name-value pair should be suppressed, false otherwise.
++ *****************************************************************************/
++bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
++                                    const char * const field_name,
++                                    const char * const name);
++
++#endif
+diff --git a/src/plugins/ves/include/hashtable.h b/src/plugins/ves/include/hashtable.h
+new file mode 100644
+index 00000000..8be17dc1
+--- /dev/null
++++ b/src/plugins/ves/include/hashtable.h
+@@ -0,0 +1,97 @@
++#ifndef HASHTABLE_INCLUDED
++#define HASHTABLE_INCLUDED
++
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++/**************************************************************************//**
++ * @file
++ * A simple hashtable.
++ *
++ * @note  No thread protection so you will need to use appropriate
++ * synchronization if use spans multiple threads.
++*****************************************************************************/
++
++typedef struct entry_s {
++      char *key;
++      void *value;
++      struct entry_s *next;
++} ENTRY_T;
++
++/**************************************************************************//**
++ * Hashtable structure
++ *****************************************************************************/
++
++typedef struct hashtable_s {
++      size_t size;
++      struct entry_s **table; 
++} HASHTABLE_T;
++
++/**************************************************************************//**
++ * Hashtable initialization.
++ *
++ * Initialize the list supplied to be empty.
++ *
++ * @param   size  Size of hashtable
++
++ * @returns Hashtable pointer
++******************************************************************************/
++/* Create a new hashtable. */
++HASHTABLE_T *ht_create( size_t size );
++
++/**************************************************************************//**
++ * Hash a string for a particular hash table.
++ *
++ * Initialize the list supplied to be empty.
++ *
++ * @param   hashtable    Pointer to the hashtable
++ * @param   key          String
++
++ * @returns hashvalue
++******************************************************************************/
++size_t ht_hash( HASHTABLE_T *hashtable, char *key );
++
++/**************************************************************************//**
++ * Create a key-value pair.
++ *
++ * @param   key     key string
++ * @param   value   value string
++ *
++ * @returns hashtable entry
++******************************************************************************/
++ENTRY_T *ht_newpair( char *key, void *value );
++
++/**************************************************************************//**
++ * Insert a key-value pair into a hash table.
++ *
++ * @param   key     key string
++ * @param   value   value string
++ *
++ * @returns Nothing
++******************************************************************************/
++void ht_set( HASHTABLE_T *hashtable, char *key, void *value );
++
++/**************************************************************************//**
++ *  Retrieve a key-value pair from a hash table.
++ *
++ * @param   key     key string
++ *
++ * @returns  value string
++******************************************************************************/
++void *ht_get( HASHTABLE_T *hashtable, char *key );
++
++#endif
+diff --git a/src/plugins/ves/include/jsmn.h b/src/plugins/ves/include/jsmn.h
+new file mode 100644
+index 00000000..4ae6d9b4
+--- /dev/null
++++ b/src/plugins/ves/include/jsmn.h
+@@ -0,0 +1,93 @@
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++#ifndef __JSMN_H_
++#define __JSMN_H_
++
++#include <stddef.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * JSON type identifier. Basic types are:
++ *    o Object
++ *    o Array
++ *    o String
++ *    o Other primitive: number, boolean (true/false) or null
++ */
++typedef enum {
++      JSMN_UNDEFINED = 0,
++      JSMN_OBJECT = 1,
++      JSMN_ARRAY = 2,
++      JSMN_STRING = 3,
++      JSMN_PRIMITIVE = 4
++} jsmntype_t;
++
++enum jsmnerr {
++      /* Not enough tokens were provided */
++      JSMN_ERROR_NOMEM = -1,
++      /* Invalid character inside JSON string */
++      JSMN_ERROR_INVAL = -2,
++      /* The string is not a full JSON packet, more bytes expected */
++      JSMN_ERROR_PART = -3
++};
++
++/**
++ * JSON token description.
++ * @param             type    type (object, array, string etc.)
++ * @param             start   start position in JSON data string
++ * @param             end             end position in JSON data string
++ */
++typedef struct {
++      jsmntype_t type;
++      int start;
++      int end;
++      int size;
++#ifdef JSMN_PARENT_LINKS
++      int parent;
++#endif
++} jsmntok_t;
++
++/**
++ * JSON parser. Contains an array of token blocks available. Also stores
++ * the string being parsed now and current position in that string
++ */
++typedef struct {
++      unsigned int pos; /* offset in the JSON string */
++      unsigned int toknext; /* next token to allocate */
++      int toksuper; /* superior token node, e.g parent object or array */
++} jsmn_parser;
++
++/**
++ * Create JSON parser over an array of tokens
++ */
++void jsmn_init(jsmn_parser *parser);
++
++/**
++ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
++ * a single JSON object.
++ */
++int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
++              jsmntok_t *tokens, unsigned int num_tokens);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __JSMN_H_ */
+diff --git a/src/plugins/ves/include/metadata.h b/src/plugins/ves/include/metadata.h
+new file mode 100644
+index 00000000..1ee44092
+--- /dev/null
++++ b/src/plugins/ves/include/metadata.h
+@@ -0,0 +1,58 @@
++#ifndef METADATA_INCLUDED
++#define METADATA_INCLUDED
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++/**************************************************************************//**
++ * @file
++ * Wrap the OpenStack metadata service.
++ *
++ ****************************************************************************/
++
++#include "evel.h"
++
++/**************************************************************************//**
++ * Download metadata from the OpenStack metadata service.
++ *
++ * @param verbosity   Controls whether to generate debug to stdout.  Zero:
++ *                    none.  Non-zero: generate debug.
++ * @returns Status code
++ * @retval  EVEL_SUCCESS      On success
++ * @retval  ::EVEL_ERR_CODES  On failure.
++ *****************************************************************************/
++EVEL_ERR_CODES openstack_metadata(int verbosity);
++
++/**************************************************************************//**
++ * Initialize default values for vm_name and vm_uuid - for testing purposes.
++ *****************************************************************************/
++void openstack_metadata_initialize();
++
++/**************************************************************************//**
++ * Get the VM name provided by the metadata service.
++ *
++ * @returns VM name
++ *****************************************************************************/
++const char *openstack_vm_name();
++
++/**************************************************************************//**
++ * Get the VM UUID provided by the metadata service.
++ *
++ * @returns VM UUID
++ *****************************************************************************/
++const char *openstack_vm_uuid();
++
++#endif
+diff --git a/src/plugins/ves/include/ring_buffer.h b/src/plugins/ves/include/ring_buffer.h
+new file mode 100644
+index 00000000..1236b78b
+--- /dev/null
++++ b/src/plugins/ves/include/ring_buffer.h
+@@ -0,0 +1,96 @@
++/*************************************************************************//**
++ *
++ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *        http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ *
++ ****************************************************************************/
++
++#ifndef RING_BUFFER_INCLUDED
++#define RING_BUFFER_INCLUDED
++
++/**************************************************************************//**
++ * @file
++ * Ring  buffer to handle message requests.
++ *
++ ****************************************************************************/
++
++#include <pthread.h>
++
++/**************************************************************************//**
++ * Ring buffer structure.
++ *****************************************************************************/
++typedef struct ring_buffer
++{
++    int size;
++    int next_write;
++    int next_read;
++    void ** ring;
++    pthread_cond_t ring_cv;
++    pthread_mutex_t ring_mutex;
++} ring_buffer;
++
++/**************************************************************************//**
++ * Ring buffer initialization.
++ *
++ * Initialize the buffer supplied to the specified size.
++ *
++ * @param   buffer  Pointer to the ring-buffer to be initialized.
++ * @param   size    How many elements to be stored in the ring-buffer.
++ *
++ * @returns Nothing
++******************************************************************************/
++void ring_buffer_initialize(ring_buffer * buffer, int size);
++
++/**************************************************************************//**
++ * Read an element from a ring_buffer.
++ *
++ * Reads an element from the ring_buffer, advancing the next-read position.
++ * Operation is synchronized and therefore MT-safe.  Blocks if no data is
++ * available.
++ *
++ * @param   buffer  Pointer to the ring-buffer to be read.
++ *
++ * @returns Pointer to the element read from the buffer.
++******************************************************************************/
++void * ring_buffer_read(ring_buffer * buffer);
++
++/**************************************************************************//**
++ * Write an element into a ring_buffer.
++ *
++ * Writes an element into the ring_buffer, advancing the next-write position.
++ * Operation is synchronized and therefore MT-safe.  Fails if the buffer is
++ * full without blocking.
++ *
++ * @param   buffer  Pointer to the ring-buffer to be written.
++ * @param   msg     Pointer to data to be stored in the ring_buffer.
++ *
++ * @returns Number of items written.
++ * @retval  1       The data was written successfully.
++ * @retval  0       The ring_buffer was full so no data written.
++******************************************************************************/
++int ring_buffer_write(ring_buffer * buffer, void * msg);
++
++/**************************************************************************//**
++ * Tests whether there is data in the ring_buffer.
++ *
++ * Tests whether there is currently data in the ring_buffer without blocking.
++ *
++ * @param   buffer  Pointer to the ring-buffer to be tested.
++ *
++ * @returns Whether there is data in the ring_buffer.
++ * @retval  0       There isn't any data in the ring_buffer.
++ * @retval  1       There is data in the ring_buffer.
++******************************************************************************/
++int ring_buffer_is_empty(ring_buffer * buffer);
++
++#endif
+diff --git a/src/plugins/ves/ves.api b/src/plugins/ves/ves.api
+new file mode 100644
+index 00000000..a7106f8d
+--- /dev/null
++++ b/src/plugins/ves/ves.api
+@@ -0,0 +1,72 @@
++/*
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/** \brief VES Agent config add / del request
++    @param client_index - opaque cookie to identify the sender
++    @param context - sender context, to match reply w/ request
++    @param server_port - VES Server port
++    @param read_interval - Time period for each loop
++    @param is_add - add the config if non-zero, else delete
++    @param server_addr[] - server address
++*/
++define ves_agent_config
++{
++  u32 client_index;
++  u32 context;
++  u32 server_port;
++  u32 read_interval;
++  u32 is_add;
++  u8 server_addr[16];
++};
++
++/** \brief VES Agent config response
++    @param context - sender context, to match reply w/ request
++    @param retval - return code for the request
++*/
++define ves_agent_config_reply
++{
++  u32 context;
++  i32 retval;
++};
++
++/** \brief VES Agent mode set request
++    @param client_index - opaque cookie to identify the sender
++    @param context - sender context, to match reply w/ request
++    @param pkt_loss_rate - Base packet loss rate if Demo Mode
++    @param work_mode[] - Agent's work mode, real or demo
++*/
++define ves_agent_mode
++{
++  u32 client_index;
++  u32 context;
++  u32 pkt_loss_rate;
++  u8  work_mode[8];
++};
++
++/** \brief VES Agent Mode response
++    @param context - sender context, to match reply w/ request
++    @param retval - return code for the request
++*/
++define ves_agent_mode_reply
++{
++  u32 context;
++  i32 retval;
++};
++
++/*
++ * Local Variables:
++ * eval: (c-set-style "gnu")
++ * End:
++ */
+diff --git a/src/plugins/ves/ves_all_api_h.h b/src/plugins/ves/ves_all_api_h.h
+new file mode 100644
+index 00000000..72b15697
+--- /dev/null
++++ b/src/plugins/ves/ves_all_api_h.h
+@@ -0,0 +1,18 @@
++/*
++ * ves_all_api_h.h - skeleton vpp engine plug-in api #include file
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <ves/ves.api.h>
+diff --git a/src/plugins/ves/ves_api.c b/src/plugins/ves/ves_api.c
+new file mode 100644
+index 00000000..7a9b8004
+--- /dev/null
++++ b/src/plugins/ves/ves_api.c
+@@ -0,0 +1,139 @@
++/*
++ *------------------------------------------------------------------
++ * ves_api.c - ves api
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ *------------------------------------------------------------------
++ */
++
++#include <vnet/vnet.h>
++#include <vlibmemory/api.h>
++
++#include <vnet/interface.h>
++#include <vnet/api_errno.h>
++#include <vnet/ip/ip.h>
++#include <vnet/ip/ip4.h>
++
++#include <ves/ves_node.h>
++
++#include <ves/ves_msg_enum.h> /* define message IDs */
++
++#define vl_typedefs           /* define message structures */
++#include <ves/ves_all_api_h.h>
++#undef vl_typedefs
++
++#define vl_endianfun          /* define message structures */
++#include <ves/ves_all_api_h.h>
++#undef vl_endianfun
++
++/* instantiate all the print functions we know about */
++#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
++
++#define vl_printfun
++#include <ves/ves_all_api_h.h>
++#undef vl_printfun
++
++
++#include <vlibapi/api_helper_macros.h>
++
++#define foreach_vpe_api_msg                       \
++_(VES_AGENT_CONFIG,ves_agent_config)            \
++_(VES_AGENT_MODE,ves_agent_mode)
++
++static void vl_api_ves_agent_config_t_handler
++  (vl_api_ves_agent_config_t *mp)
++{
++  vl_api_ves_agent_config_reply_t *rmp;
++  ip46_address_t server;
++  int rv = -1;
++
++  ip46_address_reset (&server);
++  clib_memcpy (&server.ip4, mp->server_addr, sizeof (server.ip4));
++
++  rv = ves_set_server(&server,
++                    (u32) ntohl (mp->server_port),
++                    (u32) ntohl (mp->read_interval),
++                    (int) (mp->is_add == 0));
++
++  REPLY_MACRO (VL_API_VES_AGENT_CONFIG_REPLY);
++}
++
++static void vl_api_ves_agent_mode_t_handler
++  (vl_api_ves_agent_mode_t *mp)
++{
++  vl_api_ves_agent_mode_reply_t *rmp;
++  ves_agent_mode_t mode = VES_AGENT_MODE_REAL;
++  int rv = -1;
++
++  if (!strcmp((char *)mp->work_mode, "demo")
++      || !strcmp((char *)mp->work_mode, "Demo")
++      || !strcmp((char *)mp->work_mode, "DEMO"))
++    mode = VES_AGENT_MODE_DEMO;
++
++  rv = ves_agent_set_mode(mode, (u32) ntohl(mp->pkt_loss_rate));
++
++  REPLY_MACRO (VL_API_VES_AGENT_MODE_REPLY);
++}
++
++/*
++ * ves_api_hookup
++ * Add vpe's API message handlers to the table.
++ * vlib has alread mapped shared memory and
++ * added the client registration handlers.
++ * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
++ */
++#define vl_msg_name_crc_list
++#include <ves/ves_all_api_h.h>
++#undef vl_msg_name_crc_list
++
++static void
++setup_message_id_table (api_main_t * am)
++{
++#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
++  foreach_vl_msg_name_crc_ves;
++#undef _
++}
++
++static clib_error_t *
++ves_api_hookup (vlib_main_t * vm)
++{
++  api_main_t *am = &api_main;
++
++#define _(N,n)                                                  \
++    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
++                           vl_api_##n##_t_handler,              \
++                           vl_noop_handler,                     \
++                           vl_api_##n##_t_endian,               \
++                           vl_api_##n##_t_print,                \
++                           sizeof(vl_api_##n##_t), 1);
++  foreach_vpe_api_msg;
++#undef _
++
++  /*
++   * Set up the (msg_name, crc, message-id) table
++   */
++  setup_message_id_table (am);
++
++  return 0;
++}
++
++VLIB_API_INIT_FUNCTION (ves_api_hookup);
++
++/*
++ * fd.io coding-style-patch-verification: ON
++ *
++ * Local Variables:
++ * eval: (c-set-style "gnu")
++ * End:
++ */
+diff --git a/src/plugins/ves/ves_msg_enum.h b/src/plugins/ves/ves_msg_enum.h
+new file mode 100644
+index 00000000..6e8a5dfa
+--- /dev/null
++++ b/src/plugins/ves/ves_msg_enum.h
+@@ -0,0 +1,31 @@
++/*
++ * ves_msg_enum.h - vpp engine plug-in message enumeration
++ *
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef _VES_MSG_ENUM_H_
++#define _VES_MSG_ENUM_H_
++
++#include <vppinfra/byte_order.h>
++
++#define vl_msg_id(n,h) n,
++typedef enum
++{
++#include <ves/ves_all_api_h.h>
++  /* We'll want to know how many messages IDs we need... */
++  VL_MSG_FIRST_AVAILABLE,
++} vl_msg_id_t;
++#undef vl_msg_id
++
++#endif /* _VES_MSG_ENUM_H_ */
+diff --git a/src/plugins/ves/ves_node.c b/src/plugins/ves/ves_node.c
+new file mode 100644
+index 00000000..7540dd16
+--- /dev/null
++++ b/src/plugins/ves/ves_node.c
+@@ -0,0 +1,646 @@
++/*
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <sys/time.h>
++
++#include <vnet/plugin/plugin.h>
++#include <vpp/app/version.h>
++
++#include "ves_node.h"
++
++#define BUFSIZE 128
++
++typedef struct dummy_vpp_metrics_struct {
++  int bytes_in;
++  int bytes_out;
++  int packets_in;
++  int packets_out;
++} vpp_metrics_struct;
++
++static vlib_node_registration_t ves_agent_process_node;
++vpp_metrics_struct *last_vpp_metrics;
++vpp_metrics_struct *curr_vpp_metrics;
++time_t start_epoch;
++time_t last_epoch;
++char hostname[BUFSIZE];
++
++static u8 *format_ves_agent_config(u8 *s, va_list *args);
++
++void read_vpp_metrics(vpp_metrics_struct *vpp_metrics, char *vnic) {
++  // Define an array of char that contains the parameters of the unix 'cut' command
++  char* params[] = {"-f3", "-f11", "-f4", "-f12"};
++  // Define the unix command to execute in order to read metrics from the vNIC
++  char* cmd_prefix = "sudo cat /proc/net/dev | grep \"";
++  char* cmd_mid = "\" | tr -s \' \' | cut -d\' \' ";
++  char cmd[BUFSIZE];
++  // Define other variables
++  char buf[BUFSIZE];          /* buffer used to store VPP metrics     */
++  int temp[] = {0, 0, 0, 0};  /* temp array that contains VPP values  */
++  FILE *fp;                   /* file descriptor to pipe cmd to shell */
++  int i;
++
++  for(i = 0; i < 4; i++) {
++    // Clear buffers
++    memset(buf, 0, BUFSIZE);
++    memset(cmd, 0, BUFSIZE);
++    // Build shell command to read metrics from the vNIC
++    strcat(cmd, cmd_prefix);
++    strcat(cmd, vnic);
++    strcat(cmd, cmd_mid);
++    strcat(cmd, params[i]);
++    
++    // Open a pipe and read VPP values
++    if ((fp = popen(cmd, "r")) == NULL) {
++        printf("Error opening pipe!\n");
++        return;
++    }
++
++    while (fgets(buf, BUFSIZE, fp) != NULL);
++    temp[i] = atoi(buf);
++
++    if(pclose(fp))  {
++        printf("Command not found or exited with error status\n");
++        return;
++    }
++  }
++
++  // Store metrics read from the vNIC in the struct passed from the main function
++  vpp_metrics->bytes_in = temp[0];
++  vpp_metrics->bytes_out = temp[1];
++  vpp_metrics->packets_in = temp[2];
++  vpp_metrics->packets_out = temp[3];
++}
++
++/**************************************************************************//**
++ * tap live cpu stats
++ *****************************************************************************/
++void evel_get_cpu_stats(EVENT_MEASUREMENT * measurement)
++{
++  FILE *fp;
++  char path[1024];
++  double usage=0.0;
++  double idle;
++  double intrpt;
++  double nice;
++  double softirq;
++  double steal;
++  double sys;
++  double user;
++  double wait;
++  MEASUREMENT_CPU_USE *cpu_use = NULL;
++
++  /* Open the command for reading. */
++  //fp = popen("/bin/ls /etc/", "r");
++  fp = popen("/usr/bin/top -bn 2 -d 0.01 | grep '^%Cpu' | tail -n 1 ", "r");
++  if (fp == NULL) {
++    printf("Failed to run command\n" );
++    exit(1);
++  }
++
++  /* Read the output a line at a time - output it. */
++  while (fgets(path, sizeof(path)-1, fp) != NULL) {
++    printf("%s", path+10);
++    sscanf(path+10," %lf us, %lf sy,  %lf ni,  %lf id,  %lf wa,  %lf hi,  %lf si,  %lf st",
++    &user,&sys,&nice,&idle,&wait,&intrpt,&softirq,&steal);
++  }
++
++  /* close */
++  pclose(fp);
++
++  cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu1", usage);
++  if( cpu_use != NULL ){
++  evel_measurement_cpu_use_idle_set(cpu_use,idle);
++  //evel_measurement_cpu_use_interrupt_set(cpu_use,intrpt);
++  //evel_measurement_cpu_use_nice_set(cpu_use,nice);
++  //evel_measurement_cpu_use_softirq_set(cpu_use,softirq);
++  //evel_measurement_cpu_use_steal_set(cpu_use,steal);
++  evel_measurement_cpu_use_system_set(cpu_use,sys);
++  evel_measurement_cpu_use_usageuser_set(cpu_use,user);
++  //evel_measurement_cpu_use_wait_set(cpu_use,wait);
++  //evel_measurement_cpu_use_add(measurement, "cpu2", usage,idle,intrpt,nice,softirq,steal,sys,user,wait);
++  }
++}
++
++int
++ves_agent_report_vnic_stats(ves_agent_main_t *vam)
++{
++      EVEL_ERR_CODES evel_rc = EVEL_SUCCESS;
++      EVENT_MEASUREMENT* vpp_m = NULL;
++      EVENT_HEADER* vpp_m_header = NULL;
++      int bytes_in_this_round;
++      int bytes_out_this_round;
++      int packets_in_this_round;
++      int packets_out_this_round;
++      struct timeval time_val;
++
++      /* Is not enabled, do nothing */
++      if (vam->config.is_enabled == VES_AGENT_DISABLED) {
++              return 0;
++      }
++
++      memset(curr_vpp_metrics, 0, sizeof(vpp_metrics_struct));
++      read_vpp_metrics(curr_vpp_metrics, DEFAULT_MEASURE_ETH);
++
++      if(curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in > 0) {
++              bytes_in_this_round = curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in;
++      } else {
++              bytes_in_this_round = 0;
++      }
++
++      if(curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out > 0) {
++              bytes_out_this_round = curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out;
++      } else {
++              bytes_out_this_round = 0;
++      }
++
++      if(curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in > 0) {
++              packets_in_this_round = curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in;
++      } else {
++              packets_in_this_round = 0;
++      }
++
++      if(curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out > 0) {
++              packets_out_this_round = curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out;
++      } else {
++              packets_out_this_round = 0;
++      }
++
++      vpp_m = evel_new_measurement(vam->config.read_interval, "Measurement_vGMUX", "Generic_traffic");
++      if(vpp_m != NULL) {
++          char str_pkt_loss[12];
++          MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = NULL;
++
++        printf("New measurement report created...\n");
++
++          vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance(
++                               DEFAULT_MEASURE_ETH, "true");
++          evel_meas_vnic_performance_add(vpp_m, vnic_performance);
++          evel_measurement_type_set(vpp_m, "HTTP request rate");
++          evel_measurement_request_rate_set(vpp_m, rand()%10000);
++
++          evel_vnic_performance_rx_total_pkt_delta_set(vnic_performance, packets_in_this_round);
++          evel_vnic_performance_tx_total_pkt_delta_set(vnic_performance, packets_out_this_round);
++
++          evel_vnic_performance_rx_octets_delta_set(vnic_performance, bytes_in_this_round);
++          evel_vnic_performance_tx_octets_delta_set(vnic_performance, bytes_out_this_round);
++          evel_get_cpu_stats(vpp_m);
++
++#if 0
++        evel_measurement_vnic_use_add(vpp_m,          /* Pointer to the measurement      */ 
++                        DEFAULT_MEASURE_ETH,          /* ASCII string with the vNIC's ID */
++                      packets_in_this_round,          /* Packets received                */
++                     packets_out_this_round,          /* Packets transmitted             */
++                                          0,          /* Broadcast packets received      */
++                                          0,          /* Broadcast packets transmitted   */
++                        bytes_in_this_round,          /* Total bytes received            */
++                       bytes_out_this_round,          /* Total bytes transmitted         */
++                                          0,          /* Multicast packets received      */
++                                          0,          /* Multicast packets transmitted   */
++                                          0,          /* Unicast packets received        */
++                                          0);         /* Unicast packets transmitted     */
++#endif
++
++       sprintf(str_pkt_loss, "%.1f %%", (double) vam->config.base_pkt_loss);
++         evel_measurement_custom_measurement_add(vpp_m,          /* Pointer to the measurement      */
++                                           "ONAP-DCAE",          /* measurement group's name        */
++                                    "Packet-Loss-Rate",          /* the measurement's name          */
++                                          str_pkt_loss);         /* The measurement's value         */
++
++      last_epoch = start_epoch + vam->config.read_interval * 1000000;
++      vpp_m_header = (EVENT_HEADER *)vpp_m;
++      vpp_m_header->start_epoch_microsec = start_epoch;
++      vpp_m_header->last_epoch_microsec = last_epoch;
++      strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available");
++      strcpy(vpp_m_header->reporting_entity_name, hostname);
++
++      evel_rc = evel_post_event(vpp_m_header);
++      if(evel_rc == EVEL_SUCCESS) {
++        printf("Measurement report correctly sent to the collector!\n");
++      }
++      else {
++        printf("Post failed %d (%s)\n", evel_rc, evel_error_string());
++      }
++    }
++    else {
++      printf("New measurement report failed (%s)\n", evel_error_string());
++    }
++
++      last_vpp_metrics->bytes_in = curr_vpp_metrics->bytes_in;
++      last_vpp_metrics->bytes_out = curr_vpp_metrics->bytes_out;
++      last_vpp_metrics->packets_in = curr_vpp_metrics->packets_in;
++      last_vpp_metrics->packets_out = curr_vpp_metrics->packets_out;
++      gettimeofday(&time_val, NULL);
++      start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
++
++      return 0;
++}
++
++always_inline int
++ves_agent_start(ves_agent_main_t *vam)
++{
++      vlib_main_t *vm = vam->vlib_main;
++      struct timeval time_val;
++      char fqdn[16]; /* "xxx.xxx.xxx.xxx" */
++      //char *fqdn = "127.0.0.1"; /* "xxx.xxx.xxx.xxx" */
++
++        sprintf(fqdn, "%d.%d.%d.%d", vam->config.server_addr.data[0],
++              vam->config.server_addr.data[1],
++              vam->config.server_addr.data[2],
++              vam->config.server_addr.data[3]);
++      /* Always success. TODO: Error check in next version */
++      last_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
++      curr_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
++
++      if(evel_initialize(fqdn,                         /* FQDN                  */
++      vam->config.server_port,                         /* Port                  */
++                         NULL,                         /* optional path         */
++                         NULL,                         /* optional topic        */
++                         0,                            /* HTTPS?                */
++                         "",                           /* Username              */
++                         "",                           /* Password              */
++                         EVEL_SOURCE_VIRTUAL_MACHINE,  /* Source type           */
++                         "vG-MUX",                     /* Role                  */
++                         1))                           /* Verbosity             */
++      {
++              fprintf(stderr, "\nFailed to initialize the EVEL library!!!\n");
++              return -1;
++      }
++
++      gethostname(hostname, BUFSIZE);
++      memset(last_vpp_metrics, 0, sizeof(vpp_metrics_struct));
++      read_vpp_metrics(last_vpp_metrics, DEFAULT_MEASURE_ETH);
++      gettimeofday(&time_val, NULL);
++      start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
++
++      vlib_process_wait_for_event_or_clock(vm, (f64)(vam->config.read_interval));
++
++      return 0;
++}
++
++always_inline int
++ves_agent_stop(void)
++{
++      sleep(1);
++      free(last_vpp_metrics);
++      free(curr_vpp_metrics);
++      evel_terminate();
++
++      return 0;
++}
++
++/* *INDENT-OFF* */
++VLIB_PLUGIN_REGISTER () = {
++      .version = VPP_BUILD_VER,
++      .description = "VNF Event Stream Agent",
++};
++/* *INDENT-ON* */
++
++static uword
++ves_agent_process (vlib_main_t * vm,
++                   vlib_node_runtime_t * rt,
++                   vlib_frame_t * f)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++      uword event_type;
++      uword * event_data = 0;
++
++      if (vam->config.read_interval == 0) {
++              vam->config.read_interval = DEFAULT_READ_INTERVAL;
++      }
++
++      while (1)
++      {
++              vlib_process_wait_for_event_or_clock(vm, (f64)(vam->config.read_interval));
++
++              event_type = vlib_process_get_events (vm, &event_data);
++
++              switch (event_type)
++              {
++              case EVENT_VES_AGENT_START:
++                      ves_agent_start(vam);
++                      break;
++              case EVENT_VES_AGENT_STOP:
++                      ves_agent_stop();
++                      break;
++              default:
++                      ves_agent_report_vnic_stats(vam);
++                      break;
++              }
++
++              vec_reset_length (event_data);
++      }
++
++      /* NOTREACHED */
++      return 0;
++}
++
++VLIB_REGISTER_NODE (ves_agent_process_node, static) = {
++      .function = ves_agent_process,
++      .type = VLIB_NODE_TYPE_PROCESS,
++      .name = "ves-agent-process",
++      .process_log2_n_stack_bytes = 16,
++};
++
++int
++ves_set_server (ip46_address_t *addr,
++                u32 server_port,
++                u32 read_interval, 
++                int is_del)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++      vlib_main_t *vm = vam->vlib_main;
++      int rc = 0;
++
++      if (ip46_address_is_zero(addr))
++              return VNET_API_ERROR_INVALID_DST_ADDRESS;
++  
++      if (is_del)
++      {
++              if (vam->config.is_enabled == VES_AGENT_DISABLED) {
++                      return rc;
++              }
++
++              if ((vam->config.server_addr.as_u32 != addr->ip4.as_u32)
++                  || (vam->config.server_port != server_port))
++                      return VNET_API_ERROR_NO_SUCH_ENTRY;
++
++              memset(&(vam->config.server_addr), 0, sizeof(ip4_address_t));
++              vam->config.server_port = DEFAULT_SERVER_PORT;
++              vam->config.read_interval = DEFAULT_READ_INTERVAL;
++              vam->config.is_enabled = VES_AGENT_DISABLED;
++              vlib_process_signal_event (vm, ves_agent_process_node.index,
++                                         EVENT_VES_AGENT_STOP, 0);
++      } else {
++              // Already enabled the same config.
++              if ((vam->config.server_addr.as_u32 == addr->ip4.as_u32)
++                  && (vam->config.server_port != server_port)
++                  && vam->config.read_interval == read_interval
++                  && vam->config.is_enabled == VES_AGENT_ENABLED) {
++                      return rc;
++              }
++
++              // Already enabled, but not exact match.
++              if (vam->config.is_enabled == VES_AGENT_ENABLED) {
++                      return VNET_API_ERROR_VALUE_EXIST;
++              }
++
++              vam->config.server_addr.as_u32 = addr->ip4.as_u32;
++              vam->config.server_port = server_port;
++              if (read_interval) {
++                      vam->config.read_interval = read_interval;
++              } else {
++                      vam->config.read_interval = DEFAULT_READ_INTERVAL;
++              }
++              vam->config.is_enabled = VES_AGENT_ENABLED;
++              vlib_process_signal_event (vm, ves_agent_process_node.index,
++                                         EVENT_VES_AGENT_START, 0);
++      }
++
++      return (rc);
++}
++
++static u8 *
++format_ves_agent_set_error(u8 *s, va_list *args)
++{
++      s = format(s, "%s\n\n", "Caution, set fails due to enabled config:");
++      s = format(s, "%U", format_ves_agent_config, NULL);
++      return s;
++}
++
++static clib_error_t *
++ves_server_set_command_fn(vlib_main_t * vm,
++                          unformat_input_t * input,
++                          vlib_cli_command_t * cmd)
++{
++      ip46_address_t server_addr;
++      u32 server_port = DEFAULT_SERVER_PORT, inter_val = DEFAULT_READ_INTERVAL;
++      int is_del = 0, set_server = 0;
++
++      memset(&server_addr, 0, sizeof(server_addr));
++
++      while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
++      {
++              if (unformat (input, "server %U", 
++                  unformat_ip4_address, &server_addr.ip4))
++                      set_server = 1;
++              else if (unformat (input, "port %u", &server_port))
++                      ;
++              else if (unformat (input, "intval %u", &inter_val))
++                      ;
++                      else if (unformat (input, "delete") ||
++                  unformat (input, "del"))
++                      is_del = 1;
++              else
++                      break;
++      }
++
++      if (is_del || set_server)
++      {
++              int rv;
++
++              rv = ves_set_server (&server_addr, server_port, inter_val, is_del);
++              switch (rv)
++              {
++                      case 0:
++                              return 0;
++
++                      case VNET_API_ERROR_INVALID_DST_ADDRESS:
++                              return clib_error_return (0, "Invalid address");
++          
++                      case VNET_API_ERROR_NO_SUCH_ENTRY:
++                              return clib_error_return(0, "No such Entry found");
++
++                      case VNET_API_ERROR_VALUE_EXIST:
++                              vlib_cli_output (vm, "%U\n", format_ves_agent_set_error, NULL);
++                              return clib_error_return (0, "BUG found!");
++
++                      default:
++                              return clib_error_return (0, "BUG: rv %d", rv);
++              }
++      } else {
++              return clib_error_return (0, "parse error`%U'",
++                          format_unformat_error, input);
++      }
++}
++
++VLIB_CLI_COMMAND (ves_server_set_command, static) = {
++      .path = "set ves agent",
++      .short_help = "set ves agent [del] server <ipaddr> port <port> [intval <inter-value>]",
++      .function = ves_server_set_command_fn,
++};
++
++static u8 *
++format_ves_agent_config(u8 *s, va_list *args)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++      char fqdn[16]; /* "xxx.xxx.xxx.xxx" */
++
++      s = format(s, "%=16s %=12s %=8s %s\n", "Server Addr",
++                 "Server Port", "Interval", "Enabled");
++      if (vam->config.is_enabled == VES_AGENT_DISABLED) {
++              return s;
++      }
++
++        sprintf(fqdn, "%d.%d.%d.%d", vam->config.server_addr.data[0],
++              vam->config.server_addr.data[1],
++              vam->config.server_addr.data[2],
++              vam->config.server_addr.data[3]);
++
++      s = format(s, "%=16s %=12d  %=8d %s\n", fqdn,
++              vam->config.server_port,
++              vam->config.read_interval,
++              vam->config.is_enabled ? "True" : "False");
++
++      return s;
++}
++
++static clib_error_t *
++ves_server_show_command_fn(vlib_main_t * vm,
++                           unformat_input_t * input,
++                           vlib_cli_command_t * cmd)
++{
++      vlib_cli_output (vm, "%U", format_ves_agent_config, NULL);
++
++      return (NULL);
++}
++
++VLIB_CLI_COMMAND (ves_server_show_command, static) = {
++      .path = "show ves agent",
++      .short_help = "Display VES Agent Configuration",
++      .function = ves_server_show_command_fn,
++};
++
++int
++ves_agent_set_mode(ves_agent_mode_t mode,
++                   u32 pkt_loss_rate)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++      int retval = 0;
++
++      if (VES_AGENT_MODE_DEMO == mode) {
++              if (pkt_loss_rate > 100) {
++                      vam->config.mode = VES_AGENT_MODE_REAL;
++                      vam->config.base_pkt_loss = 0;
++                      return 1;
++              }
++              vam->config.mode = VES_AGENT_MODE_DEMO;
++              vam->config.base_pkt_loss = pkt_loss_rate;
++      } else { /* Only demo or real for current stage */
++              vam->config.mode = VES_AGENT_MODE_REAL;
++              vam->config.base_pkt_loss = 0;
++      }
++
++      return retval;
++}
++
++static clib_error_t *
++ves_mode_set_command_fn(vlib_main_t * vm,
++                        unformat_input_t * input,
++                        vlib_cli_command_t * cmd)
++{
++      u32 pkt_loss_rate = 0;
++      ves_agent_mode_t mode = VES_AGENT_MODE_REAL;
++        int set_mode = 0;
++
++      while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
++      {
++                      if (unformat (input, "demo") || unformat (input, "Demo") 
++                  || unformat (input, "DEMO"))
++                {
++                      mode = VES_AGENT_MODE_DEMO;
++                      set_mode = 1;
++                }
++                      else if (unformat (input, "real") || unformat (input, "Real") 
++                  || unformat (input, "REAL"))
++                      set_mode = 1;
++              else if (unformat (input, "base %u", &pkt_loss_rate))
++                      ;
++              else
++                      break;
++      }
++
++      if (set_mode)
++      {
++              int retval = ves_agent_set_mode(mode, pkt_loss_rate);
++              if (retval == 0)
++                      return 0;
++              else
++                      return clib_error_return (0, "BUG found!");
++      } else {
++              return clib_error_return (0, "parse error`%U'",
++                          format_unformat_error, input);
++      }
++}
++
++VLIB_CLI_COMMAND (ves_mode_set_command, static) = {
++      .path = "set ves mode",
++      .short_help = "set ves mode <demo|real> [base <pkt-loss-rate>]",
++      .function = ves_mode_set_command_fn,
++};
++
++static inline u8 *
++format_ves_agent_mode(u8 *s, va_list *args)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++
++      s = format(s, "%=8s %s\n", "Mode", "Base Packet Loss Rate");
++
++      s = format(s, "%=8s         %.1f %%\n",
++              vam->config.mode ==  VES_AGENT_MODE_DEMO ? "Demo" : "Real",
++              (double) vam->config.base_pkt_loss);
++
++      return s;
++}
++
++static clib_error_t *
++ves_agent_mode_show_command_fn(vlib_main_t * vm,
++                               unformat_input_t * input,
++                               vlib_cli_command_t * cmd)
++{
++      vlib_cli_output (vm, "%U", format_ves_agent_mode, NULL);
++
++      return (NULL);
++}
++
++VLIB_CLI_COMMAND (ves_agent_mode_show_command, static) = {
++      .path = "show ves mode",
++      .short_help = "Display VES Agent Mode Information",
++      .function = ves_agent_mode_show_command_fn,
++};
++
++static clib_error_t *
++ves_agent_init(vlib_main_t * vm)
++{
++      ves_agent_main_t *vam = &ves_agent_main;
++
++      vam->vlib_main = vm;
++      vam->vnet_main = vnet_get_main();
++
++      return 0;
++}
++
++VLIB_INIT_FUNCTION (ves_agent_init);
++
++/*
++ * fd.io coding-style-patch-verification: ON
++ *
++ * Local Variables:
++ * eval: (c-set-style "gnu")
++ * End:
++ */
+diff --git a/src/plugins/ves/ves_node.h b/src/plugins/ves/ves_node.h
+new file mode 100644
+index 00000000..7b773843
+--- /dev/null
++++ b/src/plugins/ves/ves_node.h
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (c) 2017 Intel and/or its affiliates.
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef _VES_NODE_H_
++#define _VES_NODE_H_
++
++#include <vnet/ip/ip.h>
++
++#include "include/evel.h"
++
++#define DEFAULT_SERVER_IP     "127.0.0.1"
++#define DEFAULT_MEASURE_ETH   "eth0"
++#define DEFAULT_SERVER_PORT   8080
++#define DEFAULT_READ_INTERVAL 100
++
++typedef enum {
++      VES_AGENT_MODE_REAL = 0,
++      VES_AGENT_MODE_DEMO,
++      _NUM_VES_AGENT_MODES
++} ves_agent_mode_t;
++
++/* VES Agent Server configuration */
++typedef struct {
++      ip4_address_t           server_addr;
++      u32                     server_port;
++      u32                     read_interval;
++      int                     is_enabled;
++      u32                     base_pkt_loss; /* For demo only */
++      ves_agent_mode_t        mode; /* Demo or Real */
++} ves_agent_config_t;
++
++typedef struct {
++      ves_agent_config_t config;
++
++      /* convenience */
++      vlib_main_t * vlib_main;
++      vnet_main_t * vnet_main;
++} ves_agent_main_t;
++
++ves_agent_main_t ves_agent_main;
++
++#define EVENT_VES_AGENT_START         1
++#define EVENT_VES_AGENT_STOP  0
++
++#define VES_AGENT_DISABLED    0
++#define VES_AGENT_ENABLED     1
++
++int ves_set_server(ip46_address_t *addr, u32 server_port,
++                 u32 read_interval, int is_del);
++
++int ves_agent_set_mode(ves_agent_mode_t mode,
++                       u32 pkt_loss_rate);
++
++#endif /* _VES_NODE_H_ */
+diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am
+index f18e0c24..7f4738d8 100644
+--- a/src/vpp-api/java/Makefile.am
++++ b/src/vpp-api/java/Makefile.am
+@@ -148,6 +148,26 @@ jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_js
+       $(call japigen,snat,JVppSnatImpl)
+ endif
++#
++# VES Plugin
++#
++if ENABLE_VES_PLUGIN
++noinst_LTLIBRARIES += libjvpp_ves.la
++libjvpp_ves_la_SOURCES = jvpp-ves/jvpp_ves.c
++libjvpp_ves_la_CPPFLAGS = -Ijvpp-ves
++libjvpp_ves_la_LIBADD = $(JVPP_LIBS)
++libjvpp_ves_la_DEPENDENCIES = libjvpp_common.la
++
++BUILT_SOURCES += jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h
++JAR_FILES += jvpp-ves-$(PACKAGE_VERSION).jar
++CLEANDIRS += jvpp-ves/target
++
++jvpp_ves_json_files = @top_builddir@/plugins/ves/ves.api.json
++
++jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h: $(jvpp_registry_ok) $(jvpp_ves_json_files)
++      $(call japigen,ves,JVppVesImpl)
++endif
++
+ #
+ # iOAM Trace Plugin
+ #
+diff --git a/src/vpp-api/java/jvpp-ves/jvpp_ves.c b/src/vpp-api/java/jvpp-ves/jvpp_ves.c
+new file mode 100644
+index 00000000..60e325b5
+--- /dev/null
++++ b/src/vpp-api/java/jvpp-ves/jvpp_ves.c
+@@ -0,0 +1,108 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#include <vnet/vnet.h>
++
++#include <ves/ves_msg_enum.h>
++#define vl_typedefs             /* define message structures */
++#include <ves/ves_all_api_h.h>
++#undef vl_typedefs
++
++#include <vnet/api_errno.h>
++#include <vlibapi/api.h>
++#include <vlibmemory/api.h>
++
++#if VPPJNI_DEBUG == 1
++  #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
++#else
++  #define DEBUG_LOG(...)
++#endif
++
++#include <jvpp-common/jvpp_common.h>
++
++#include "jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h"
++#include "jvpp_ves.h"
++#include "jvpp-ves/jvpp_ves_gen.h"
++
++/*
++ * Class:     io_fd_vpp_jvpp_ves_JVppVesImpl
++ * Method:    init0
++ * Signature: (JI)V
++ */
++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ves_JVppVesImpl_init0
++  (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) {
++  ves_main_t * plugin_main = &ves_main;
++  clib_warning ("Java_io_fd_vpp_jvpp_ves_JVppVesImpl_init0");
++
++  plugin_main->my_client_index = my_client_index;
++  plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address;
++
++  plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
++  plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
++
++  // verify API has not changed since jar generation
++  #define _(N)             \
++      get_message_id(env, #N);
++      foreach_supported_api_message;
++  #undef _
++
++  #define _(N,n)                                  \
++      vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
++              vl_api_##n##_t_handler,             \
++              vl_noop_handler,                    \
++              vl_noop_handler,                    \
++              vl_noop_handler,                    \
++              sizeof(vl_api_##n##_t), 1);
++      foreach_api_reply_handler;
++  #undef _
++}
++
++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ves_JVppVesImpl_close0
++(JNIEnv *env, jclass clazz) {
++  ves_main_t * plugin_main = &ves_main;
++
++    // cleanup:
++    (*env)->DeleteGlobalRef(env, plugin_main->callbackClass);
++    (*env)->DeleteGlobalRef(env, plugin_main->callbackObject);
++
++    plugin_main->callbackClass = NULL;
++    plugin_main->callbackObject = NULL;
++}
++
++/* Attach thread to JVM and cache class references when initiating JVPP VES */
++jint JNI_OnLoad(JavaVM *vm, void *reserved) {
++    JNIEnv* env;
++
++    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
++        return JNI_EVERSION;
++    }
++
++    if (cache_class_references(env) != 0) {
++        clib_warning ("Failed to cache class references\n");
++        return JNI_ERR;
++    }
++
++    return JNI_VERSION_1_8;
++}
++
++/* Clean up cached references when disposing JVPP VES */
++void JNI_OnUnload(JavaVM *vm, void *reserved) {
++    JNIEnv* env;
++    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
++        return;
++    }
++    delete_class_references(env);
++}
+diff --git a/src/vpp-api/java/jvpp-ves/jvpp_ves.h b/src/vpp-api/java/jvpp-ves/jvpp_ves.h
+new file mode 100644
+index 00000000..642101ca
+--- /dev/null
++++ b/src/vpp-api/java/jvpp-ves/jvpp_ves.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (c) 2017 Intel Corp and/or its affiliates.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at:
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++#ifndef __included_jvpp_ves_h__
++#define __included_jvpp_ves_h__
++
++#include <vnet/vnet.h>
++#include <vnet/ip/ip.h>
++#include <vnet/api_errno.h>
++#include <vlibapi/api.h>
++#include <vlibmemory/api.h>
++#include <jni.h>
++
++/* Global state for JVPP-VES */
++typedef struct {
++    /* Pointer to shared memory queue */
++    unix_shared_memory_queue_t * vl_input_queue;
++
++    /* VPP api client index */
++    u32 my_client_index;
++
++    /* Callback object and class references enabling asynchronous Java calls */
++    jobject callbackObject;
++    jclass callbackClass;
++
++} ves_main_t;
++
++ves_main_t ves_main __attribute__((aligned (64)));
++
++
++#endif /* __included_jvpp_ves_h__ */
+-- 
+2.14.1.windows.1
+
index 0a2c8da..262a01b 100644 (file)
@@ -58,9 +58,10 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
+apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
 pip install jsonschema
 
 # Download artifacts for virtual firewall
@@ -73,11 +74,11 @@ wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_V
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves/$DEMO_ARTIFACTS_VERSION/ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves_vfw_reporting/$DEMO_ARTIFACTS_VERSION/ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 
-tar -zxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv ves-$DEMO_ARTIFACTS_VERSION VES
-tar -zxvf ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION VESreporting_vFW
-tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
+tar -zmxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
 mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb
 sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json
 mv VESreporting_vFW /opt/VES/code/evel_training/VESreporting
index 4ec1e4e..3f150fc 100644 (file)
@@ -48,9 +48,10 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
+apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
 pip install jsonschema
 
 # Download code for packet generator
@@ -63,8 +64,8 @@ wget $REPO_URL_BLOB/org.onap.demo/vnfs/vfw/$INSTALL_SCRIPT_VERSION/run_traffic_f
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_VERSION/sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vfw/vfw_pg_streams/$DEMO_ARTIFACTS_VERSION/vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz 
 
-tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
-tar -zxvf vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
+tar -zmxvf vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv vfw_pg_streams-$DEMO_ARTIFACTS_VERSION pg_streams
 mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb
 sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json
index 88c194d..f01a0ab 100644 (file)
@@ -46,9 +46,10 @@ then
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y make wget openjdk-8-jdk apt-transport-https ca-certificates darkstat
+apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk apt-transport-https ca-certificates darkstat
 
 # Configure and run Darkstat
 sed -i "s/START_DARKSTAT=.*/START_DARKSTAT=yes/g" /etc/darkstat/init.cfg
diff --git a/vnfs/vLB/.DS_Store b/vnfs/vLB/.DS_Store
deleted file mode 100644 (file)
index b7ccbfd..0000000
Binary files a/vnfs/vLB/.DS_Store and /dev/null differ
index ff9fdc5..3d2de9b 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x22c60100000100000000000005686f73743107646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x22c60100000100000000000005686f73743107646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 9f28e20..7c67ca3 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 54
-    hex 0x867b0100000100000000000006686f7374313007646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 49
+    hex 0x867b0100000100000000000006686f7374313007646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 0b3d6c6..2696d36 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x23550100000100000000000005686f73743207646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x23550100000100000000000005686f73743207646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 531ba8e..0a691d4 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x7b110100000100000000000005686f73743307646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x7b110100000100000000000005686f73743307646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 2bfd4cb..eb1ea3e 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x63910100000100000000000005686f73743407646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x63910100000100000000000005686f73743407646e7364656d6f046f6e6170036f72670000010001
   }
 }
index c853c57..eb4d5eb 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x054e0100000100000000000005686f73743507646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x054e0100000100000000000005686f73743507646e7364656d6f046f6e6170036f72670000010001
   }
 }
index dab5156..acfc683 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0xb9d80100000100000000000005686f73743607646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0xb9d80100000100000000000005686f73743607646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 1cca61e..f2d6b2d 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x36f30100000100000000000005686f73743707646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x36f30100000100000000000005686f73743707646e7364656d6f046f6e6170036f72670000010001
   }
 }
index ce76bca..0040eb6 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x09860100000100000000000005686f73743807646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x09860100000100000000000005686f73743807646e7364656d6f046f6e6170036f72670000010001
   }
 }
index 0cc3132..b7f6af4 100644 (file)
@@ -7,7 +7,7 @@ packet-generator new {
   data {
     UDP: 104.130.226.226 -> 104.130.169.190
     UDP: 15320 -> 53
-    length 53
-    hex 0x12610100000100000000000005686f73743907646e7364656d6f096f70656e65636f6d70036f72670000010001
+    length 48
+    hex 0x12610100000100000000000005686f73743907646e7364656d6f046f6e6170036f72670000010001
   }
 }
diff --git a/vnfs/vLB/scripts/.DS_Store b/vnfs/vLB/scripts/.DS_Store
deleted file mode 100644 (file)
index 32f7eca..0000000
Binary files a/vnfs/vLB/scripts/.DS_Store and /dev/null differ
index 04dfc77..3574e08 100644 (file)
@@ -7,15 +7,17 @@ then
 fi
 
 DNS_IPADDR=$1
-MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
-MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt)
+IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt)
+IP_TO_DNS_NET=$(cat /opt/config/ip_to_dns_net.txt)
+GRE_IPADDR=$(cat /opt/config/gre_ipaddr.txt)
 
-vppctl lb as $MY_PUBLIC_IP"/32" $DNS_IPADDR
-GRE=$(vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR)
+vppctl lb as $IP_TO_PKTGEN_NET"/32" $DNS_IPADDR
+GRE=$(vppctl create gre tunnel src $IP_TO_DNS_NET dst $DNS_IPADDR)
+vppctl set int ip address $GRE $GRE_IPADDR"/32"
 vppctl set int state $GRE up
 
 # Update the number of vDNSs currently active
 FD="/opt/VES/code/evel_training/VESreporting/active_dns.txt"
 CURR_DNS=$(cat $FD)
 let CURR_DNS=$CURR_DNS+1
-echo $CURR_DNS > $FD
+echo $CURR_DNS > $FD
\ No newline at end of file
index 345dc3f..e18ab80 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
+IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt)
 VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 
-java -jar dns-manager-$VERSION.jar $MY_PUBLIC_IP 8888 10 3 0
+java -jar dns-manager-$VERSION.jar $IP_TO_PKTGEN_NET 8888 10 3 0
index 1d505ab..f400aa0 100644 (file)
@@ -2,23 +2,23 @@
 
 if [ ! "$#" -eq 1 ]
 then
-  echo "Usage: ./add_dns.sh [remote DNS server]"
+  echo "Usage: ./remove_dns.sh [remote DNS server]"
   exit
 fi
 
 DNS_IPADDR=$1
-MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
-MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt)
+IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt)
+IP_TO_DNS_NET=$(cat /opt/config/ip_to_dns_net.txt)
 
-vppctl lb as $MY_PUBLIC_ID"/32" $DNS_IPADDR del
-vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR del
+vppctl lb as $IP_TO_PKTGEN_NET"/32" $DNS_IPADDR del
+vppctl create gre tunnel src $IP_TO_DNS_NET dst $DNS_IPADDR del
 
 # Update the number of vDNSs currently active
 FD="/opt/VES/code/evel_training/VESreporting/active_dns.txt"
 CURR_DNS=$(cat $FD)
 let CURR_DNS=$CURR_DNS-1
 if [[ $CURR_DNS -lt 0 ]]
-then 
+then
   CURR_DNS=0
 fi
-echo $CURR_DNS > $FD
+echo $CURR_DNS > $FD
\ No newline at end of file
index 4d4e543..cf95fa5 100755 (executable)
@@ -3,7 +3,7 @@
 vppctl packet-gen disable
 vppctl packet-gen enable-stream dns1
 vppctl packet-gen enable-stream dns2
-sleep 300
+sleep 100
 vppctl packet-gen enable-stream dns3
 vppctl packet-gen enable-stream dns4
 vppctl packet-gen enable-stream dns5
index 83441ac..91cce8a 100644 (file)
@@ -42,19 +42,16 @@ then
        echo "    address $IP" >> /etc/network/interfaces
        echo "    netmask $NETMASK" >> /etc/network/interfaces
        echo "    mtu $MTU" >> /etc/network/interfaces
-
-       ifup eth1
-       ifup eth2
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates
+apt-get install --allow-unauthenticated -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates
 sleep 1
 
 # Download vDNS demo code for DNS Server
-mkdir /opt/config
 mkdir /opt/FDclient
 cd /opt
 
@@ -92,4 +89,17 @@ sleep 1
 cd /opt
 mv vdns.sh /etc/init.d
 update-rc.d vdns.sh defaults
+
+# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
+if [[ $CLOUD_ENV != "rackspace" ]]
+then
+       sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub
+       grub-mkconfig -o /boot/grub/grub.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules
+       echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
+       echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic
+       reboot
+fi
+
 ./v_dns_init.sh
\ No newline at end of file
index 8767a94..9223e04 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # Start VPP
-start vpp
+systemctl start vpp
 sleep 1
 
 # Compute the network CIDR from the Netmask
@@ -25,30 +25,33 @@ mask2cidr() {
     echo "$nbits"
 }
 
-IPADDR1_MASK=$(ifconfig eth0 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}')
+IPADDR1_MASK=$(ifconfig eth3 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}')
 IPADDR1_CIDR=$(mask2cidr $IPADDR1_MASK)
 IPADDR2_MASK=$(ifconfig eth1 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}')
 IPADDR2_CIDR=$(mask2cidr $IPADDR2_MASK)
 
 # Configure VPP for vPacketGenerator
-IPADDR1=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+IPADDR1=$(ifconfig eth3 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
 IPADDR2=$(ifconfig eth1 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
-HWADDR1=$(ifconfig eth0 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+HWADDR1=$(ifconfig eth3 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
 HWADDR2=$(ifconfig eth1 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
-FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null |hexdump -v -e '/1 ":%02X"')
-FAKE_HWADDR2=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null |hexdump -v -e '/1 ":%02X"')
+FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
+FAKE_HWADDR2=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
 GW=$(route -n | grep "^0.0.0.0" | awk '{print $2}')
+PKTGEN_IPADDR=$(cat /opt/config/pktgen_ipaddr.txt)
+PKTGEN_MAC=$(cat /opt/config/pktgen_mac.txt)
+VIP=$(cat /opt/config/vip.txt)
 
-ifconfig eth0 down
-ifconfig eth0 hw ether $FAKE_HWADDR1
-ip addr flush dev eth0
-ifconfig eth0 up
+ifconfig eth3 down
+ifconfig eth3 hw ether $FAKE_HWADDR1
+ip addr flush dev eth3
+ifconfig eth3 up
 vppctl tap connect tappub hwaddr $HWADDR1
-vppctl set int ip address tap-0 $IPADDR1"/"$IPADDR1_CIDR
+vppctl set int ip address tap-0 $VIP"/"$IPADDR1_CIDR
 vppctl set int state tap-0 up
 brctl addbr br0
 brctl addif br0 tappub
-brctl addif br0 eth0
+brctl addif br0 eth3
 ifconfig br0 up
 
 ifconfig eth1 down
@@ -66,13 +69,16 @@ sleep 1
 
 vppctl lb conf ip4-src-address $IPADDR2
 vppctl lb vip $IPADDR1"/32" encap gre4
-vppctl ip route add 0.0.0.0/0 via $GW
 sleep 1
 
+vppctl set ip arp proxy $IPADDR1" - "$IPADDR1
+vppctl set interface proxy-arp tap-0 enable
+vppctl set ip arp tap-0 $PKTGEN_IPADDR $PKTGEN_MAC
+
 cd /opt/FDserver
 ./dnsmembership.sh &>/dev/null &disown
 
 # Start VES client
 cd /opt/VES/code/evel_training/VESreporting/
 echo 0 > active_dns.txt
-./go-client.sh &>/dev/null &disown
+./go-client.sh &>/dev/null &disown
\ No newline at end of file
index 394a6c8..a6577c4 100644 (file)
@@ -25,7 +25,7 @@ then
 
        MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
 
-       IP=$(cat /opt/config/local_private_ipaddr.txt)
+       IP=$(cat /opt/config/ip_to_dns_net.txt)
        BITS=$(cat /opt/config/vlb_private_net_cidr.txt | cut -d"/" -f2)
        NETMASK=$(cdr2mask $BITS)
        echo "auto eth1" >> /etc/network/interfaces
@@ -43,18 +43,24 @@ then
        echo "    netmask $NETMASK" >> /etc/network/interfaces
        echo "    mtu $MTU" >> /etc/network/interfaces
 
-       ifup eth1
-       ifup eth2
+       IP=$(cat /opt/config/ip_to_pktgen_net.txt)
+       BITS=$(cat /opt/config/pktgen_private_net_cidr.txt | cut -d"/" -f2)
+       NETMASK=$(cdr2mask $BITS)
+       echo "auto eth3" >> /etc/network/interfaces
+       echo "iface eth3 inet static" >> /etc/network/interfaces
+       echo "    address $IP" >> /etc/network/interfaces
+       echo "    netmask $NETMASK" >> /etc/network/interfaces
+       echo "    mtu $MTU" >> /etc/network/interfaces
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y make gcc wget openjdk-8-jdk bridge-utils libcurl4-openssl-dev apt-transport-https ca-certificates
+apt-get install --allow-unauthenticated -y make gcc wget openjdk-8-jdk bridge-utils libcurl4-openssl-dev apt-transport-https ca-certificates
 sleep 1
 
 # Download vLB demo code for load balancer
-mkdir /opt/config
 mkdir /opt/FDserver
 cd /opt
 
@@ -67,9 +73,9 @@ wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vlb/dns-manager/$DEMO_ARTIFACTS_VERSI
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves/$DEMO_ARTIFACTS_VERSION/ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves_vlb_reporting/$DEMO_ARTIFACTS_VERSION/ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 
-tar -zxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv ves-$DEMO_ARTIFACTS_VERSION VES
-tar -zxvf ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION VESreporting_vLB
 
 mv VESreporting_vLB /opt/VES/code/evel_training/VESreporting
@@ -86,16 +92,9 @@ chmod +x /opt/FDserver/dnsmembership.sh
 chmod +x /opt/FDserver/add_dns.sh
 chmod +x /opt/FDserver/remove_dns.sh
 
-# Create a file with public IP of the VM if it doesn't exist. This is for VMs directly attached to the external network.
-if [ ! -e /opt/config/local_public_ipaddr.txt ]
-then
-       IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
-       echo $IP_ADDRESS > /opt/config/local_public_ipaddr.txt
-fi
-
 # Install VPP
-export UBUNTU="trusty"
-export RELEASE=".stable.1609"
+export UBUNTU="xenial"
+export RELEASE=".stable.1707"
 rm /etc/apt/sources.list.d/99fd.io.list
 echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io$RELEASE.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list
 apt-get update
@@ -112,4 +111,17 @@ sleep 1
 cd /opt
 mv vlb.sh /etc/init.d
 update-rc.d vlb.sh defaults
+
+# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
+if [[ $CLOUD_ENV != "rackspace" ]]
+then
+       sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub
+       grub-mkconfig -o /boot/grub/grub.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules
+       echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
+       echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic
+       reboot
+fi
+
 ./v_lb_init.sh
\ No newline at end of file
similarity index 76%
rename from vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh
rename to vnfs/vLB/scripts/v_packetgen_init.sh
index 9e7879b..3e0de3e 100644 (file)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # Start VPP
-start vpp
+systemctl start vpp
 sleep 1
 
 # Compute the network CIDR from the Netmask
@@ -25,51 +25,37 @@ mask2cidr() {
     echo "$nbits"
 }
 
-IPADDR1_MASK=$(ifconfig eth0 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}')
+IPADDR1_MASK=$(ifconfig eth1 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}')
 IPADDR1_CIDR=$(mask2cidr $IPADDR1_MASK)
 
 # Configure VPP for vPacketGenerator
-IPADDR1=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
-HWADDR1=$(ifconfig eth0 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+IPADDR1=$(ifconfig eth1 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+HWADDR1=$(ifconfig eth1 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
 FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
 VLB_IPADDR=$(cat /opt/config/vlb_ipaddr.txt)
+VLB_MAC=$(cat /opt/config/vlb_mac.txt)
 GW=$(route -n | grep "^0.0.0.0" | awk '{print $2}')
 
-ifconfig eth0 down
-ifconfig eth0 hw ether $FAKE_HWADDR1
-ip addr flush dev eth0
-ifconfig eth0 up
+ifconfig eth1 down
+ifconfig eth1 hw ether $FAKE_HWADDR1
+ip addr flush dev eth1
+ifconfig eth1 up
 vppctl tap connect tap111 hwaddr $HWADDR1
 vppctl set int ip address tap-0 $IPADDR1"/"$IPADDR1_CIDR
 vppctl set int state tap-0 up
 brctl addbr br0
 brctl addif br0 tap111
-brctl addif br0 eth0
+brctl addif br0 eth1
 ifconfig br0 up
 vppctl ip route add 0.0.0.0/0 via $GW
 sleep 1
 
-
 # Set br0 with public IP and valid MAC so that Linux will have public network access
 ifconfig br0 hw ether $HWADDR1
 ifconfig br0 $IPADDR1 netmask $IPADDR1_MASK
 route add default gw $GW
-
-#Adding static arp entry for VPP so that it will be able to send packets to default GW
-ping -c 1 $VLB_IPADDR &>/dev/null &disown
-sleep 3
-
-GW_MAC=$(arp -n | grep -w $GW | tr -s ' ' | cut -d' ' -f3)
-VLB_MAC=$(arp -n | grep -w $VLB_IPADDR | tr -s ' ' | cut -d' ' -f3)
-
-# If VLB is in our network, we will use its MAC
-if [ ! -z "$VLB_MAC" ]
-then
-       vppctl set ip arp tap-0 $VLB_IPADDR $VLB_MAC
-fi
-
-# Add arp entry for default GW
-vppctl set ip arp tap-0 $GW $GW_MAC
+sleep 1
+vppctl set ip arp tap-0 $VLB_IPADDR $VLB_MAC
 
 # Install packet streams
 sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns1
@@ -104,17 +90,11 @@ vppctl exec /opt/dns_streams/stream_dns7
 vppctl exec /opt/dns_streams/stream_dns8
 vppctl exec /opt/dns_streams/stream_dns9
 vppctl exec /opt/dns_streams/stream_dns10
-sleep 1
 
-# Start HoneyComb
-VERSION=$(cat /opt/config/demo_artifacts_version.txt)
-echo "" > /var/lib/honeycomb/persist/context/data.json
-echo "" > /var/lib/honeycomb/persist/config/data.json
-/opt/honeycomb/sample-distribution-$VERSION/honeycomb &>/dev/null &disown
-sleep 20
+vppctl set int ip address pg0 $(cat /opt/config/pg_int.txt)"/"$IPADDR1_CIDR
+sleep 1
 
 # Enable traffic flows
 cd /opt
 chmod +x run_streams_dns.sh
-./run_streams_dns.sh &>/dev/null &disown
-
+./run_streams_dns.sh &>/dev/null &disown
\ No newline at end of file
index 2a2d7a2..ca2957a 100644 (file)
@@ -6,6 +6,14 @@ DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt)
 INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt)
 CLOUD_ENV=$(cat /opt/config/cloud_env.txt)
 
+# Convert Network CIDR to Netmask
+cdr2mask () {
+       # Number of args to shift, 255..255, first non-255 byte, zeroes
+       set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
+       [ $1 -gt 1 ] && shift $1 || shift
+       echo ${1-0}.${2-0}.${3-0}.${4-0}
+}
+
 # OpenStack network configuration
 if [[ $CLOUD_ENV == "openstack" ]]
 then
@@ -14,40 +22,54 @@ then
        # Allow remote login as root
        mv /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bk
        cp /home/ubuntu/.ssh/authorized_keys /root/.ssh
+
+       MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1)
+
+       IP=$(cat /opt/config/local_private_ipaddr.txt)
+       BITS=$(cat /opt/config/pktgen_private_net_cidr.txt | cut -d"/" -f2)
+       NETMASK=$(cdr2mask $BITS)
+       echo "auto eth1" >> /etc/network/interfaces
+       echo "iface eth1 inet static" >> /etc/network/interfaces
+       echo "    address $IP" >> /etc/network/interfaces
+       echo "    netmask $NETMASK" >> /etc/network/interfaces
+       echo "    mtu $MTU" >> /etc/network/interfaces
+
+       IP=$(cat /opt/config/oam_private_ipaddr.txt)
+       BITS=$(cat /opt/config/onap_private_net_cidr.txt | cut -d"/" -f2)
+       NETMASK=$(cdr2mask $BITS)
+       echo "auto eth2" >> /etc/network/interfaces
+       echo "iface eth2 inet static" >> /etc/network/interfaces
+       echo "    address $IP" >> /etc/network/interfaces
+       echo "    netmask $NETMASK" >> /etc/network/interfaces
+       echo "    mtu $MTU" >> /etc/network/interfaces
 fi
 
 # Download required dependencies
-add-apt-repository -y ppa:openjdk-r/ppa
+echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
+echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >>  /etc/apt/sources.list.d/java.list
 apt-get update
-apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
+apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates
 pip install jsonschema
 
 # Download vFirewall demo code for packet generator
-mkdir /opt/config
-mkdir /opt/honeycomb
 cd /opt
-wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/v_packetgen_for_dns_demo_init.sh
-wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vpacketgenfordnsdemo.sh
+wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/v_packetgen_init.sh
+wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vpacketgen.sh
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/run_streams_dns.sh
 wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vdnspacketgen_change_streams_ports.sh
-wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_VERSION/sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
 wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vlb/vlb_dns_streams/$DEMO_ARTIFACTS_VERSION/vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz 
 
-tar -zxvf vpp.tar.gz
-tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz
-mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb
-sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json
-tar -zxvf vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
+tar -zmxvf vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz
 mv vlb_dns_streams-$DEMO_ARTIFACTS_VERSION dns_streams
 rm *.tar.gz
-chmod +x v_packetgen_for_dns_demo_init.sh
-chmod +x vpacketgenfordnsdemo.sh
+chmod +x v_packetgen_init.sh
+chmod +x vpacketgen.sh
 chmod +x run_streams_dns.sh
 chmod +x vdnspacketgen_change_streams_ports.sh
 
 # Install VPP
-export UBUNTU="trusty"
-export RELEASE=".stable.1609"
+export UBUNTU="xenial"
+export RELEASE=".stable.1707"
 rm /etc/apt/sources.list.d/99fd.io.list
 echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io$RELEASE.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list
 apt-get update
@@ -56,6 +78,22 @@ sleep 1
 
 # Run instantiation script
 cd /opt
-mv vpacketgenfordnsdemo.sh /etc/init.d
-update-rc.d vpacketgenfordnsdemo.sh defaults
-./v_packetgen_for_dns_demo_init.sh
+mv vpacketgen.sh /etc/init.d
+update-rc.d vpacketgen.sh defaults
+
+# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
+if [[ $CLOUD_ENV != "rackspace" ]]
+then
+       sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub
+       grub-mkconfig -o /boot/grub/grub.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg
+       sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules
+       echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
+       echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic
+       reboot
+fi
+
+# Install a cron job that restart streams every minute. This allows to map streams to different vDNSs when we scale out the VNF
+echo "* * * * * /opt/vdnspacketgen_change_streams_ports.sh" | crontab
+
+./v_packetgen_init.sh
index 9bd7716..e472388 100644 (file)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
-#Disable all streams via Honeycomb (so that it will in consistent state)
-curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{"pg-streams":{"pg-stream": []}}' "http://localhost:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+#Disable all streams
+killall -9 run_streams_dns.sh
 
 vppctl pac del dns1
 vppctl pac del dns2
@@ -14,10 +14,9 @@ vppctl pac del dns8
 vppctl pac del dns9
 vppctl pac del dns10
 
-
 #Update destination (vLB) IP
 VLB_IPADDR=$(cat /opt/config/vlb_ipaddr.txt)
-IPADDR1=$(ifconfig br0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+IPADDR1=$(cat /opt/config/local_private_ipaddr.txt)
 sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns1
 sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns2
 sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns3
@@ -50,4 +49,8 @@ vppctl exec /opt/dns_streams/stream_dns6
 vppctl exec /opt/dns_streams/stream_dns7
 vppctl exec /opt/dns_streams/stream_dns8
 vppctl exec /opt/dns_streams/stream_dns9
-vppctl exec /opt/dns_streams/stream_dns10
\ No newline at end of file
+vppctl exec /opt/dns_streams/stream_dns10
+
+#Resume stream execution
+cd /opt
+./run_streams_dns.sh &>/dev/null &disown
\ No newline at end of file
similarity index 97%
rename from vnfs/vLB/scripts/vpacketgenfordnsdemo.sh
rename to vnfs/vLB/scripts/vpacketgen.sh
index 427e533..1d00fd9 100644 (file)
@@ -10,7 +10,7 @@
 ### END INIT INFO
 
 dir="/opt"
-cmd="./v_packetgen_for_dns_demo_init.sh"
+cmd="./v_packetgen_init.sh"
 user="root"
 
 name=`basename $0`