Merge "Naming custom additional fields and filesys fields"
authorMarco Platania <platania@research.att.com>
Fri, 22 Sep 2017 17:20:25 +0000 (17:20 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 22 Sep 2017 17:20:25 +0000 (17:20 +0000)
77 files changed:
boot/aai_install.sh
boot/appc_install.sh
boot/appc_vm_init.sh
boot/bind_zones
boot/clamp_install.sh
boot/clamp_vm_init.sh
boot/cli_install.sh [new file with mode: 0644]
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 82% 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/mso_install.sh with 81% similarity]
boot/so_serv.sh [moved from boot/asdc_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/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]
pom.xml
vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json
vnfs/vCPE/scripts/kea-dhcp4.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_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/scripts/v_dns_install.sh
vnfs/vLB/scripts/v_lb_install.sh
vnfs/vLB/scripts/v_packetgen_install.sh

index a09849e..9ee49d7 100644 (file)
@@ -49,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
index 7dfbd39..b241efe 100644 (file)
@@ -48,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
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 83b9f87..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
@@ -77,6 +77,8 @@ c2.vm1.clamp.simpledemo.openecomp.org.        IN      A       clamp_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
@@ -96,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
@@ -119,8 +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
 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.
index 03af230..26e8f06 100644 (file)
@@ -5,7 +5,6 @@ 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)
@@ -49,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/clamp_vm_init.sh -o /opt/clamp_vm_init.sh
index 997e556..f8b26e3 100644 (file)
@@ -3,10 +3,28 @@
 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)
-OPENSTACK_USERNAME=$(cat /opt/config/openstack_username.txt)
-OPENSTACK_APIKEY=$(cat /opt/config/api_key.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 -
index 65c8265..942be99 100644 (file)
@@ -119,7 +119,7 @@ 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
 clamp.api.simpledemo.openecomp.org.    IN      CNAME   vm1.clamp.simpledemo.openecomp.org.
 
 ;AAF
index 058725f..09a9e33 100644 (file)
@@ -80,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
index 48c402c..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
@@ -80,6 +81,7 @@ then
        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 0f89057..e216838 100644 (file)
@@ -48,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
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 87aaca4..3f6ea5d 100644 (file)
@@ -48,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
index 0d54565..c1b816e 100644 (file)
@@ -48,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
index a6c1ba4..5b201e0 100755 (executable)
@@ -29,12 +29,17 @@ docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
 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
+
index 81f8e79..3447a01 100644 (file)
@@ -48,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
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 82%
rename from boot/asdc_install.sh
rename to boot/sdc_install.sh
index 0400194..2c32266 100644 (file)
@@ -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/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
@@ -71,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
@@ -139,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 5cf169c..3b5c5cf 100644 (file)
@@ -48,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
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 81%
rename from boot/mso_install.sh
rename to boot/so_install.sh
index d9215b8..d9a8a64 100644 (file)
@@ -49,17 +49,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/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-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
@@ -94,8 +95,8 @@ resolvconf -u
 # Clone Gerrit repository
 cd /opt
 git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO 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
+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
 
 # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes
 if [[ $CLOUD_ENV != "rackspace" ]]
@@ -110,4 +111,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
+./so_vm_init.sh
similarity index 98%
rename from boot/asdc_serv.sh
rename to boot/so_serv.sh
index 7d2539e..d324447 100644 (file)
@@ -10,7 +10,7 @@
 ### END INIT INFO
 
 dir="/opt"
-cmd="./asdc_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 1ec8ae6..118995c 100644 (file)
@@ -48,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
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 964ec08..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
@@ -90,6 +88,7 @@ parameters:
   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
@@ -118,6 +117,44 @@ 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 #
@@ -127,7 +164,7 @@ parameters:
   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 
-  mso_repo: http://gerrit.onap.org/r/so/docker-config.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
@@ -135,3 +172,4 @@ parameters:
   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 a99054c..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,106 +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
-    description: CLAMP IP Address
-
+  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
 
   ###########################
   #                         #
@@ -302,51 +252,98 @@ parameters:
 
   aai_repo:
     type: string
-    description: AAI repository
-
   appc_repo:
     type: string
-    description: APPC repository
-
   dcae_repo:
     type: string
-    description: DCAE repository
-
   mr_repo:
     type: string
-    description: Message Router repository
-
-  mso_repo:
+  so_repo:
     type: string
-    description: MSO repository
-
   policy_repo:
     type: string
-    description: Policy repository
-
   portal_repo:
     type: string
-    description: Portal repository
-
   robot_repo:
     type: string
-    description: Robot repository
-
   sdc_repo:
     type: string
-    description: SDC repository
-
   sdnc_repo:
     type: string
-    description: SDNC repository
-
   vid_repo:
     type: string
-    description: VID repository
-
   clamp_repo:
     type: string
-    description: CLAMP repository
+  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
 
 
 #############
@@ -450,7 +447,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 }
@@ -459,6 +456,7 @@ resources:
             __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: |
