diff --git a/basice2e/dsa.json b/basice2e/dsa.json
deleted file mode 100644
index 599d792b46a0458d9f06fbd3cc4b6f9913bcc4cc..0000000000000000000000000000000000000000
--- a/basice2e/dsa.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-	"PrivateKey":"-----BEGIN PRIVATE KEY-----\nMIIDXDCCAzUwggIsAoIBAQCdtvtZUbZrtv4eFA8dLOVQI3QWH9ZTjfFkghhkLwtc\nSMj3pBqt+hhzJLh2dPoYIrAPHs+BNpQ9fFV1cmTloaRP/gEumTbgDB0+kxCwHH0X\nmAXTBYsqn0u2+XFr/mEXxrWzzE2b40EQStSoCtbJTgBfS5k+FPCR61F0O/MwUMON\n4jVWfhs0w9alwM6qGg82ghPD0ZhD0LSwncufxy05yN5B8b8U1LtFY8ooNxYhytMy\nS2otOSFFvr+sdIgFI29cov6SuHHNj5w20ykrVQnKjKp3oq38e/133ab3ESWnRW/q\nFT5DMlaiJhxqBu02k3l+eZX61aq7z74+2idB43VASuJbAiEA8sMRk3TOdsk1aZC0\nZTdKF/I/ntNQib2Wn2HG3emZjB8CggEAXH/2sG+PFD/oKIQzST5HacTZiKzlviWg\n4kgJZwcWxhPXsM7mky+PqnxE0sskUj2lP75PbsNZWJLRqljEMooGxGoVZi5+qnA6\nHez4u7LQXb4uuVbBQqM4Zh0QRhwNE1RyCFBX80lDCf+nPGEfeLMq27V0DDYcnzW+\nkJl9sgFOLvWqYXgvUqvri9ZDLE3Ql7xUI7KF2vtg3DZOgWH0oqNayjoQscTSA8x2\npHCjOv3L3ZKVmFmr2LVuFyUlLXjqxm5xuprj8d0khxmYdDk81NgyGGgAZUdg4eNM\nCeTRVRefnsDcRHP5lr3Obu0cq+2LbxFvetnPUF3w+ZjjSrJ1FLD/5wKCAQEAk8r/\nHxHAAA9Ad3+aMEPWE5CHpQbk30WEkk5aaw8O3L7wLQe9jfjKr+7/nh4MGYKfJYrR\nJ/5dp6/HiNVDgxYAYjl6uyDYCow0rtczOBXBSdjuqQnBdDYCRloH1Uy7kup1tJIA\nLLPa4x0pEZCYx024sXjUq7hXKmeAeQjLYMiSmuC2oyJW3rf/lz27OBpWhejPHtES\nm7gN0G250h8EA4+wPYuArwG0CrBrvBxRhaQZfq6ieWAOMKkvR4VnDIJgmQnCrRnk\nXF2qKrMWgbG5Nd7GR4FJyd39lthdakdg/kPVwtTTPbXNxrYBUChcMb1DBRjkymc4\nmiT9s5PwGFc79iyejQIhAL1LSeSRu8lGmEOj9UE26QVSYtfWBOa4lqJrHCDuSko/\n-----END PRIVATE KEY-----\n"
-}
diff --git a/gen/gateway.yaml b/gen/gateway.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0001165edd70efba65c1eef115eb9d5e245705f6
--- /dev/null
+++ b/gen/gateway.yaml
@@ -0,0 +1,46 @@
+################################################################################
+## Copyright © 2018 Privategrity Corporation                                   #
+##                                                                             #
+## All rights reserved.                                                        #
+################################################################################
+
+##
+# Gateway Configuration File
+##
+
+# Used for debugging
+loglevel: 2
+
+# Output log file
+log: "gateway-1.log"
+
+# The listening port of this gateway
+Port: {GW_ADDR}
+
+# The local IP address of the Gateway used for internal listening.
+localAddress: "0.0.0.0"
+
+# The public IP address of the Node associated with this Gateway.
+nodeAddress: {NODE_ADDR}
+
+# Period in which the message cleanup function executes. Recommended period is on the order of a minute.
+messageTimeout: "60s"
+
+# Path to where the IDF is saved. This is used by the wrapper management script.
+idfPath: "results/gateways/gatewayIDF-0.json"
+
+# === REQUIRED FOR ENABLING TLS ===
+# Path to the private key file
+keyPath: "../keys/cmix.rip.key"
+# Path to the certificate file
+certPath: "../keys/cmix.rip.crt"
+# Path to the permissioning certificate
+schedulingCertPath: "../keys/cmix.rip.crt"
+# Path to the certificate file
+cmixCertPath: "../keys/cmix.rip.crt"
+
+
+
+# Needed to verify that NDF originated from permissioning
+# Path to the permissioning certificate file
+permissioningCertPath: "configurations/keys/permissioning.crt"
diff --git a/gen/network.config b/gen/network.config
new file mode 100644
index 0000000000000000000000000000000000000000..e7242113823cac0bea1eec70d766f3c66acbdf0a
--- /dev/null
+++ b/gen/network.config
@@ -0,0 +1,26 @@
+localhost:8440
+# This is the network configuration file. The top line of this file,
+# when not set via command line, is used to determine to which network
+# the integration test will be run against.
+
+# Note you can also specify "release", "betanet", or "protonet" on run.sh
+
+# Betanet gateways
+109.169.15.30:22840
+5.12.137.118:22840
+92.246.20.92:22840
+178.16.39.203:22840
+86.135.17.18:22840
+
+# Release (messenger test) network gateways
+34.221.74.216:11420
+52.25.9.28:11420
+54.149.122.115:11420
+
+
+# protonet
+185.152.3.247:11420
+93.151.207.39:11420
+93.107.154.131:11420
+173.208.225.75:11421
+92.246.20.92:11420
diff --git a/gen/network.sh b/gen/network.sh
new file mode 100755
index 0000000000000000000000000000000000000000..372f9000697a41f91e4e9d9839c434145377f242
--- /dev/null
+++ b/gen/network.sh
@@ -0,0 +1,114 @@
+# This script is used to start a basic 5 node network for running clients on. It is meant to be `source`'d into a script
+# which will run clients on the network, such as `client-session-tests.sh` or the main `run.sh`. 
+# 
+# You **must** source it, because otherwise the `trap finish EXIT` instruction will cause the network to stop when 
+# network.sh returns to your script or shell. Sourcing it will "import" the commands into your script instead, causing 
+# the trap instruction to stop the network when your script/shell exits.
+
+echo "STARTING SERVERS..."
+
+SERVERCONFIG=servers/
+SERVERLOGS=results/servers
+GATEWAYLOGS=results/gateways
+UDBOUT=results/udb-console.txt
+
+# Copy udbContact into place when running locally.
+cp udbContact.bin results/udbContact.bin
+
+PERMCMD="../bin/permissioning --logLevel $DEBUGLEVEL -c permissioning.yaml "
+$PERMCMD > results/permissioning-console.txt 2>&1 &
+PIDVAL=$!
+echo "$PERMCMD -- $PIDVAL"
+
+
+# Run Client Registrar
+CLIENT_REG_CMD="../bin/client-registrar \
+-l 2 -c client-registrar.yaml"
+$CLIENT_REG_CMD > results/client-registrat-console.txt 2>&1 &
+PIDVAL=$!
+echo "$CLIENT_REG_CMD -- $PIDVAL"
+
+for SERVERID in $(seq 5 -1 1)
+do
+    IDX=$(($SERVERID - 1))
+    SERVERCMD="../bin/server --logLevel $DEBUGLEVEL --config $SERVERCONFIG/server-$SERVERID.yaml"
+    if [ $SERVERID -eq 5 ] && [ -n "$NSYSENABLED" ]
+    then
+        SERVERCMD="nsys profile --session-new=gputest --trace=cuda -o server-$SERVERID $SERVERCMD"
+    fi
+    $SERVERCMD > $SERVERLOGS/server-$SERVERID-console.txt 2>&1 &
+    PIDVAL=$!
+    echo "$SERVERCMD -- $PIDVAL"
+done
+
+# Start gateways
+for GWID in $(seq 5 -1 1)
+do
+    IDX=$(($GWID - 1))
+    GATEWAYCMD="../bin/gateway --logLevel $DEBUGLEVEL --config gateway-$GWID.yaml"
+    $GATEWAYCMD > $GATEWAYLOGS/gateway-$GWID-console.txt 2>&1 &
+    PIDVAL=$!
+    echo "$GATEWAYCMD -- $PIDVAL"
+done
+
+jobs -p > results/serverpids
+
+finish() {
+    echo "STOPPING SERVERS AND GATEWAYS..."
+    if [ -n "$NSYSENABLED" ]
+    then
+        nsys stop --session=gputest
+    fi
+    # NOTE: jobs -p doesn't work in a signal handler
+    for job in $(cat results/serverpids)
+    do
+        echo "KILLING $job"
+        kill $job || true
+    done
+
+    sleep 5
+
+    for job in $(cat results/serverpids)
+    do
+        echo "KILL -9 $job"
+        kill -9 $job || true
+    done
+    #tail $SERVERLOGS/*
+    #tail $CLIENTCLEAN/*
+    #diff -aruN clients.goldoutput $CLIENTCLEAN
+}
+
+trap finish EXIT
+trap finish INT
+
+# Sleeps can die in a fire on the sun, we wait for the servers to start running
+# rounds
+rm rid.txt || true
+touch rid.txt
+cnt=0
+echo -n "Waiting for a round to run"
+while [ ! -s rid.txt ] && [ $cnt -lt 120 ]; do
+    sleep 1
+    grep -a "RID 1 ReceiveFinishRealtime END" results/servers/server-* > rid.txt || true
+    cnt=$(($cnt + 1))
+    echo -n "."
+done
+
+# Start a user discovery bot server
+echo "STARTING UDB..."
+UDBCMD="../bin/udb --logLevel $DEBUGLEVEL --skipVerification --protoUserPath	udbProto.json --config udb.yaml -l 1"
+$UDBCMD >> $UDBOUT 2>&1 &
+PIDVAL=$!
+echo $PIDVAL >> results/serverpids
+echo "$UDBCMD -- $PIDVAL"
+rm rid.txt || true
+while [ ! -s rid.txt ] && [ $cnt -lt 30 ]; do
+    sleep 1
+    grep -a "Sending Poll message" results/udb-console.txt > rid.txt || true
+    cnt=$(($cnt + 1))
+    echo -n "."
+done
+
+echo "localhost:8440" > results/startgwserver.txt
+
+echo "DONE LETS DO STUFF"
\ No newline at end of file
diff --git a/gen/noerrors.txt b/gen/noerrors.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/gen/permissioning.yaml b/gen/permissioning.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..01cc7fb4d9f225edc4e2153d0eaf4bcdb5db6a0b
--- /dev/null
+++ b/gen/permissioning.yaml
@@ -0,0 +1,87 @@
+# ==================================
+# Permissioning Server Configuration
+# ==================================
+
+# Log message level
+loglevel: 2
+# Path to log file
+logPath: "registration.log"
+# Path to the node topology permissioning info
+ndfOutputPath: "ndf.json"
+# Minimum number of nodes to begin running rounds. this differs from the number of members
+# in a team because some scheduling algorithms may require multiple teams worth of nodes at minimum
+minimumNodes: 5
+
+# Path to the file containing the round ID
+roundIdPath: "roundId.txt"
+
+# Path to the file containing the update ID
+updateIdPath: "updateId.txt"
+
+# UDB ID
+udbID: 1
+
+# Public address, used in NDF it gives to client
+publicAdress: "0.0.0.0:11420"
+
+# The listening port of this  server
+port: 11420
+
+# The minimum version required of gateways to connect
+minGatewayVersion: "1.1.0"
+
+# The minimum version required of servers to connect
+minServerVersion:  "1.1.0"
+
+# Database connection information
+dbUsername: "cmix"
+dbPassword: ""
+dbName: "cmix_server"
+dbAddress: "0.0.0.0:5959"
+
+# Path to JSON file with list of Node registration codes (in order of network 
+# placement)
+RegCodesFilePath: "configurations/regCodes.json"
+
+# List of client codes to be added to the database (for testing)
+clientRegCodes:
+  - "AAAA"
+  - "BBBB"
+  - "CCCC"
+    
+
+# Time interval (in seconds) between committing Node statistics to storage
+nodeMetricInterval: 180
+
+# Time interval (in minutes) in which the database is
+# checked for banned nodes
+BanTrackerInterval: "3"
+
+# === REQUIRED FOR ENABLING TLS ===
+# Path to the permissioning server private key file
+keyPath: "configurations/keys/permissioning.key"
+# Path to the permissioning server certificate file
+certPath: "configurations/keys/permissioning.crt"
+
+# E2E/CMIX Primes
+groups:
+  cmix:
+    prime: "F6FAC7E480EE519354C058BF856AEBDC43AD60141BAD5573910476D030A869979A7E23F5FC006B6CE1B1D7CDA849BDE46A145F80EE97C21AA2154FA3A5CF25C75E225C6F3384D3C0C6BEF5061B87E8D583BEFDF790ECD351F6D2B645E26904DE3F8A9861CC3EAD0AA40BD7C09C1F5F655A9E7BA7986B92B73FD9A6A69F54EFC92AC7E21D15C9B85A76084D1EEFBC4781B91E231E9CE5F007BC75A8656CBD98E282671C08A5400C4E4D039DE5FD63AA89A618C5668256B12672C66082F0348B6204DD0ADE58532C967D055A5D2C34C43DF9998820B5DFC4C49C6820191CB3EC81062AA51E23CEEA9A37AB523B24C0E93B440FDC17A50B219AB0D373014C25EE8F"
+    generator: "B22FDF91EE6BA01BDE4969C1A986EA1F81C4A1795921403F3437D681D05E95167C2F6414CCB74AC8D6B3BA8C0E85C7E4DEB0E8B5256D37BC5C21C8BE068F5342858AFF2FC7FF2644EBED8B10271941C74C86CCD71AA6D2D98E4C8C70875044900F842998037A7DFB9BC63BAF1BC2800E73AF9615E4F5B869D4C6DE6E5F48FACE9CA594CC5D228CB7F763A0AD6BF6ED78B27F902D9ADA38A1FCD7D09E398CE377BB15A459044D3B8541DC6D8049B66AE1662682254E69FAD31CA0016251D0522EF8FE587A3F6E3AB1E5F9D8C2998874ABAB205217E95B234A7D3E69713B884918ADB57360B5DE97336C7DC2EB8A3FEFB0C4290E7A92FF5758529AC45273135427"
+  e2e:
+    prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873847AEF49F66E43873"
+    generator: "2"
+
+# Selection of scheduling algorithem to use. Options are:
+#   simple - Schedules multiple teams to maximize performance, does not randomly re-arrange teams, if only a single
+#            only scheduling a single team, will use numerical ordering data for AlphaNet
+#   secure - Schedules new teams randomly, has apropreate buffers to ensure unpredictability, designed for BetaNet
+schedulingAlgorithm: "simple"
+
+# Path to file with config for scheduling algorithem within the user directory 
+schedulingConfigPath: "configurations/registration.json"
+
+# Time that the registration server waits before timing out while killing the round scheduling thread
+schedulingKillTimeout: 10s
+# Time the registration waits for rounds to close out and stop (optional)
+closeTimeout: 60s
diff --git a/gen/registration.json b/gen/registration.json
new file mode 100644
index 0000000000000000000000000000000000000000..f400c7eb3334920b7f93396409ae19fb013d9073
--- /dev/null
+++ b/gen/registration.json
@@ -0,0 +1,12 @@
+{
+    "TeamSize": 5,
+    "PrecomputationTimeout": 30000,
+    "RealtimeTimeout": 15000,
+    "DebugTrackRounds": true,
+    "BatchSize": 32,
+    "MinimumDelay": 1000,
+    "RealtimeDelay": 2000,
+    "Threshold":     0.3,
+    "NodeCleanUpInterval": 180000,
+    "ResourceQueueTimeout": 300000
+}
\ No newline at end of file
diff --git a/gen/run.sh b/gen/run.sh
new file mode 100644
index 0000000000000000000000000000000000000000..dbb49f5120530d7f3f0728eb6cc3278f43361c13
--- /dev/null
+++ b/gen/run.sh
@@ -0,0 +1,78 @@
+cp ../network/network.sh temp_network.sh
+
+mkdir -p $SERVERLOGS
+mkdir -p $GATEWAYLOGS
+mkdir -p $CLIENTOUT
+mkdir -p $CLIENTCLEAN
+
+mkdir -p $SERVERLOGS
+mkdir -p $GATEWAYLOGS
+mkdir -p $CLIENTOUT
+mkdir -p $CLIENTCLEAN
+
+
+################################################################################
+## Network Set Up
+################################################################################
+
+
+if [ "$NETWORKENTRYPOINT" == "betanet" ]
+then
+    NETWORKENTRYPOINT=$(sort -R betanet.txt | head -1)
+elif [ "$NETWORKENTRYPOINT" == "mainnet" ]
+then
+    NETWORKENTRYPOINT=$(sort -R mainnet.txt | head -1)
+elif [ "$NETWORKENTRYPOINT" == "release" ]
+then
+    NETWORKENTRYPOINT=$(sort -R release.txt | head -1)
+elif [ "$NETWORKENTRYPOINT" == "devnet" ]
+then
+    NETWORKENTRYPOINT=$(sort -R devnet.txt | head -1)
+elif [ "$NETWORKENTRYPOINT" == "" ]
+then
+    NETWORKENTRYPOINT=$(head -1 network.config)
+fi
+
+echo "NETWORK: $NETWORKENTRYPOINT"
+
+if [ "$NETWORKENTRYPOINT" == "localhost:8440" ]
+then
+    source network.sh
+
+else
+    echo "Connecting to network defined at $NETWORKENTRYPOINT"
+    echo $NETWORKENTRYPOINT > results/startgwserver.txt
+fi
+
+echo "DOWNLOADING TLS Cert..."
+# -alpn h2 added to mimic grpc headers
+CMD="openssl s_client -alpn h2 -showcerts -connect $(tr -d '[:space:]' < results/startgwserver.txt)"
+echo $CMD
+eval $CMD < /dev/null 2>&1 > "results/startgwcert.bin"
+CMD="cat results/startgwcert.bin | openssl x509 -outform PEM"
+echo $CMD
+eval $CMD > "results/startgwcert.pem"
+head "results/startgwcert.pem"
+
+echo "DOWNLOADING NDF..."
+CLIENTCMD="../bin/client getndf --gwhost $(tr -d '[:space:]' < results/startgwserver.txt) --cert results/startgwcert.pem"
+eval $CLIENTCMD >> results/ndf.json 2>&1 &
+PIDVAL=$!
+echo "$CLIENTCMD -- $PIDVAL"
+wait $PIDVAL
+
+cat results/ndf.json | jq . | head -5
+
+file results/ndf.json
+
+if [ ! -s results/ndf.json ]
+then
+    echo "results/ndf.json is empty, cannot proceed"
+    exit -1
+fi
+
+####################################
+# Insert client tests here
+
+#####################################
+rm temp_network.sh
\ No newline at end of file
diff --git a/gen/server.yaml b/gen/server.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..026c367bb515dab4b4c5da22406b3f3462c620c1
--- /dev/null
+++ b/gen/server.yaml
@@ -0,0 +1,40 @@
+# START YAML ===
+registrationCode: "AAAA"
+useGPU: false
+logLevel: 2
+
+node:
+  paths:
+    # Path where the ID will be stored after the ID is created on first run
+    # used by the wrapper script
+    errOutput: "errServer-0.txt"
+    # Path where the ID will be stored after the ID is created on first run
+    # used by the wrapper script
+    idf:  "nodeID-1.json"
+    # Path to the self signed TLS cert that the node uses for identification
+    cert: "configurations/keys/server-1.crt"
+    # Path to the private key for the self signed TLS cert
+    key:  "configurations/keys/server-1.key"
+    # Path to where the log will be stored
+    log:  "server-1.log"
+  port: {NODE_ADDR}
+database:
+  name: "cmix_server"
+  username: "cmix"
+  password: ""
+  addresses: {DB_ADDR}
+gateway:
+  paths:
+    # Path to the self signed TLS cert used by the gateway
+    cert: "configurations/keys/gateway-1.crt"
+permissioning:
+  paths:
+    # Path to the self signed TLS cert used by the permissioning. Provided by xx network
+    cert: "configurations/keys/permissioning.crt"
+  # IP Address of the permissioning server, provided by xx network
+  address: "0.0.0.0:11420"
+metrics:
+  # location of stored metrics data. Modification to set to permissioning
+  # server instead of saving will be made at a later date
+  log:  "metrics-server-1.log"
+# === END YAML
diff --git a/generatePackage.py b/generatePackage.py
new file mode 100755
index 0000000000000000000000000000000000000000..81d166a94f88c30ae613d249826d2fe65dd67be1
--- /dev/null
+++ b/generatePackage.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import os
+import string
+import random
+import argparse
+from collections.abc import Sequence
+# Generates a random string
+def random_string(stringLength=4):
+    letters = string.ascii_lowercase
+    return ''.join(random.choice(letters) for i in range(stringLength))
+
+
+# Generate a list of all ports servers and gateways occupy. Doing this as a
+# separate step because their configs need every one listed, and generating them
+# once is lighter on CPU cycles. Takes an offset to ensure no port collisions
+# occur with existing packages
+def create_ports_list(offset, manualOffset=0):
+    # Array of integers for ports of each server and gateway in the network
+    gateway_ports = []
+    node_ports = []
+    node_regCodes = []
+
+    for i in range(nodes):
+        gateway_ports.append(1000 + 1000 * offset + manualOffset + i)
+        node_ports.append(10000 + 1000 * offset + i)
+
+        regCode = random_string()
+        # If this regCode is already in the list, we loop until we get one that
+        # isn't
+        while regCode in node_regCodes:
+            regCode = random_string()
+        node_regCodes.append(regCode)
+    return gateway_ports, node_ports, node_regCodes
+
+# Generate server and gateway configs
+def generate_server_side_config(offset, newPackage):
+
+    nodes = 5
+
+    server_template = ""
+    with open("gen/server.yaml") as f:
+        server_template = f.read()
+
+    gateway_template = ""
+    with open("gen/gateway.yaml") as f:
+        gateway_template = f.read()
+
+    reg_template = ""
+    with open("gen/permissioning.yaml") as f:
+        reg_template = f.read()
+
+    reg_json_template = ""
+    with open("gen/registration.json") as f:
+        reg_json_template = f.read()
+
+
+
+    gateway_ports, node_ports, node_regCodes = create_ports_list(offset)
+
+
+
+    for i in range(nodes):
+        with open(newPackage + "/configurations/servers/server-{}.yml".format(i), 'w') as f:
+            # Array of strings defining node and gateway IPs and ports
+            node_addrs = []
+            node_addrs.append("\"{}\"".format(node_ports[i]))
+
+            # Create a new config based on template
+            s_config = server_template.replace("server-1", "server-" + str(i)) \
+                .replace("gateway-1", "gateway-" + str(i)) \
+                .replace("{NODE_ADDR}", "\r\n".join(node_addrs)) \
+                .replace("{DB_ADDR}", "".join(["\"\""])) \
+                .replace("AAAA", node_regCodes[i]) \
+                .replace("nodeID-1.json", "nodeID-"+str(i)+".json") \
+                .replace("errServer-0.txt", "errServer-"+str(i)+".txt")
+            f.write(s_config)
+
+
+        with open(newPackage + "/configurations/gateways/gateway-{}.yml".format(i), 'w') as f:
+            # Array of strings defining node and gateway IPs and ports
+            node_addrs = []
+            node_addrs.append(" \"0.0.0.0:{}\"".format(node_ports[i]))
+
+            # Create a new config based on template
+            g_config = gateway_template.replace("server-1", "server-" + str(i)) \
+                .replace("gateway-1", "gateway-" + str(i)) \
+                .replace("8200", str(gateway_ports[i])) \
+                .replace("{NODE_ADDR}", "\r\n".join(node_addrs)) \
+                .replace("gatewayIDF-0", "gatewayIDF-" + str(i))
+
+            f.write(g_config)
+
+
+
+    # Generate regCodes file
+    with open(newPackage + "/configurations/regCodes.json", "w") as f:
+        f.write("[")
+
+        for i in range(nodes):
+            f.write("{\"RegCode\": \"" + node_regCodes[i] + "\", \"Order\": \"" + \
+                str(i) + "\"}")
+            # If not the last element, write a comma
+            if i is not (nodes - 1):
+                f.write(",")
+
+        f.write("]")
+
+
+# Count the number of packages previously created by counting
+# run.sh files creates
+def count_run_sh_files():
+    current_dir = os.getcwd()
+    count = 0
+    for root, dirs, files in os.walk(current_dir):
+        for file in files:
+            if file == "run.sh":
+                count += 1
+    return count
+
+
+def main(argv: Sequence[str] | None = None) -> int:
+    run_sh_count = count_run_sh_files()
+
+    parser = argparse.ArgumentParser()
+    subparsers = parser.add_subparsers(dest="command", required=True)
+
+    # Add sub-commands
+    count_parser = subparsers.add_parser("count", help="This will count the number of run.sh and print the result.")
+    count_parser.add_argument("string")
+
+
+    gen_parser = subparsers.add_parser("generate", description="Generates a template package that can be used for client tests.")
+    gen_parser.add_argument("offset", type=int, default=0, help="Optional argument. Used when several programmers are separating tests simultaneously.")
+    gen_parser.add_argument("pkg", help="The name of the package that will be generated.")
+
+    args = parser.parse_args(argv)
+
+    if args.command == "count":
+        print(f"Number of occurrences of run.sh in all subdirectories: {run_sh_count}")
+        return
+    elif args.command == "generate":
+        # todo: It may be that the serveral programmers are separating tests
+        # simultaneously. If they are doing this, it's likely their offsets will be
+        # the same and they will generate newtorks operating on the same port.
+        # In which case, there should be some way to input
+        # an argument to just run the count function and output the result.
+        # Instruct in the guide (some readme) that the user should post this offset
+        # Have an argument that  takes this offset and adds it to run_sh_count
+        # Request new package name from user
+        #newPackage = string(input("Name of new package: "))
+        #os.makedirs(os.path.dirname(newPackage), exist_ok=True)
+        generate_server_side_config(run_sh_count + args.offset, args.pkg)
+    else:
+        raise NotImplementedError(
+            f"Command {args.command} does not exist.",
+        )
+
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/network/network.sh b/network/network.sh
new file mode 100755
index 0000000000000000000000000000000000000000..372f9000697a41f91e4e9d9839c434145377f242
--- /dev/null
+++ b/network/network.sh
@@ -0,0 +1,114 @@
+# This script is used to start a basic 5 node network for running clients on. It is meant to be `source`'d into a script
+# which will run clients on the network, such as `client-session-tests.sh` or the main `run.sh`. 
+# 
+# You **must** source it, because otherwise the `trap finish EXIT` instruction will cause the network to stop when 
+# network.sh returns to your script or shell. Sourcing it will "import" the commands into your script instead, causing 
+# the trap instruction to stop the network when your script/shell exits.
+
+echo "STARTING SERVERS..."
+
+SERVERCONFIG=servers/
+SERVERLOGS=results/servers
+GATEWAYLOGS=results/gateways
+UDBOUT=results/udb-console.txt
+
+# Copy udbContact into place when running locally.
+cp udbContact.bin results/udbContact.bin
+
+PERMCMD="../bin/permissioning --logLevel $DEBUGLEVEL -c permissioning.yaml "
+$PERMCMD > results/permissioning-console.txt 2>&1 &
+PIDVAL=$!
+echo "$PERMCMD -- $PIDVAL"
+
+
+# Run Client Registrar
+CLIENT_REG_CMD="../bin/client-registrar \
+-l 2 -c client-registrar.yaml"
+$CLIENT_REG_CMD > results/client-registrat-console.txt 2>&1 &
+PIDVAL=$!
+echo "$CLIENT_REG_CMD -- $PIDVAL"
+
+for SERVERID in $(seq 5 -1 1)
+do
+    IDX=$(($SERVERID - 1))
+    SERVERCMD="../bin/server --logLevel $DEBUGLEVEL --config $SERVERCONFIG/server-$SERVERID.yaml"
+    if [ $SERVERID -eq 5 ] && [ -n "$NSYSENABLED" ]
+    then
+        SERVERCMD="nsys profile --session-new=gputest --trace=cuda -o server-$SERVERID $SERVERCMD"
+    fi
+    $SERVERCMD > $SERVERLOGS/server-$SERVERID-console.txt 2>&1 &
+    PIDVAL=$!
+    echo "$SERVERCMD -- $PIDVAL"
+done
+
+# Start gateways
+for GWID in $(seq 5 -1 1)
+do
+    IDX=$(($GWID - 1))
+    GATEWAYCMD="../bin/gateway --logLevel $DEBUGLEVEL --config gateway-$GWID.yaml"
+    $GATEWAYCMD > $GATEWAYLOGS/gateway-$GWID-console.txt 2>&1 &
+    PIDVAL=$!
+    echo "$GATEWAYCMD -- $PIDVAL"
+done
+
+jobs -p > results/serverpids
+
+finish() {
+    echo "STOPPING SERVERS AND GATEWAYS..."
+    if [ -n "$NSYSENABLED" ]
+    then
+        nsys stop --session=gputest
+    fi
+    # NOTE: jobs -p doesn't work in a signal handler
+    for job in $(cat results/serverpids)
+    do
+        echo "KILLING $job"
+        kill $job || true
+    done
+
+    sleep 5
+
+    for job in $(cat results/serverpids)
+    do
+        echo "KILL -9 $job"
+        kill -9 $job || true
+    done
+    #tail $SERVERLOGS/*
+    #tail $CLIENTCLEAN/*
+    #diff -aruN clients.goldoutput $CLIENTCLEAN
+}
+
+trap finish EXIT
+trap finish INT
+
+# Sleeps can die in a fire on the sun, we wait for the servers to start running
+# rounds
+rm rid.txt || true
+touch rid.txt
+cnt=0
+echo -n "Waiting for a round to run"
+while [ ! -s rid.txt ] && [ $cnt -lt 120 ]; do
+    sleep 1
+    grep -a "RID 1 ReceiveFinishRealtime END" results/servers/server-* > rid.txt || true
+    cnt=$(($cnt + 1))
+    echo -n "."
+done
+
+# Start a user discovery bot server
+echo "STARTING UDB..."
+UDBCMD="../bin/udb --logLevel $DEBUGLEVEL --skipVerification --protoUserPath	udbProto.json --config udb.yaml -l 1"
+$UDBCMD >> $UDBOUT 2>&1 &
+PIDVAL=$!
+echo $PIDVAL >> results/serverpids
+echo "$UDBCMD -- $PIDVAL"
+rm rid.txt || true
+while [ ! -s rid.txt ] && [ $cnt -lt 30 ]; do
+    sleep 1
+    grep -a "Sending Poll message" results/udb-console.txt > rid.txt || true
+    cnt=$(($cnt + 1))
+    echo -n "."
+done
+
+echo "localhost:8440" > results/startgwserver.txt
+
+echo "DONE LETS DO STUFF"
\ No newline at end of file
diff --git a/server b/server
deleted file mode 100755
index b18932c5bf6c56eb7eb6cb1452474d0ea76de9a7..0000000000000000000000000000000000000000
Binary files a/server and /dev/null differ
diff --git a/test.py b/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391