@@ -476,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
@@ -485,6 +483,7 @@ resources:
             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
@@ -532,8 +531,8 @@ 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 }
@@ -599,8 +598,8 @@ 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 }
@@ -630,32 +629,32 @@ resources:
             ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
       network: { get_resource: oam_onap }
-      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      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:
@@ -672,11 +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 }
-            __mso_repo__: { get_param: mso_repo }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -698,13 +697,13 @@ 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 "__mso_repo__" > /opt/config/remote_repo.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
@@ -743,7 +742,7 @@ 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 }
@@ -807,24 +806,27 @@ resources:
             __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 }
@@ -841,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
@@ -851,13 +854,15 @@ 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
@@ -907,8 +912,8 @@ 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 }
@@ -972,8 +977,9 @@ 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 }
@@ -990,6 +996,7 @@ 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
@@ -1049,8 +1056,8 @@ 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 }
@@ -1075,10 +1082,10 @@ resources:
             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
@@ -1118,8 +1125,8 @@ 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 }
@@ -1200,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 }
@@ -1326,8 +1333,8 @@ 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 }
@@ -1393,8 +1400,9 @@ 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 }
@@ -1412,6 +1420,7 @@ 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
@@ -1465,8 +1474,8 @@ 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: 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 }
@@ -1497,4 +1506,109 @@ resources:
             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
\ No newline at end of file
+            ./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 bbc7019..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
@@ -93,11 +92,10 @@ parameters:
   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
@@ -108,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
@@ -117,6 +115,7 @@ parameters:
   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
 
   ###########################
   #                         #
@@ -138,6 +137,45 @@ 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 #
@@ -147,7 +185,7 @@ parameters:
   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 
-  mso_repo: http://gerrit.onap.org/r/so/docker-config.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
@@ -155,3 +193,4 @@ parameters:
   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 74e24e4..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,163 +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
-
   clamp_float_ip:
     type: string
-    description: CLAMP Floating IP Address
-
-  ### Private IP addresses ###
-  oam_network_cidr:
+  openo_float_ip:
     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
-    description: CLAMP IP Address
+  openo_ip_addr:
+    type: string
 
 
   ###########################
@@ -368,51 +287,98 @@ parameters:
 
   aai_repo:
     type: string
-    description: AAI repository
-
   appc_repo:
     type: string
-    description: APPC repository
-
   dcae_repo:
     type: string
-    description: DCAE repository
-
   mr_repo:
     type: string
-    description: Message Router repository
-
-  mso_repo:
+  so_repo:
     type: string
-    description: MSO repository
-
   policy_repo:
     type: string
-    description: Policy repository
-
   portal_repo:
     type: string
-    description: Portal repository
-
   robot_repo:
     type: string
-    description: Robot repository
-
   sdc_repo:
     type: string
-    description: SDC repository
-
   sdnc_repo:
     type: string
-    description: SDNC repository
-
   vid_repo:
     type: string
-    description: VID repository
-
   clamp_repo:
     type: string
-    description: CLAMP repository
+  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
 
 
 #############
@@ -520,7 +486,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 }
@@ -529,6 +495,7 @@ resources:
             __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: |
@@ -546,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
@@ -555,6 +522,7 @@ resources:
             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
@@ -603,9 +571,9 @@ 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: |
@@ -671,9 +639,9 @@ 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: |
@@ -702,33 +670,33 @@ resources:
             ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
       network: { get_resource: oam_onap }
-      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      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:
@@ -745,11 +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 }
-            __mso_repo__: { get_param: mso_repo }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -771,13 +739,13 @@ 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 "__mso_repo__" > /opt/config/remote_repo.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
@@ -817,7 +785,7 @@ 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 }
@@ -882,23 +850,26 @@ resources:
             __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 }
@@ -916,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
@@ -926,13 +898,15 @@ 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
@@ -983,8 +957,8 @@ 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 }
@@ -1049,8 +1023,9 @@ 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 }
@@ -1067,6 +1042,7 @@ 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
@@ -1127,8 +1103,8 @@ 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 }
@@ -1153,10 +1129,10 @@ resources:
             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
@@ -1197,8 +1173,8 @@ 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 }
@@ -1280,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 }
@@ -1407,8 +1383,8 @@ 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 }
@@ -1475,8 +1451,9 @@ 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 }
@@ -1494,6 +1471,7 @@ 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
@@ -1548,8 +1526,8 @@ 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: 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 }
@@ -1580,4 +1558,110 @@ resources:
             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
\ No newline at end of file
+            ./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 1ef3c75..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
@@ -87,7 +87,7 @@ parameters:
   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
 
   ###########################
   #                         #
@@ -110,6 +110,44 @@ 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 #
@@ -119,7 +157,7 @@ parameters:
   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 
-  mso_repo: http://gerrit.onap.org/r/so/docker-config.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
@@ -127,3 +165,4 @@ parameters:
   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 05ba223..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,87 +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
-    description: CLAMP IP Address
-
+  openo_ip_addr:
+    type: string
 
   ###########################
   #                         #
@@ -279,51 +239,98 @@ parameters:
 
   aai_repo:
     type: string
-    description: AAI repository
-
   appc_repo:
     type: string
-    description: APPC repository
-
   dcae_repo:
     type: string
-    description: DCAE repository
-
   mr_repo:
     type: string
-    description: Message Router repository
-
-  mso_repo:
+  so_repo:
     type: string
-    description: MSO repository
-
   policy_repo:
     type: string
-    description: Policy repository
-
   portal_repo:
     type: string
-    description: Portal repository
-
   robot_repo:
     type: string
-    description: Robot repository
-
   sdc_repo:
     type: string
-    description: SDC repository
-
   sdnc_repo:
     type: string
-    description: SDNC repository
-
   vid_repo:
     type: string
-    description: VID repository
-
   clamp_repo:
     type: string
-    description: CLAMP repository
+  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
 
 
 #############
@@ -409,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 }
@@ -418,6 +425,7 @@ resources:
             __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: |
@@ -435,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
@@ -444,6 +452,7 @@ resources:
             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
@@ -488,8 +497,8 @@ 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 }
@@ -554,8 +563,8 @@ 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 }
@@ -587,27 +596,27 @@ resources:
             ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
       network: { get_resource: oam_onap }
-      fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mso_ip_addr }}]
+      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:
@@ -624,13 +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 }
-            __mso_repo__: { get_param: mso_repo }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -641,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
@@ -654,13 +663,13 @@ 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 "__mso_repo__" > /opt/config/remote_repo.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
@@ -696,7 +705,7 @@ 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 }
@@ -757,25 +766,28 @@ resources:
             __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 }
@@ -793,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
@@ -805,13 +818,15 @@ 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
@@ -858,8 +873,8 @@ 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 }
@@ -922,8 +937,9 @@ 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 }
@@ -942,6 +958,7 @@ 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
@@ -997,8 +1014,8 @@ 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 }
@@ -1024,10 +1041,10 @@ resources:
             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
@@ -1063,8 +1080,8 @@ 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 }
@@ -1142,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 }
@@ -1253,8 +1270,8 @@ 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 }
@@ -1318,8 +1335,9 @@ 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 }
@@ -1339,6 +1357,7 @@ 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
@@ -1389,8 +1408,8 @@ resources:
             __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: docker_version }
-            __gerrit_branch__: { get_param: gerrit_branch }
+            __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 }
@@ -1423,4 +1442,104 @@ resources:
             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
\ No newline at end of file
+            ./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 5c82a47..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
 
 
@@ -66,17 +62,13 @@ parameters:
   dcae_hdp2_ip_addr: 10.0.4.104
   dcae_hdp3_ip_addr: 10.0.4.105
 
+  # ONAP repositories, docker versions, and Gerrit branches
 
-  #####################
-  #                   #
-  # 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
-  mso_repo: http://gerrit.onap.org/r/so/docker-config.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
@@ -84,3 +76,30 @@ parameters:
   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 260632c..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
@@ -159,55 +151,83 @@ parameters:
     type: string
     description: Hadoop VM3 IP Address
 
-
-  # ONAP repositories
+  # ONAP repositories, docker versions, and Gerrit branches
   aai_repo:
     type: string
-    description: AAI repository
-
   appc_repo:
     type: string
-    description: APPC repository
-
   dcae_repo:
     type: string
-    description: DCAE repository
-
   mr_repo:
     type: string
-    description: Message Router repository
-
-  mso_repo:
+  so_repo:
     type: string
-    description: MSO repository
-
   policy_repo:
     type: string
-    description: Policy repository
-
   portal_repo:
     type: string
-    description: Portal repository
-
   robot_repo:
     type: string
-    description: Robot repository
-
   sdc_repo:
     type: string
-    description: SDC repository
-
   sdnc_repo:
     type: string
-    description: SDNC repository
-
   vid_repo:
     type: string
-    description: VID repository
-
   clamp_repo:
     type: string
-    description: CLAMP repository
+
+  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:
@@ -338,8 +358,8 @@ 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: |
@@ -407,8 +427,8 @@ 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: |
@@ -436,27 +456,27 @@ resources:
             ./aai_install.sh
 
 
-  # MSO instantiation
-  mso_private_port:
+  # SO instantiation
+  so_private_port:
     type: OS::Neutron::Port
     properties:
       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:
@@ -470,10 +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 }
-            __mso_repo__: { get_param: mso_repo }
+            __so_repo__: { get_param: so_repo }
           template: |
             #!/bin/bash
 
@@ -492,13 +512,13 @@ 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 "__mso_repo__" > /opt/config/remote_repo.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
@@ -531,7 +551,7 @@ 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: |
@@ -589,10 +609,11 @@ resources:
             __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: |
@@ -608,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
@@ -618,13 +640,14 @@ 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
@@ -667,8 +690,8 @@ 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: |
@@ -724,8 +747,9 @@ 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: |
@@ -741,6 +765,7 @@ 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
 
@@ -806,8 +831,8 @@ 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: |
@@ -829,10 +854,10 @@ resources:
             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
@@ -875,8 +900,8 @@ 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: |
@@ -945,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 }
@@ -1048,8 +1073,8 @@ 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: |
@@ -1106,8 +1131,9 @@ 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: |
@@ -1124,6 +1150,7 @@ 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
 
@@ -1168,10 +1195,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: clamp_docker }
+            __gerrit_branch__: { get_param: clamp_branch }
             __cloud_env__: { get_param: cloud_env }
-            __mso_repo__: { get_param: clamp_repo }
+            __clamp_repo__: { get_param: clamp_repo }
           template: |
             #!/bin/bash
 
@@ -1196,4 +1223,4 @@ resources:
             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
\ No newline at end of file
+            ./clamp_install.sh
index 790949b..689d1cf 100644 (file)
@@ -19,7 +19,7 @@ parameters:
   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 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
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 82339b0..160add5 100644 (file)
                                        "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 62b77e2..fa53f3c 100644 (file)
@@ -36,7 +36,7 @@
             "next-server": "10.3.0.1",
             "option-data": [
                  {"name": "tftp-server-name",
-                  "data": "10.3.0.1"},
+                  "data": "10.4.0.1"},
                       {"name": "boot-file-name",
                   "data": "/dev/null"}
                ]
index 5505d1c..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
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 c8c567d..f369704 100644 (file)
@@ -49,9 +49,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 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
index 426af3b..feaa770 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 bind9 bind9utils bind9-doc 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 bind9 bind9utils bind9-doc apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev
 sleep 1
 
 # Download DNS and DHCP config files
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
index 84d7a01..91cce8a 100644 (file)
@@ -45,9 +45,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 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
index 89869a0..a6577c4 100644 (file)
@@ -54,9 +54,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 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
@@ -72,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
index 621385c..ca2957a 100644 (file)
@@ -45,9 +45,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 vFirewall demo code for packet generator
@@ -58,8 +59,7 @@ wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/run_streams_d
 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/vlb/vlb_dns_streams/$DEMO_ARTIFACTS_VERSION/vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz 
 
-tar -zxvf vpp.tar.gz
-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_init.sh