text:
#include <arpa/inet.h>
#include <getopt.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/virtio_net.h>
#include <linux/virtio_ring.h>
#include <signal.h>
#include <stdint.h>
#include <sys/eventfd.h>
#include <sys/param.h>
#include <unistd.h>

#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_ethdev.h>
#include <rte_log.h>
#include <rte_string_fns.h>
#include <rte_malloc.h>
#include <rte_virtio_net.h>
#include <rte_ip.h>
#include <rte_tcp.h>

#include "main.h"

#ifndef MAX_QUEUES
#define MAX_QUEUES 128
#endif

/* the maximum number of external ports supported */
#define MAX_SUP_PORTS 1

#define MBUF_CACHE_SIZE	128
#define MBUF_DATA_SIZE	RTE_MBUF_DEFAULT_BUF_SIZE

#define MAX_PKT_BURST 32		/* Max burst size for RX/TX */
#define BURST_TX_DRAIN_US 100	/* TX drain every ~100us */

#define BURST_RX_WAIT_US 15	/* Defines how long we wait between retries on RX */
#define BURST_RX_RETRIES 4		/* Number of retries on RX. */

#define JUMBO_FRAME_MAX_SIZE    0x2600

/* State of virtio device. */
#define DEVICE_MAC_LEARNING 0
#define DEVICE_RX			1
#define DEVICE_SAFE_REMOVE	2

/* Configurable number of RX/TX ring descriptors */
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 512

#define INVALID_PORT_ID 0xFF

/* Max number of devices. Limited by vmdq. */
#define MAX_DEVICES 64

/* Size of buffers used for snprintfs. */
#define MAX_PRINT_BUFF 6072

/* Maximum long option length for option parsing. */
#define MAX_LONG_OPT_SZ 64

/* mask of enabled ports */
static uint32_t enabled_port_mask = 0;

/* Promiscuous mode */
static uint32_t promiscuous;

/* number of devices/queues to support*/
static uint32_t num_queues = 0;
static uint32_t num_devices;

static struct rte_mempool *mbuf_pool;
static int mergeable;

/* Enable VM2VM communications. If this is disabled then the MAC address compare is skipped. */
typedef enum {
	VM2VM_DISABLED = 0,
	VM2VM_SOFTWARE = 1,
	VM2VM_HARDWARE = 2,
	VM2VM_LAST
} vm2vm_type;
static vm2vm_type vm2vm_mode = VM2VM_SOFTWARE;

/* Enable stats. */
static uint32_t enable_stats = 0;
/* Enable retries on RX. */
static uint32_t enable_retry = 1;

/* Disable TX checksum offload */
static uint32_t enable_tx_csum;

/* Disable TSO offload */
static uint32_t enable_tso;

static int client_mode;
static int dequeue_zero_copy;

/* Specify timeout (in useconds) between retries on RX. */
static uint32_t burst_rx_delay_time = BURST_RX_WAIT_US;
/* Specify the number of retries on RX. */
static uint32_t burst_rx_retry_num = BURST_RX_RETRIES;

/* Socket file paths. Can be set by user */
static char *socket_files;
static int nb_sockets;

/* empty vmdq configuration structure. Filled in programatically */
static struct rte_eth_conf vmdq_conf_default = {
	.rxmode = {
		.mq_mode        = ETH_MQ_RX_VMDQ_ONLY,
		.split_hdr_size = 0,
		.header_split   = 0, /**< Header Split disabled */
		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
		/*
		 * It is necessary for 1G NIC such as I350,
		 * this fixes bug of ipv4 forwarding in guest can't
		 * forward pakets from one virtio dev to another virtio dev.
		 */
		.hw_vlan_strip  = 1, /**< VLAN strip enabled. */
		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
	},

	.txmode = {
		.mq_mode = ETH_MQ_TX_NONE,
	},
	.rx_adv_conf = {
		/*
		 * should be overridden separately in code with
		 * appropriate values
		 */
		.vmdq_rx_conf = {
			.nb_queue_pools = ETH_8_POOLS,
			.enable_default_pool = 0,
			.default_pool = 0,
			.nb_pool_maps = 0,
			.pool_map = {{0, 0},},
		},
	},
};

static unsigned lcore_ids[RTE_MAX_LCORE];
static uint8_t ports[RTE_MAX_ETHPORTS];
static unsigned num_ports = 0; /**< The number of ports specified in command line */
static uint16_t num_pf_queues, num_vmdq_queues;
static uint16_t vmdq_pool_base, vmdq_queue_base;
static uint16_t queues_per_pool;

const uint16_t vlan_tags[] = {
	1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
	1008, 1009, 1010, 1011,	1012, 1013, 1014, 1015,
	1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
	1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031,
	1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039,
	1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047,
	1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055,
	1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
};

/* ethernet addresses of ports */
static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];

static struct vhost_dev_tailq_list vhost_dev_list =
	TAILQ_HEAD_INITIALIZER(vhost_dev_list);

static struct lcore_info lcore_info[RTE_MAX_LCORE];

/* Used for queueing bursts of TX packets. */
struct mbuf_table {
	unsigned len;
	unsigned txq_id;
	struct rte_mbuf *m_table[MAX_PKT_BURST];
};

/* TX queue for each data core. */
struct mbuf_table lcore_tx_queue[RTE_MAX_LCORE];

#define MBUF_TABLE_DRAIN_TSC	((rte_get_tsc_hz() + US_PER_S - 1) \
				 / US_PER_S * BURST_TX_DRAIN_US)
#define VLAN_HLEN       4

/*
 * Builds up the correct configuration for VMDQ VLAN pool map
 * according to the pool & queue limits.
 */
static inline int
get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_devices)
{
	struct rte_eth_vmdq_rx_conf conf;
	struct rte_eth_vmdq_rx_conf *def_conf =
		&vmdq_conf_default.rx_adv_conf.vmdq_rx_conf;
	unsigned i;

	memset(&conf, 0, sizeof(conf));
	conf.nb_queue_pools = (enum rte_eth_nb_pools)num_devices;
	conf.nb_pool_maps = num_devices;
	conf.enable_loop_back = def_conf->enable_loop_back;
	conf.rx_mode = def_conf->rx_mode;

	for (i = 0; i < conf.nb_pool_maps; i++) {
		conf.pool_map[i].vlan_id = vlan_tags[ i ];
		conf.pool_map[i].pools = (1UL << i);
	}

	(void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_rx_conf, &conf,
		   sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
	return 0;
}

/*
 * Validate the device number according to the max pool number gotten form
 * dev_info. If the device number is invalid, give the error message and
 * return -1. Each device must have its own pool.
 */
static inline int
validate_num_devices(uint32_t max_nb_devices)
{
	if (num_devices > max_nb_devices) {
		RTE_LOG(ERR, VHOST_PORT, "invalid number of devices\n");
		return -1;
	}
	return 0;
}

/*
 * Initialises a given port using global settings and with the rx buffers
 * coming from the mbuf_pool passed as parameter
 */
static inline int
port_init(uint8_t port)
{
	struct rte_eth_dev_info dev_info;
	struct rte_eth_conf port_conf;
	struct rte_eth_rxconf *rxconf;
	struct rte_eth_txconf *txconf;
	int16_t rx_rings, tx_rings;
	uint16_t rx_ring_size, tx_ring_size;
	int retval;
	uint16_t q;

	/* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
	rte_eth_dev_info_get (port, &dev_info);

	if (dev_info.max_rx_queues > MAX_QUEUES) {
		rte_exit(EXIT_FAILURE,
			"please define MAX_QUEUES no less than %u in %s\n",
			dev_info.max_rx_queues, __FILE__);
	}

	rxconf = &dev_info.default_rxconf;
	txconf = &dev_info.default_txconf;
	rxconf->rx_drop_en = 1;

	/* Enable vlan offload */
	txconf->txq_flags &= ~ETH_TXQ_FLAGS_NOVLANOFFL;

	/*configure the number of supported virtio devices based on VMDQ limits */
	num_devices = dev_info.max_vmdq_pools;

	rx_ring_size = RTE_TEST_RX_DESC_DEFAULT;
	tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;

	/*
	 * When dequeue zero copy is enabled, guest Tx used vring will be
	 * updated only when corresponding mbuf is freed. Thus, the nb_tx_desc
	 * (tx_ring_size here) must be small enough so that the driver will
	 * hit the free threshold easily and free mbufs timely. Otherwise,
	 * guest Tx vring would be starved.
	 */
	if (dequeue_zero_copy)
		tx_ring_size = 64;

	tx_rings = (uint16_t)rte_lcore_count();

	retval = validate_num_devices(MAX_DEVICES);
	if (retval < 0)
		return retval;

	/* Get port configuration. */
	retval = get_eth_conf(&port_conf, num_devices);
	if (retval < 0)
		return retval;
	/* NIC queues are divided into pf queues and vmdq queues.  */
	num_pf_queues = dev_info.max_rx_queues - dev_info.vmdq_queue_num;
	queues_per_pool = dev_info.vmdq_queue_num / dev_info.max_vmdq_pools;
	num_vmdq_queues = num_devices * queues_per_pool;
	num_queues = num_pf_queues + num_vmdq_queues;
	vmdq_queue_base = dev_info.vmdq_queue_base;
	vmdq_pool_base  = dev_info.vmdq_pool_base;
	printf("pf queue num: %u, configured vmdq pool num: %u, each vmdq pool has %u queues\n",
		num_pf_queues, num_devices, queues_per_pool);

	if (port >= rte_eth_dev_count()) return -1;

	if (enable_tx_csum == 0)
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_CSUM);

	if (enable_tso == 0) {
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_HOST_TSO4);
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_HOST_TSO6);
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_GUEST_TSO4);
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_GUEST_TSO6);
	}

	rx_rings = (uint16_t)dev_info.max_rx_queues;
	/* Configure ethernet device. */
	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
	if (retval != 0) {
		RTE_LOG(ERR, VHOST_PORT, "Failed to configure port %u: %s.\n",
			port, strerror(-retval));
		return retval;
	}

	/* Setup the queues. */
	for (q = 0; q < rx_rings; q ++) {
		retval = rte_eth_rx_queue_setup(port, q, rx_ring_size,
						rte_eth_dev_socket_id(port),
						rxconf,
						mbuf_pool);
		if (retval < 0) {
			RTE_LOG(ERR, VHOST_PORT,
				"Failed to setup rx queue %u of port %u: %s.\n",
				q, port, strerror(-retval));
			return retval;
		}
	}
	for (q = 0; q < tx_rings; q ++) {
		retval = rte_eth_tx_queue_setup(port, q, tx_ring_size,
						rte_eth_dev_socket_id(port),
						txconf);
		if (retval < 0) {
			RTE_LOG(ERR, VHOST_PORT,
				"Failed to setup tx queue %u of port %u: %s.\n",
				q, port, strerror(-retval));
			return retval;
		}
	}

	/* Start the device. */
	retval  = rte_eth_dev_start(port);
	if (retval < 0) {
		RTE_LOG(ERR, VHOST_PORT, "Failed to start port %u: %s\n",
			port, strerror(-retval));
		return retval;
	}

	if (promiscuous)
		rte_eth_promiscuous_enable(port);

	rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
	RTE_LOG(INFO, VHOST_PORT, "Max virtio devices supported: %u\n", num_devices);
	RTE_LOG(INFO, VHOST_PORT, "Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
			(unsigned)port,
			vmdq_ports_eth_addr[port].addr_bytes[0],
			vmdq_ports_eth_addr[port].addr_bytes[1],
			vmdq_ports_eth_addr[port].addr_bytes[2],
			vmdq_ports_eth_addr[port].addr_bytes[3],
			vmdq_ports_eth_addr[port].addr_bytes[4],
			vmdq_ports_eth_addr[port].addr_bytes[5]);

	return 0;
}

/*
 * Set socket file path.
 */
static int
us_vhost_parse_socket_path(const char *q_arg)
{
	/* parse number string */
	if (strnlen(q_arg, PATH_MAX) > PATH_MAX)
		return -1;

	socket_files = realloc(socket_files, PATH_MAX * (nb_sockets + 1));
	snprintf(socket_files + nb_sockets * PATH_MAX, PATH_MAX, "%s", q_arg);
	nb_sockets++;

	return 0;
}

/*
 * Parse the portmask provided at run time.
 */
static int
parse_portmask(const char *portmask)
{
	char *end = NULL;
	unsigned long pm;

	errno = 0;

	/* parse hexadecimal string */
	pm = strtoul(portmask, &end, 16);
	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0))
		return -1;

	if (pm == 0)
		return -1;

	return pm;

}

/*
 * Parse num options at run time.
 */
static int
parse_num_opt(const char *q_arg, uint32_t max_valid_value)
{
	char *end = NULL;
	unsigned long num;

	errno = 0;

	/* parse unsigned int string */
	num = strtoul(q_arg, &end, 10);
	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0))
		return -1;

	if (num > max_valid_value)
		return -1;

	return num;

}

/*
 * Display usage
 */
static void
us_vhost_usage(const char *prgname)
{
	RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
	"		--vm2vm [0|1|2]\n"
	"		--rx_retry [0|1] --mergeable [0|1] --stats [0-N]\n"
	"		--socket-file <path>\n"
	"		--nb-devices ND\n"
	"		-p PORTMASK: Set mask for ports to be used by application\n"
	"		--vm2vm [0|1|2]: disable/software(default)/hardware vm2vm comms\n"
	"		--rx-retry [0|1]: disable/enable(default) retries on rx. Enable retry if destintation queue is full\n"
	"		--rx-retry-delay [0-N]: timeout(in usecond) between retries on RX. This makes effect only if retries on rx enabled\n"
	"		--rx-retry-num [0-N]: the number of retries on rx. This makes effect only if retries on rx enabled\n"
	"		--mergeable [0|1]: disable(default)/enable RX mergeable buffers\n"
	"		--stats [0-N]: 0: Disable stats, N: Time in seconds to print stats\n"
	"		--socket-file: The path of the socket file.\n"
	"		--tx-csum [0|1] disable/enable TX checksum offload.\n"
	"		--tso [0|1] disable/enable TCP segment offload.\n"
	"		--client register a vhost-user socket as client mode.\n"
	"		--dequeue-zero-copy enables dequeue zero copy\n",
	       prgname);
}

/*
 * Parse the arguments given in the command line of the application.
 */
static int
us_vhost_parse_args(int argc, char **argv)
{
	int opt, ret;
	int option_index;
	unsigned i;
	const char *prgname = argv[0];
	static struct option long_option[] = {
		{"vm2vm", required_argument, NULL, 0},
		{"rx-retry", required_argument, NULL, 0},
		{"rx-retry-delay", required_argument, NULL, 0},
		{"rx-retry-num", required_argument, NULL, 0},
		{"mergeable", required_argument, NULL, 0},
		{"stats", required_argument, NULL, 0},
		{"socket-file", required_argument, NULL, 0},
		{"tx-csum", required_argument, NULL, 0},
		{"tso", required_argument, NULL, 0},
		{"client", no_argument, &client_mode, 1},
		{"dequeue-zero-copy", no_argument, &dequeue_zero_copy, 1},
		{NULL, 0, 0, 0},
	};

	/* Parse command line */
	while ((opt = getopt_long(argc, argv, "p:P",
			long_option, &option_index)) != EOF) {
		switch (opt) {
		/* Portmask */
		case 'p':
			enabled_port_mask = parse_portmask(optarg);
			if (enabled_port_mask == 0) {
				RTE_LOG(INFO, VHOST_CONFIG, "Invalid portmask\n");
				us_vhost_usage(prgname);
				return -1;
			}
			break;

		case 'P':
			promiscuous = 1;
			vmdq_conf_default.rx_adv_conf.vmdq_rx_conf.rx_mode =
				ETH_VMDQ_ACCEPT_BROADCAST |
				ETH_VMDQ_ACCEPT_MULTICAST;
			rte_vhost_feature_enable(1ULL << VIRTIO_NET_F_CTRL_RX);

			break;

		case 0:
			/* Enable/disable vm2vm comms. */
			if (!strncmp(long_option[option_index].name, "vm2vm",
				MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, (VM2VM_LAST - 1));
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG,
						"Invalid argument for "
						"vm2vm [0|1|2]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					vm2vm_mode = (vm2vm_type)ret;
				}
			}

			/* Enable/disable retries on RX. */
			if (!strncmp(long_option[option_index].name, "rx-retry", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, 1);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for rx-retry [0|1]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					enable_retry = ret;
				}
			}

			/* Enable/disable TX checksum offload. */
			if (!strncmp(long_option[option_index].name, "tx-csum", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, 1);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for tx-csum [0|1]\n");
					us_vhost_usage(prgname);
					return -1;
				} else
					enable_tx_csum = ret;
			}

			/* Enable/disable TSO offload. */
			if (!strncmp(long_option[option_index].name, "tso", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, 1);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for tso [0|1]\n");
					us_vhost_usage(prgname);
					return -1;
				} else
					enable_tso = ret;
			}

			/* Specify the retries delay time (in useconds) on RX. */
			if (!strncmp(long_option[option_index].name, "rx-retry-delay", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, INT32_MAX);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for rx-retry-delay [0-N]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					burst_rx_delay_time = ret;
				}
			}

			/* Specify the retries number on RX. */
			if (!strncmp(long_option[option_index].name, "rx-retry-num", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, INT32_MAX);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for rx-retry-num [0-N]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					burst_rx_retry_num = ret;
				}
			}

			/* Enable/disable RX mergeable buffers. */
			if (!strncmp(long_option[option_index].name, "mergeable", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, 1);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for mergeable [0|1]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					mergeable = !!ret;
					if (ret) {
						vmdq_conf_default.rxmode.jumbo_frame = 1;
						vmdq_conf_default.rxmode.max_rx_pkt_len
							= JUMBO_FRAME_MAX_SIZE;
					}
				}
			}

			/* Enable/disable stats. */
			if (!strncmp(long_option[option_index].name, "stats", MAX_LONG_OPT_SZ)) {
				ret = parse_num_opt(optarg, INT32_MAX);
				if (ret == -1) {
					RTE_LOG(INFO, VHOST_CONFIG,
						"Invalid argument for stats [0..N]\n");
					us_vhost_usage(prgname);
					return -1;
				} else {
					enable_stats = ret;
				}
			}

			/* Set socket file path. */
			if (!strncmp(long_option[option_index].name,
						"socket-file", MAX_LONG_OPT_SZ)) {
				if (us_vhost_parse_socket_path(optarg) == -1) {
					RTE_LOG(INFO, VHOST_CONFIG,
					"Invalid argument for socket name (Max %d characters)\n",
					PATH_MAX);
					us_vhost_usage(prgname);
					return -1;
				}
			}

			break;

			/* Invalid option - print options. */
		default:
			us_vhost_usage(prgname);
			return -1;
		}
	}

	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
		if (enabled_port_mask & (1 << i))
			ports[num_ports++] = (uint8_t)i;
	}

	if ((num_ports ==  0) || (num_ports > MAX_SUP_PORTS)) {
		RTE_LOG(INFO, VHOST_PORT, "Current enabled port number is %u,"
			"but only %u port can be enabled\n",num_ports, MAX_SUP_PORTS);
		return -1;
	}

	return 0;
}

/*
 * Update the global var NUM_PORTS and array PORTS according to system ports number
 * and return valid ports number
 */
static unsigned check_ports_num(unsigned nb_ports)
{
	unsigned valid_num_ports = num_ports;
	unsigned portid;

	if (num_ports > nb_ports) {
		RTE_LOG(INFO, VHOST_PORT, "\nSpecified port number(%u) exceeds total system port number(%u)\n",
			num_ports, nb_ports);
		num_ports = nb_ports;
	}

	for (portid = 0; portid < num_ports; portid ++) {
		if (ports[portid] >= nb_ports) {
			RTE_LOG(INFO, VHOST_PORT, "\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
				ports[portid], (nb_ports - 1));
			ports[portid] = INVALID_PORT_ID;
			valid_num_ports--;
		}
	}
	return valid_num_ports;
}

static inline struct vhost_dev *__attribute__((always_inline))
find_vhost_dev(struct ether_addr *mac)
{
	struct vhost_dev *vdev;

	TAILQ_FOREACH(vdev, &vhost_dev_list, global_vdev_entry) {
		if (vdev->ready == DEVICE_RX &&
		    is_same_ether_addr(mac, &vdev->mac_address))
			return vdev;
	}

	return NULL;
}

/*
 * This function learns the MAC address of the device and registers this along with a
 * vlan tag to a VMDQ.
 */
static int
link_vmdq(struct vhost_dev *vdev, struct rte_mbuf *m)
{
	struct ether_hdr *pkt_hdr;
	int i, ret;

	/* Learn MAC address of guest device from packet */
	pkt_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);

	if (find_vhost_dev(&pkt_hdr->s_addr)) {
		RTE_LOG(ERR, VHOST_DATA,
			"(%d) device is using a registered MAC!\n",
			vdev->vid);
		return -1;
	}

	for (i = 0; i < ETHER_ADDR_LEN; i++)
		vdev->mac_address.addr_bytes[i] = pkt_hdr->s_addr.addr_bytes[i];

	/* vlan_tag currently uses the device_id. */
	vdev->vlan_tag = vlan_tags[vdev->vid];

	/* Print out VMDQ registration info. */
	RTE_LOG(INFO, VHOST_DATA,
		"(%d) mac %02x:%02x:%02x:%02x:%02x:%02x and vlan %d registered\n",
		vdev->vid,
		vdev->mac_address.addr_bytes[0], vdev->mac_address.addr_bytes[1],
		vdev->mac_address.addr_bytes[2], vdev->mac_address.addr_bytes[3],
		vdev->mac_address.addr_bytes[4], vdev->mac_address.addr_bytes[5],
		vdev->vlan_tag);

	/* Register the MAC address. */
	ret = rte_eth_dev_mac_addr_add(ports[0], &vdev->mac_address,
				(uint32_t)vdev->vid + vmdq_pool_base);
	if (ret)
		RTE_LOG(ERR, VHOST_DATA,
			"(%d) failed to add device MAC address to VMDQ\n",
			vdev->vid);

	rte_eth_dev_set_vlan_strip_on_queue(ports[0], vdev->vmdq_rx_q, 1);

	/* Set device as ready for RX. */
	vdev->ready = DEVICE_RX;

	return 0;
}

/*
 * Removes MAC address and vlan tag from VMDQ. Ensures that nothing is adding buffers to the RX
 * queue before disabling RX on the device.
 */
static inline void
unlink_vmdq(struct vhost_dev *vdev)
{
	unsigned i = 0;
	unsigned rx_count;
	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];

	if (vdev->ready == DEVICE_RX) {
		/*clear MAC and VLAN settings*/
		rte_eth_dev_mac_addr_remove(ports[0], &vdev->mac_address);
		for (i = 0; i < 6; i++)
			vdev->mac_address.addr_bytes[i] = 0;

		vdev->vlan_tag = 0;

		/*Clear out the receive buffers*/
		rx_count = rte_eth_rx_burst(ports[0],
					(uint16_t)vdev->vmdq_rx_q, pkts_burst, MAX_PKT_BURST);

		while (rx_count) {
			for (i = 0; i < rx_count; i++)
				rte_pktmbuf_free(pkts_burst[i]);

			rx_count = rte_eth_rx_burst(ports[0],
					(uint16_t)vdev->vmdq_rx_q, pkts_burst, MAX_PKT_BURST);
		}

		vdev->ready = DEVICE_MAC_LEARNING;
	}
}

static inline void __attribute__((always_inline))
virtio_xmit(struct vhost_dev *dst_vdev, struct vhost_dev *src_vdev,
	    struct rte_mbuf *m)
{
	uint16_t ret;

	ret = rte_vhost_enqueue_burst(dst_vdev->vid, VIRTIO_RXQ, &m, 1);
	if (enable_stats) {
		rte_atomic64_inc(&dst_vdev->stats.rx_total_atomic);
		rte_atomic64_add(&dst_vdev->stats.rx_atomic, ret);
		src_vdev->stats.tx_total++;
		src_vdev->stats.tx += ret;
	}
}

/*
 * Check if the packet destination MAC address is for a local device. If so then put
 * the packet on that devices RX queue. If not then return.
 */
static inline int __attribute__((always_inline))
virtio_tx_local(struct vhost_dev *vdev, struct rte_mbuf *m)
{
	struct ether_hdr *pkt_hdr;
	struct vhost_dev *dst_vdev;

	pkt_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);

	dst_vdev = find_vhost_dev(&pkt_hdr->d_addr);
	if (!dst_vdev)
		return -1;

	if (vdev->vid == dst_vdev->vid) {
		RTE_LOG_DP(DEBUG, VHOST_DATA,
			"(%d) TX: src and dst MAC is same. Dropping packet.\n",
			vdev->vid);
		return 0;
	}

	RTE_LOG_DP(DEBUG, VHOST_DATA,
		"(%d) TX: MAC address is local\n", dst_vdev->vid);

	if (unlikely(dst_vdev->remove)) {
		RTE_LOG_DP(DEBUG, VHOST_DATA,
			"(%d) device is marked for removal\n", dst_vdev->vid);
		return 0;
	}

	virtio_xmit(dst_vdev, vdev, m);
	return 0;
}

/*
 * Check if the destination MAC of a packet is one local VM,
 * and get its vlan tag, and offset if it is.
 */
static inline int __attribute__((always_inline))
find_local_dest(struct vhost_dev *vdev, struct rte_mbuf *m,
	uint32_t *offset, uint16_t *vlan_tag)
{
	struct vhost_dev *dst_vdev;
	struct ether_hdr *pkt_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);

	dst_vdev = find_vhost_dev(&pkt_hdr->d_addr);
	if (!dst_vdev)
		return 0;

	if (vdev->vid == dst_vdev->vid) {
		RTE_LOG_DP(DEBUG, VHOST_DATA,
			"(%d) TX: src and dst MAC is same. Dropping packet.\n",
			vdev->vid);
		return -1;
	}

	/*
	 * HW vlan strip will reduce the packet length
	 * by minus length of vlan tag, so need restore
	 * the packet length by plus it.
	 */
	*offset  = VLAN_HLEN;
	*vlan_tag = vlan_tags[vdev->vid];

	RTE_LOG_DP(DEBUG, VHOST_DATA,
		"(%d) TX: pkt to local VM device id: (%d), vlan tag: %u.\n",
		vdev->vid, dst_vdev->vid, *vlan_tag);

	return 0;
}

static uint16_t
get_psd_sum(void *l3_hdr, uint64_t ol_flags)
{
	if (ol_flags & PKT_TX_IPV4)
		return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
	else /* assume ethertype == ETHER_TYPE_IPv6 */
		return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
}

static void virtio_tx_offload(struct rte_mbuf *m)
{
	void *l3_hdr;
	struct ipv4_hdr *ipv4_hdr = NULL;
	struct tcp_hdr *tcp_hdr = NULL;
	struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);

	l3_hdr = (char *)eth_hdr + m->l2_len;

	if (m->ol_flags & PKT_TX_IPV4) {
		ipv4_hdr = l3_hdr;
		ipv4_hdr->hdr_checksum = 0;
		m->ol_flags |= PKT_TX_IP_CKSUM;
	}

	tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + m->l3_len);
	tcp_hdr->cksum = get_psd_sum(l3_hdr, m->ol_flags);
}

static inline void
free_pkts(struct rte_mbuf **pkts, uint16_t n)
{
	while (n--)
		rte_pktmbuf_free(pkts[n]);
}

static inline void __attribute__((always_inline))
do_drain_mbuf_table(struct mbuf_table *tx_q)
{
	uint16_t count;

	count = rte_eth_tx_burst(ports[0], tx_q->txq_id,
				 tx_q->m_table, tx_q->len);
	if (unlikely(count < tx_q->len))
		free_pkts(&tx_q->m_table[count], tx_q->len - count);

	tx_q->len = 0;
}

/*
 * This function routes the TX packet to the correct interface. This
 * may be a local device or the physical port.
 */
static inline void __attribute__((always_inline))
virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m, uint16_t vlan_tag)
{
	struct mbuf_table *tx_q;
	unsigned offset = 0;
	const uint16_t lcore_id = rte_lcore_id();
	struct ether_hdr *nh;

	nh = rte_pktmbuf_mtod(m, struct ether_hdr *);
	if (unlikely(is_broadcast_ether_addr(&nh->d_addr))) {
		struct vhost_dev *vdev2;

		TAILQ_FOREACH(vdev2, &vhost_dev_list, global_vdev_entry) {
			virtio_xmit(vdev2, vdev, m);
		}
		goto queue2nic;
	}

	/*check if destination is local VM*/
	if ((vm2vm_mode == VM2VM_SOFTWARE) && (virtio_tx_local(vdev, m) == 0)) {
		rte_pktmbuf_free(m);
		return;
	}

	if (unlikely(vm2vm_mode == VM2VM_HARDWARE)) {
		if (unlikely(find_local_dest(vdev, m, &offset,
					     &vlan_tag) != 0)) {
			rte_pktmbuf_free(m);
			return;
		}
	}

	RTE_LOG_DP(DEBUG, VHOST_DATA,
		"(%d) TX: MAC address is external\n", vdev->vid);

queue2nic:

	/*Add packet to the port tx queue*/
	tx_q = &lcore_tx_queue[lcore_id];

	nh = rte_pktmbuf_mtod(m, struct ether_hdr *);
	if (unlikely(nh->ether_type == rte_cpu_to_be_16(ETHER_TYPE_VLAN))) {
		/* Guest has inserted the vlan tag. */
		struct vlan_hdr *vh = (struct vlan_hdr *) (nh + 1);
		uint16_t vlan_tag_be = rte_cpu_to_be_16(vlan_tag);
		if ((vm2vm_mode == VM2VM_HARDWARE) &&
			(vh->vlan_tci != vlan_tag_be))
			vh->vlan_tci = vlan_tag_be;
	} else {
		m->ol_flags |= PKT_TX_VLAN_PKT;

		/*
		 * Find the right seg to adjust the data len when offset is
		 * bigger than tail room size.
		 */
		if (unlikely(vm2vm_mode == VM2VM_HARDWARE)) {
			if (likely(offset <= rte_pktmbuf_tailroom(m)))
				m->data_len += offset;
			else {
				struct rte_mbuf *seg = m;

				while ((seg->next != NULL) &&
					(offset > rte_pktmbuf_tailroom(seg)))
					seg = seg->next;

				seg->data_len += offset;
			}
			m->pkt_len += offset;
		}

		m->vlan_tci = vlan_tag;
	}

	if (m->ol_flags & PKT_TX_TCP_SEG)
		virtio_tx_offload(m);

	tx_q->m_table[tx_q->len++] = m;
	if (enable_stats) {
		vdev->stats.tx_total++;
		vdev->stats.tx++;
	}

	if (unlikely(tx_q->len == MAX_PKT_BURST))
		do_drain_mbuf_table(tx_q);
}

static inline void __attribute__((always_inline))
drain_mbuf_table(struct mbuf_table *tx_q)
{
	static uint64_t prev_tsc;
	uint64_t cur_tsc;

	if (tx_q->len == 0)
		return;

	cur_tsc = rte_rdtsc();
	if (unlikely(cur_tsc - prev_tsc > MBUF_TABLE_DRAIN_TSC)) {
		prev_tsc = cur_tsc;

		RTE_LOG_DP(DEBUG, VHOST_DATA,
			"TX queue drained after timeout with burst size %u\n",
			tx_q->len);
		do_drain_mbuf_table(tx_q);
	}
}

static inline void __attribute__((always_inline))
drain_eth_rx(struct vhost_dev *vdev)
{
	uint16_t rx_count, enqueue_count;
	struct rte_mbuf *pkts[MAX_PKT_BURST];

	rx_count = rte_eth_rx_burst(ports[0], vdev->vmdq_rx_q,
				    pkts, MAX_PKT_BURST);
	if (!rx_count)
		return;

	/*
	 * When "enable_retry" is set, here we wait and retry when there
	 * is no enough free slots in the queue to hold @rx_count packets,
	 * to diminish packet loss.
	 */
	if (enable_retry &&
	    unlikely(rx_count > rte_vhost_avail_entries(vdev->vid,
			VIRTIO_RXQ))) {
		uint32_t retry;

		for (retry = 0; retry < burst_rx_retry_num; retry++) {
			rte_delay_us(burst_rx_delay_time);
			if (rx_count <= rte_vhost_avail_entries(vdev->vid,
					VIRTIO_RXQ))
				break;
		}
	}

	enqueue_count = rte_vhost_enqueue_burst(vdev->vid, VIRTIO_RXQ,
						pkts, rx_count);
	if (enable_stats) {
		rte_atomic64_add(&vdev->stats.rx_total_atomic, rx_count);
		rte_atomic64_add(&vdev->stats.rx_atomic, enqueue_count);
	}

	free_pkts(pkts, rx_count);
}

static inline void __attribute__((always_inline))
drain_virtio_tx(struct vhost_dev *vdev)
{
	struct rte_mbuf *pkts[MAX_PKT_BURST];
	uint16_t count;
	uint16_t i;

	count = rte_vhost_dequeue_burst(vdev->vid, VIRTIO_TXQ, mbuf_pool,
					pkts, MAX_PKT_BURST);

	/* setup VMDq for the first packet */
	if (unlikely(vdev->ready == DEVICE_MAC_LEARNING) && count) {
		if (vdev->remove || link_vmdq(vdev, pkts[0]) == -1)
			free_pkts(pkts, count);
	}

	for (i = 0; i < count; ++i)
		virtio_tx_route(vdev, pkts[i], vlan_tags[vdev->vid]);
}

/*
 * Main function of vhost-switch. It basically does:
 *
 * for each vhost device {
 *    - drain_eth_rx()
 *
 *      Which drains the host eth Rx queue linked to the vhost device,
 *      and deliver all of them to guest virito Rx ring associated with
 *      this vhost device.
 *
 *    - drain_virtio_tx()
 *
 *      Which drains the guest virtio Tx queue and deliver all of them
 *      to the target, which could be another vhost device, or the
 *      physical eth dev. The route is done in function "virtio_tx_route".
 * }
 */
static int
switch_worker(void *arg __rte_unused)
{
	unsigned i;
	unsigned lcore_id = rte_lcore_id();
	struct vhost_dev *vdev;
	struct mbuf_table *tx_q;

	RTE_LOG(INFO, VHOST_DATA, "Procesing on Core %u started\n", lcore_id);

	tx_q = &lcore_tx_queue[lcore_id];
	for (i = 0; i < rte_lcore_count(); i++) {
		if (lcore_ids[i] == lcore_id) {
			tx_q->txq_id = i;
			break;
		}
	}

	while(1) {
		drain_mbuf_table(tx_q);

		/*
		 * Inform the configuration core that we have exited the
		 * linked list and that no devices are in use if requested.
		 */
		if (lcore_info[lcore_id].dev_removal_flag == REQUEST_DEV_REMOVAL)
			lcore_info[lcore_id].dev_removal_flag = ACK_DEV_REMOVAL;

		/*
		 * Process vhost devices
		 */
		TAILQ_FOREACH(vdev, &lcore_info[lcore_id].vdev_list,
			      lcore_vdev_entry) {
			if (unlikely(vdev->remove)) {
				unlink_vmdq(vdev);
				vdev->ready = DEVICE_SAFE_REMOVE;
				continue;
			}

			if (likely(vdev->ready == DEVICE_RX))
				drain_eth_rx(vdev);

			if (likely(!vdev->remove))
				drain_virtio_tx(vdev);
		}
	}

	return 0;
}

/*
 * Remove a device from the specific data core linked list and from the
 * main linked list. Synchonization  occurs through the use of the
 * lcore dev_removal_flag. Device is made volatile here to avoid re-ordering
 * of dev->remove=1 which can cause an infinite loop in the rte_pause loop.
 */
static void
destroy_device(int vid)
{
	struct vhost_dev *vdev = NULL;
	int lcore;

	TAILQ_FOREACH(vdev, &vhost_dev_list, global_vdev_entry) {
		if (vdev->vid == vid)
			break;
	}
	if (!vdev)
		return;
	/*set the remove flag. */
	vdev->remove = 1;
	while(vdev->ready != DEVICE_SAFE_REMOVE) {
		rte_pause();
	}

	TAILQ_REMOVE(&lcore_info[vdev->coreid].vdev_list, vdev,
		     lcore_vdev_entry);
	TAILQ_REMOVE(&vhost_dev_list, vdev, global_vdev_entry);

	/* Set the dev_removal_flag on each lcore. */
	RTE_LCORE_FOREACH_SLAVE(lcore)
		lcore_info[lcore].dev_removal_flag = REQUEST_DEV_REMOVAL;

	/*
	 * Once each core has set the dev_removal_flag to ACK_DEV_REMOVAL
	 * we can be sure that they can no longer access the device removed
	 * from the linked lists and that the devices are no longer in use.
	 */
	RTE_LCORE_FOREACH_SLAVE(lcore) {
		while (lcore_info[lcore].dev_removal_flag != ACK_DEV_REMOVAL)
			rte_pause();
	}

	lcore_info[vdev->coreid].device_num--;

	RTE_LOG(INFO, VHOST_DATA,
		"(%d) device has been removed from data core\n",
		vdev->vid);

	rte_free(vdev);
}

/*
 * A new device is added to a data core. First the device is added to the main linked list
 * and the allocated to a specific data core.
 */
static int
new_device(int vid)
{
	int lcore, core_add = 0;
	uint32_t device_num_min = num_devices;
	struct vhost_dev *vdev;

	vdev = rte_zmalloc("vhost device", sizeof(*vdev), RTE_CACHE_LINE_SIZE);
	if (vdev == NULL) {
		RTE_LOG(INFO, VHOST_DATA,
			"(%d) couldn't allocate memory for vhost dev\n",
			vid);
		return -1;
	}
	vdev->vid = vid;

	TAILQ_INSERT_TAIL(&vhost_dev_list, vdev, global_vdev_entry);
	vdev->vmdq_rx_q = vid * queues_per_pool + vmdq_queue_base;

	/*reset ready flag*/
	vdev->ready = DEVICE_MAC_LEARNING;
	vdev->remove = 0;

	/* Find a suitable lcore to add the device. */
	RTE_LCORE_FOREACH_SLAVE(lcore) {
		if (lcore_info[lcore].device_num < device_num_min) {
			device_num_min = lcore_info[lcore].device_num;
			core_add = lcore;
		}
	}
	vdev->coreid = core_add;

	TAILQ_INSERT_TAIL(&lcore_info[vdev->coreid].vdev_list, vdev,
			  lcore_vdev_entry);
	lcore_info[vdev->coreid].device_num++;

	/* Disable notifications. */
	rte_vhost_enable_guest_notification(vid, VIRTIO_RXQ, 0);
	rte_vhost_enable_guest_notification(vid, VIRTIO_TXQ, 0);

	RTE_LOG(INFO, VHOST_DATA,
		"(%d) device has been added to data core %d\n",
		vid, vdev->coreid);

	return 0;
}

/*
 * These callback allow devices to be added to the data core when configuration
 * has been fully complete.
 */
static const struct virtio_net_device_ops virtio_net_device_ops =
{
	.new_device =  new_device,
	.destroy_device = destroy_device,
};

/*
 * This is a thread will wake up after a period to print stats if the user has
 * enabled them.
 */
static void
print_stats(void)
{
	struct vhost_dev *vdev;
	uint64_t tx_dropped, rx_dropped;
	uint64_t tx, tx_total, rx, rx_total;
	const char clr[] = { 27, '[', '2', 'J', '\0' };
	const char top_left[] = { 27, '[', '1', ';', '1', 'H','\0' };

	while(1) {
		sleep(enable_stats);

		/* Clear screen and move to top left */
		printf("%s%s\n", clr, top_left);
		printf("Device statistics =================================\n");

		TAILQ_FOREACH(vdev, &vhost_dev_list, global_vdev_entry) {
			tx_total   = vdev->stats.tx_total;
			tx         = vdev->stats.tx;
			tx_dropped = tx_total - tx;

			rx_total   = rte_atomic64_read(&vdev->stats.rx_total_atomic);
			rx         = rte_atomic64_read(&vdev->stats.rx_atomic);
			rx_dropped = rx_total - rx;

			printf("Statistics for device %d\n"
				"-----------------------\n"
				"TX total:              %" PRIu64 "\n"
				"TX dropped:            %" PRIu64 "\n"
				"TX successful:         %" PRIu64 "\n"
				"RX total:              %" PRIu64 "\n"
				"RX dropped:            %" PRIu64 "\n"
				"RX successful:         %" PRIu64 "\n",
				vdev->vid,
				tx_total, tx_dropped, tx,
				rx_total, rx_dropped, rx);
		}

		printf("===================================================\n");
	}
}

static void
unregister_drivers(int socket_num)
{
	int i, ret;

	for (i = 0; i < socket_num; i++) {
		ret = rte_vhost_driver_unregister(socket_files + i * PATH_MAX);
		if (ret != 0)
			RTE_LOG(ERR, VHOST_CONFIG,
				"Fail to unregister vhost driver for %s.\n",
				socket_files + i * PATH_MAX);
	}
}

/* When we receive a INT signal, unregister vhost driver */
static void
sigint_handler(__rte_unused int signum)
{
	/* Unregister vhost driver. */
	unregister_drivers(nb_sockets);

	exit(0);
}

/*
 * While creating an mbuf pool, one key thing is to figure out how
 * many mbuf entries is enough for our use. FYI, here are some
 * guidelines:
 *
 * - Each rx queue would reserve @nr_rx_desc mbufs at queue setup stage
 *
 * - For each switch core (A CPU core does the packet switch), we need
 *   also make some reservation for receiving the packets from virtio
 *   Tx queue. How many is enough depends on the usage. It's normally
 *   a simple calculation like following:
 *
 *       MAX_PKT_BURST * max packet size / mbuf size
 *
 *   So, we definitely need allocate more mbufs when TSO is enabled.
 *
 * - Similarly, for each switching core, we should serve @nr_rx_desc
 *   mbufs for receiving the packets from physical NIC device.
 *
 * - We also need make sure, for each switch core, we have allocated
 *   enough mbufs to fill up the mbuf cache.
 */
static void
create_mbuf_pool(uint16_t nr_port, uint32_t nr_switch_core, uint32_t mbuf_size,
	uint32_t nr_queues, uint32_t nr_rx_desc, uint32_t nr_mbuf_cache)
{
	uint32_t nr_mbufs;
	uint32_t nr_mbufs_per_core;
	uint32_t mtu = 1500;

	if (mergeable)
		mtu = 9000;
	if (enable_tso)
		mtu = 64 * 1024;

	nr_mbufs_per_core  = (mtu + mbuf_size) * MAX_PKT_BURST /
			(mbuf_size - RTE_PKTMBUF_HEADROOM);
	nr_mbufs_per_core += nr_rx_desc;
	nr_mbufs_per_core  = RTE_MAX(nr_mbufs_per_core, nr_mbuf_cache);

	nr_mbufs  = nr_queues * nr_rx_desc;
	nr_mbufs += nr_mbufs_per_core * nr_switch_core;
	nr_mbufs *= nr_port;

	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", nr_mbufs,
					    nr_mbuf_cache, 0, mbuf_size,
					    rte_socket_id());
	if (mbuf_pool == NULL)
		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
}

/*
 * Main function, does initialisation and calls the per-lcore functions.
 */
int
main(int argc, char *argv[])
{
	unsigned lcore_id, core_id = 0;
	unsigned nb_ports, valid_num_ports;
	int ret, i;
	uint8_t portid;
	static pthread_t tid;
	char thread_name[RTE_MAX_THREAD_NAME_LEN];
	uint64_t flags = 0;

	signal(SIGINT, sigint_handler);

	/* init EAL */
	ret = rte_eal_init(argc, argv);
	if (ret < 0)
		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
	argc -= ret;
	argv += ret;

	/* parse app arguments */
	ret = us_vhost_parse_args(argc, argv);
	if (ret < 0)
		rte_exit(EXIT_FAILURE, "Invalid argument\n");

	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
		TAILQ_INIT(&lcore_info[lcore_id].vdev_list);

		if (rte_lcore_is_enabled(lcore_id))
			lcore_ids[core_id++] = lcore_id;
	}

	if (rte_lcore_count() > RTE_MAX_LCORE)
		rte_exit(EXIT_FAILURE,"Not enough cores\n");

	/* Get the number of physical ports. */
	nb_ports = rte_eth_dev_count();

	/*
	 * Update the global var NUM_PORTS and global array PORTS
	 * and get value of var VALID_NUM_PORTS according to system ports number
	 */
	valid_num_ports = check_ports_num(nb_ports);

	if ((valid_num_ports ==  0) || (valid_num_ports > MAX_SUP_PORTS)) {
		RTE_LOG(INFO, VHOST_PORT, "Current enabled port number is %u,"
			"but only %u port can be enabled\n",num_ports, MAX_SUP_PORTS);
		return -1;
	}

	/*
	 * FIXME: here we are trying to allocate mbufs big enough for
	 * @MAX_QUEUES, but the truth is we're never going to use that
	 * many queues here. We probably should only do allocation for
	 * those queues we are going to use.
	 */
	create_mbuf_pool(valid_num_ports, rte_lcore_count() - 1, MBUF_DATA_SIZE,
			 MAX_QUEUES, RTE_TEST_RX_DESC_DEFAULT, MBUF_CACHE_SIZE);

	if (vm2vm_mode == VM2VM_HARDWARE) {
		/* Enable VT loop back to let L2 switch to do it. */
		vmdq_conf_default.rx_adv_conf.vmdq_rx_conf.enable_loop_back = 1;
		RTE_LOG(DEBUG, VHOST_CONFIG,
			"Enable loop back for L2 switch in vmdq.\n");
	}

	/* initialize all ports */
	for (portid = 0; portid < nb_ports; portid++) {
		/* skip ports that are not enabled */
		if ((enabled_port_mask & (1 << portid)) == 0) {
			RTE_LOG(INFO, VHOST_PORT,
				"Skipping disabled port %d\n", portid);
			continue;
		}
		if (port_init(portid) != 0)
			rte_exit(EXIT_FAILURE,
				"Cannot initialize network ports\n");
	}

	/* Enable stats if the user option is set. */
	if (enable_stats) {
		ret = pthread_create(&tid, NULL, (void *)print_stats, NULL);
		if (ret != 0)
			rte_exit(EXIT_FAILURE,
				"Cannot create print-stats thread\n");

		/* Set thread_name for aid in debugging.  */
		snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "print-stats");
		ret = rte_thread_setname(tid, thread_name);
		if (ret != 0)
			RTE_LOG(DEBUG, VHOST_CONFIG,
				"Cannot set print-stats name\n");
	}

	/* Launch all data cores. */
	RTE_LCORE_FOREACH_SLAVE(lcore_id)
		rte_eal_remote_launch(switch_worker, NULL, lcore_id);

	if (mergeable == 0)
		rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_MRG_RXBUF);

	if (client_mode)
		flags |= RTE_VHOST_USER_CLIENT;

	if (dequeue_zero_copy)
		flags |= RTE_VHOST_USER_DEQUEUE_ZERO_COPY;

	/* Register vhost user driver to handle vhost messages. */
	for (i = 0; i < nb_sockets; i++) {
		ret = rte_vhost_driver_register
				(socket_files + i * PATH_MAX, flags);
		if (ret != 0) {
			unregister_drivers(i);
			rte_exit(EXIT_FAILURE,
				"vhost driver register failure.\n");
		}
	}

	rte_vhost_driver_callback_register(&virtio_net_device_ops);

	rte_vhost_driver_session_start();
	return 0;

}


text:
title: 'JavaScript is relatable'
date: '2017-09-08'
layout: post
readNext: '/'
path: '/JS-is-relatable/'
meta: 'JavaScript is for the people because it is relatable and usable.'
post_index: 51
categories:
  - javascript
---

JavaScript fatigue real because **JavaScript is relatable**. That's why so much is happening with it! I remember this always. I hope others do too. JavaScript has become the most used programming language because it is relatable! It was written in a [week](https://www.w3.org/community/webed/wiki/A_Short_History_of_JavaScript) and delivered to a browser as a prototype. It is often looked down on. Despite its status, it is used everywhere for many different things. JavaScript is a programming language that can be understood in sentiment, starting out, and in very complex applications because it is relatable.

Image from boomsbeat—found by searching 'dogs looking into mirrors'

## JavaScript is scrappy

JavaScript is scrappy and it has been for most of its life span so far. It was a final piece of code to make that thing do that thing on a web page. It was the feeling of web pages. It was hacky. For that, logical thinking tended towards despised it and creative thinking tended towards fascination, 'How can this pile of legos became a castle?'.

#### JS write code in your chrome browser `console`

```javascript
// crack open your console (on a mac)
// cmd + opt + j
alert('You are writing JavaScript')
```

#### JS write a bookmarklet to do stuff in your chrome browser

```javascript
// open your bookmark manager (on a mac 💻)
// opt + cmd + b
// copy/paste the code snippet below into a new bookmark
javascript: alert('You are writing JavaScript')
// click the new bookmark on any page
```

## JavaScript has a low level of entry

JavaScript, when learning about computers goes right along with learning `HTML` and `CSS`. It can still be added right to web pages within a `<script>` tag. It is easy to read about all of the other things—tooling and frameworks and feel like those things need to create a valid web page, but they're not. This is such a cool thing. With just HTML, CSS, and JavaScript—which is what generally people view all computer information on inspiring technology can be made.

#### JS do some inline scripting stuff

```html
<body>
  <script>
    alert('You are writing JavaScript')
  </script>
</body>
```

## JavaScript is for anything

Now that JavaScript is established and something that is easy to get started with, why does the barrier to entry seem so high? JavaScript seems to have a high barrier to entry because of what people are doing with it currently. Currently, JavaScript is used for everything—even HTML and CSS. This means that when JavaScript is compiled into HTML and CSS. When JavaScript is used for everything, it is a lot more complex.

JavaScript has the ability to be used for everything does not mean that great things can't be built using JavaScript in a lot of different ways. This is a very important thing to note, understand and remember.

#### JS do some server stuff

```bash
# crack open a shell (on a mac )
# lines below assumes homebrew is not installed and neither is node
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" &&
brew install node

# make 'dat app
mkdir code/express-thing &&
cd code/express-thing &&
npm i express --save-dev &&
npm init -f &&
echo 'const express=require("express"),app=express();app.get("/",function(e,p){p.send("Hello World!")}),app.listen(3e3,function(){console.log("Example app listening on port 3000!")});' > app.js &&
node app.js
```

## There can be many types of JavaScript Experts

There can be many types of JavaScript Experts. This is not discussed a lot. Going through, [JavaScript30](https://javascript30.com/) recently, it became immediately clear that JavaScript's APIs are large and growing. Some people may deal with the [Adio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) every day and never think much about whole other areas of the language.

Other people may do amazing things with CSS-in-JS. Understanding the reflow of styling properties and the way CSS describes layouts is very important to the way a web page is perceived. Have a deep understanding of this can make a huge difference—especially with the simplest of interfaces.

There are many types of JavaScript Experts and many things to learn about within JavaScript because it is relatable. This is very important to understand when trying to understand engineering teams and application architecture generally.

## JavaScript is what it is because it is relatable

JavaScript can seem overwhelming because it has so many buckets and can teach so much. This bucketing is not _good emotional_, but JavaScript is relatable. Find a way to make JavaScript work for you and it will. Remember the way that it works for you and feel comfortable in that—to appreciate it, learn and teach.

redpajama_set_name: RedPajamaGithub


text:
from calvin.actor.actor import Actor, manage, condition, ActionResult
from calvin.runtime.north.calvin_token import EOSToken

class PrefixString(Actor):

    """
    Prepends <prefix> to input tokens and passes them to ouput port as strings
    Inputs:
      in : Text token
    Outputs:
      out : Prefixed text token
    """
    @manage(['prefix'])
    def init(self, prefix='-'):
        self.prefix = str(prefix)

    def exception_handler(self, action, args, exceptions):
        return ActionResult(tokens_consumed=1, tokens_produced=1, production=(EOSToken(), ))

    @condition(['in'], ['out'])
    def prefix(self, token):
        return ActionResult(tokens_produced=1, production=(self.prefix + str(token), ))

    action_priority = (prefix, )

    test_kwargs = {'prefix': 'P'}

    test_set = [
        {
            'in': {'in': ['a', 'b', 'c']},
            'out': {'out': ['Pa', 'Pb', 'Pc']}
        }
    ]


text:
package zipkin.storage.cassandra;

import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.List;
import zipkin.DependencyLink;
import zipkin.internal.Dependencies;
import zipkin.internal.Util;

final class CassandraDependenciesWriter {
  private final PreparedStatement insertDependencies;
  private final Session session;

  CassandraDependenciesWriter(Session session) {
    this.session = session;
    insertDependencies = session.prepare(QueryBuilder.insertInto("dependencies")
        .value("day", QueryBuilder.bindMarker("day"))
        .value("dependencies", QueryBuilder.bindMarker("dependencies")));
  }

  @VisibleForTesting void write(List<DependencyLink> links, long timestampMillis) {
    long midnight = Util.midnightUTC(timestampMillis);
    Dependencies deps = Dependencies.create(midnight, midnight /* ignored */, links);
    ByteBuffer thrift = deps.toThrift();
    Futures.getUnchecked(storeDependencies(midnight, thrift));
  }

  ListenableFuture<?> storeDependencies(long epochDayMillis, ByteBuffer dependencies) {
    Date startFlooredToDay = new Date(epochDayMillis);
    try {
      BoundStatement bound = CassandraUtil.bindWithName(insertDependencies, "insert-dependencies")
          .setTimestamp("day", startFlooredToDay)
          .setBytes("dependencies", dependencies);

      return session.executeAsync(bound);
    } catch (RuntimeException ex) {
      return Futures.immediateFailedFuture(ex);
    }
  }
}


text:
<?php
/**
 * @ingroup SMWDataValues
 */

/**
 * This datavalue implements Boolean datavalues.
 *
 * @author Markus Krötzsch
 * @ingroup SMWDataValues
 */
class SMWBoolValue extends SMWDataValue {

	/**
	 * The text to write for "true" if a custom output format was set.
	 * @var string
	 */
	protected $m_truecaption;

	/**
	 * The text to write for "false" if a custom output format was set.
	 * @var string
	 */
	protected $m_falsecaption;

	protected function parseUserValue( $value ) {
		$value = trim( $value );
		if ( $this->m_caption === false ) {
			$this->m_caption = $value;
		}

		$lcv = strtolower( $value );
		$boolvalue = false;
		if ( $lcv === '1' ) {
			$boolvalue = true;
		} elseif ( $lcv === '0' ) {
			$boolvalue = false;
		} elseif ( in_array( $lcv, explode( ',', wfMessage( 'smw_true_words' )->inContentLanguage()->text() ), true ) ) {
			$boolvalue = true;
		} elseif ( in_array( $lcv, explode( ',', wfMessage( 'smw_false_words' )->inContentLanguage()->text() ), true ) ) {
			$boolvalue = false;
		} else {
			$this->addError( wfMessage( 'smw_noboolean', $value )->inContentLanguage()->text() );
		}
		$this->m_dataitem = new SMWDIBoolean( $boolvalue, $this->m_typeid );
	}

	/**
	 * @see SMWDataValue::loadDataItem()
	 * @param $dataitem SMWDataItem
	 * @return boolean
	 */
	protected function loadDataItem( SMWDataItem $dataItem ) {
		if ( $dataItem->getDIType() == SMWDataItem::TYPE_BOOLEAN ) {
			$this->m_dataitem = $dataItem;
			$this->m_caption = $this->getStandardCaption( true ); // use default for this language
			return true;
		} else {
			return false;
		}
	}

	public function setOutputFormat( $formatstring ) {
		if ( $formatstring == $this->m_outformat ) {
			return;
		}
		unset( $this->m_truecaption );
		unset( $this->m_falsecaption );
		if ( $formatstring === '' ) { // no format
			// (unsetting the captions is exactly the right thing here)
		} elseif ( strtolower( $formatstring ) == '-' ) { // "plain" format
			$this->m_truecaption = 'true';
			$this->m_falsecaption = 'false';
		} elseif ( strtolower( $formatstring ) == 'x' ) { // X format
			$this->m_truecaption = 'X';
			$this->m_falsecaption = ' ';
		} else { // format "truelabel, falselabel" (hopefully)
			$captions = explode( ',', $formatstring, 2 );
			if ( count( $captions ) == 2 ) { // note: escaping needed to be safe; MW-sanitising would be an alternative
				$this->m_truecaption = htmlspecialchars( trim( $captions[0] ) );
				$this->m_falsecaption = htmlspecialchars( trim( $captions[1] ) );
			} // else: no format that is recognised, ignore
		}
		$this->m_caption = $this->getStandardCaption( true );
		$this->m_outformat = $formatstring;
	}

	public function getShortWikiText( $linked = null ) {
		return $this->m_caption;
	}

	public function getShortHTMLText( $linker = null ) {
		return $this->m_caption;
	}

	public function getLongWikiText( $linked = null ) {
		return $this->isValid() ? $this->getStandardCaption( true ) : $this->getErrorText();
	}

	public function getLongHTMLText( $linker = null ) {
		return $this->isValid() ? $this->getStandardCaption( true ) : $this->getErrorText();
	}

	public function getWikiValue() {
		return $this->getStandardCaption( false );
	}

	public function getBoolean() {
		return $this->m_dataitem->getBoolean();
	}

	/**
	 * Get text for displaying the value of this property, or false if not
	 * valid.
	 * @param $useformat bool, true if the output format should be used, false if the returned text should be parsable
	 * @return string
	 */
	protected function getStandardCaption( $useformat ) {
		if ( !$this->isValid() ) {
			return false;
		}
		if ( $useformat && ( isset( $this->m_truecaption ) ) ) {
			return $this->m_dataitem->getBoolean() ? $this->m_truecaption : $this->m_falsecaption;
		} else {
			$vals = explode(
				',',
				wfMessage(
					$this->m_dataitem->getBoolean() ? 'smw_true_words' : 'smw_false_words'
				)->inContentLanguage()->text()
			);
			return reset( $vals );
		}
	}
}


text:
<?php
/**
 * @author JKetelaar
 */

namespace Parabot\BDN\UserBundle\Repository;

use Doctrine\ORM\EntityRepository;
use Parabot\BDN\UserBundle\Entity\OAuth\Client;

class ClientRepository extends EntityRepository {

    /**
     * @param string[] $redirectUris
     *
     * @return bool
     */
    public function redirectUrisAvailable($redirectUris) {
        /**
         * @var $clientInstance Client
         */
        $clientRepository = $this->getEntityManager()->getRepository('BDNUserBundle:OAuth\\Client');

        foreach($clientRepository->findAll() as $clientInstance) {
            if(count(array_intersect($clientInstance->getRedirectUris(), $redirectUris)) > 0) {
                return false;
            }
        }

        return true;
    }

    public function isValidRedirectUri($uri) {
        /**
         * @var $clientInstance Client
         */
        $clientRepository = $this->getEntityManager()->getRepository('BDNUserBundle:OAuth\\Client');
        $uri              = parse_url($uri);

        foreach($clientRepository->findAll() as $clientInstance) {
            foreach($clientInstance->getRedirectUris() as $clientUri) {
                $clientUri = parse_url($clientUri);
                if($uri[ 'host' ] == $clientUri[ 'host' ]) {
                    return true;
                }
            }
        }

        return false;
    }

    public function getCurrentHost() {

    }
}


text:
#include "ctr_6002dr2_LogicDLL.h"

//(*InternalHeaders(pnlADF)
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/radiobox.h>
#include <wx/textctrl.h>
#include <wx/spinctrl.h>
#include <wx/intl.h>
#include <wx/button.h>
#include <wx/string.h>
#include <wx/combobox.h>
//*)

//(*IdInit(pnlADF)
const long pnlADF::ID_STATICTEXT1 = wxNewId();
const long pnlADF::ID_STATICTEXT2 = wxNewId();
const long pnlADF::ID_STATICTEXT3 = wxNewId();
const long pnlADF::ID_COMBOBOX1 = wxNewId();
const long pnlADF::ID_COMBOBOX2 = wxNewId();
const long pnlADF::ID_SPINCTRL1 = wxNewId();
const long pnlADF::ID_STATICTEXT4 = wxNewId();
const long pnlADF::ID_STATICTEXT5 = wxNewId();
const long pnlADF::ID_COMBOBOX3 = wxNewId();
const long pnlADF::ID_SPINCTRL2 = wxNewId();
const long pnlADF::ID_STATICTEXT6 = wxNewId();
const long pnlADF::ID_STATICTEXT7 = wxNewId();
const long pnlADF::ID_COMBOBOX4 = wxNewId();
const long pnlADF::ID_COMBOBOX5 = wxNewId();
const long pnlADF::ID_STATICTEXT8 = wxNewId();
const long pnlADF::ID_STATICTEXT9 = wxNewId();
const long pnlADF::ID_COMBOBOX6 = wxNewId();
const long pnlADF::ID_COMBOBOX7 = wxNewId();
const long pnlADF::ID_STATICTEXT10 = wxNewId();
const long pnlADF::ID_COMBOBOX8 = wxNewId();
const long pnlADF::ID_RADIOBOX1 = wxNewId();
const long pnlADF::ID_RADIOBOX2 = wxNewId();
const long pnlADF::ID_RADIOBOX3 = wxNewId();
const long pnlADF::ID_RADIOBOX4 = wxNewId();
const long pnlADF::ID_RADIOBOX5 = wxNewId();
const long pnlADF::ID_STATICTEXT17 = wxNewId();
const long pnlADF::ID_STATICTEXT18 = wxNewId();
const long pnlADF::ID_COMBOBOX9 = wxNewId();
const long pnlADF::ID_COMBOBOX10 = wxNewId();
const long pnlADF::ID_STATICTEXT19 = wxNewId();
const long pnlADF::ID_STATICTEXT20 = wxNewId();
const long pnlADF::ID_COMBOBOX11 = wxNewId();
const long pnlADF::ID_COMBOBOX12 = wxNewId();
const long pnlADF::ID_STATICTEXT21 = wxNewId();
const long pnlADF::ID_COMBOBOX13 = wxNewId();
const long pnlADF::ID_RADIOBOX6 = wxNewId();
const long pnlADF::ID_RADIOBOX7 = wxNewId();
const long pnlADF::ID_RADIOBOX8 = wxNewId();
const long pnlADF::ID_RADIOBOX9 = wxNewId();
const long pnlADF::ID_RADIOBOX10 = wxNewId();
const long pnlADF::ID_STATICTEXT11 = wxNewId();
const long pnlADF::ID_STATICTEXT12 = wxNewId();
const long pnlADF::ID_TEXTCTRL1 = wxNewId();
const long pnlADF::ID_TEXTCTRL2 = wxNewId();
const long pnlADF::ID_STATICTEXT13 = wxNewId();
const long pnlADF::ID_STATICTEXT14 = wxNewId();
const long pnlADF::ID_STATICTEXT15 = wxNewId();
const long pnlADF::ID_STATICTEXT16 = wxNewId();
const long pnlADF::ID_BUTTON1 = wxNewId();
//*)

BEGIN_EVENT_TABLE(pnlADF,wxPanel)
	//(*EventTable(pnlADF)
	//*)
END_EVENT_TABLE()

pnlADF::pnlADF(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size, int styles, wxString idname)
{
	BuildContent(parent,id,pos,size);
}

void pnlADF::BuildContent(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size)
{
	//(*Initialize(pnlADF)
	wxStaticBoxSizer* StaticBoxSizer2;
	wxFlexGridSizer* FlexGridSizer4;
	wxFlexGridSizer* FlexGridSizer16;
	wxStaticBoxSizer* StaticBoxSizer4;
	wxFlexGridSizer* FlexGridSizer10;
	wxFlexGridSizer* FlexGridSizer3;
	wxFlexGridSizer* FlexGridSizer5;
	wxFlexGridSizer* FlexGridSizer9;
	wxFlexGridSizer* FlexGridSizer2;
	wxFlexGridSizer* FlexGridSizer7;
	wxStaticBoxSizer* StaticBoxSizer3;
	wxStaticBoxSizer* StaticBoxSizer6;
	wxFlexGridSizer* FlexGridSizer15;
	wxFlexGridSizer* FlexGridSizer8;
	wxFlexGridSizer* FlexGridSizer14;
	wxFlexGridSizer* FlexGridSizer13;
	wxFlexGridSizer* FlexGridSizer12;
	wxFlexGridSizer* FlexGridSizer6;
	wxStaticBoxSizer* StaticBoxSizer1;
	wxFlexGridSizer* FlexGridSizer1;
	wxFlexGridSizer* FlexGridSizer11;
	wxStaticBoxSizer* StaticBoxSizer5;

	Create(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T("id"));
	FlexGridSizer1 = new wxFlexGridSizer(0, 2, 0, 0);
	StaticBoxSizer1 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("ADF4002"));
	FlexGridSizer3 = new wxFlexGridSizer(3, 1, 0, 0);
	FlexGridSizer4 = new wxFlexGridSizer(0, 2, 0, 5);
	FlexGridSizer4->AddGrowableCol(0);
	StaticBoxSizer2 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reference Counter Latch"));
	FlexGridSizer5 = new wxFlexGridSizer(2, 3, 0, 5);
	FlexGridSizer5->AddGrowableCol(0);
	FlexGridSizer5->AddGrowableCol(1);
	FlexGridSizer5->AddGrowableCol(2);
	StaticText1 = new wxStaticText(this, ID_STATICTEXT1, _("Lock Detect Precision:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
	FlexGridSizer5->Add(StaticText1, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText2 = new wxStaticText(this, ID_STATICTEXT2, _("Anti-Backlash:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT2"));
	FlexGridSizer5->Add(StaticText2, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText3 = new wxStaticText(this, ID_STATICTEXT3, _("Reference Counter:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3"));
	FlexGridSizer5->Add(StaticText3, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbLDP = new wxComboBox(this, ID_COMBOBOX1, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX1"));
	cmbLDP->SetSelection( cmbLDP->Append(_("Three Cycles")) );
	cmbLDP->Append(_("Five Cycles"));
	FlexGridSizer5->Add(cmbLDP, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	cmbABW = new wxComboBox(this, ID_COMBOBOX2, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX2"));
	cmbABW->SetSelection( cmbABW->Append(_("2.9ns")) );
	cmbABW->Append(_("6.0ns"));
	cmbABW->Append(_("2.9ns"));
	FlexGridSizer5->Add(cmbABW, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	spinRCnt = new wxSpinCtrl(this, ID_SPINCTRL1, _T("125"), wxDefaultPosition, wxDefaultSize, 0, 0, 1000000000, 125, _T("ID_SPINCTRL1"));
	spinRCnt->SetValue(_T("125"));
	spinRCnt->Disable();
	FlexGridSizer5->Add(spinRCnt, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer2->Add(FlexGridSizer5, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer4->Add(StaticBoxSizer2, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer4 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("N Counter Latch"));
	FlexGridSizer6 = new wxFlexGridSizer(2, 2, 0, 5);
	FlexGridSizer6->AddGrowableCol(0);
	FlexGridSizer6->AddGrowableCol(1);
	StaticText4 = new wxStaticText(this, ID_STATICTEXT4, _("CP Gain:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT4"));
	FlexGridSizer6->Add(StaticText4, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText5 = new wxStaticText(this, ID_STATICTEXT5, _("N Counter:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT5"));
	FlexGridSizer6->Add(StaticText5, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbCPG = new wxComboBox(this, ID_COMBOBOX3, wxEmptyString, wxDefaultPosition, wxSize(65,21), 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX3"));
	cmbCPG->SetSelection( cmbCPG->Append(_("0")) );
	cmbCPG->Append(_("1"));
	FlexGridSizer6->Add(cmbCPG, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	spinNCnt = new wxSpinCtrl(this, ID_SPINCTRL2, _T("384"), wxDefaultPosition, wxSize(70,21), 0, 0, 1000000000, 384, _T("ID_SPINCTRL2"));
	spinNCnt->SetValue(_T("384"));
	spinNCnt->Disable();
	FlexGridSizer6->Add(spinNCnt, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer4->Add(FlexGridSizer6, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer4->Add(StaticBoxSizer4, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer3->Add(FlexGridSizer4, 1, wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
	StaticBoxSizer3 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Function Latch"));
	FlexGridSizer7 = new wxFlexGridSizer(0, 3, 0, 5);
	FlexGridSizer8 = new wxFlexGridSizer(4, 2, 0, 5);
	StaticText6 = new wxStaticText(this, ID_STATICTEXT6, _("Current Setting 1:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT6"));
	FlexGridSizer8->Add(StaticText6, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText7 = new wxStaticText(this, ID_STATICTEXT7, _("Timer Counter:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT7"));
	FlexGridSizer8->Add(StaticText7, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbCS1_f = new wxComboBox(this, ID_COMBOBOX4, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX4"));
	cmbCS1_f->Append(_("0"));
	cmbCS1_f->Append(_("1"));
	cmbCS1_f->Append(_("2"));
	cmbCS1_f->Append(_("3"));
	cmbCS1_f->Append(_("4"));
	cmbCS1_f->Append(_("5"));
	cmbCS1_f->Append(_("6"));
	cmbCS1_f->SetSelection( cmbCS1_f->Append(_("7")) );
	FlexGridSizer8->Add(cmbCS1_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	cmbTC_f = new wxComboBox(this, ID_COMBOBOX5, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX5"));
	cmbTC_f->SetSelection( cmbTC_f->Append(_("3")) );
	cmbTC_f->Append(_("7"));
	cmbTC_f->Append(_("11"));
	cmbTC_f->Append(_("15"));
	cmbTC_f->Append(_("19"));
	cmbTC_f->Append(_("23"));
	cmbTC_f->Append(_("27"));
	cmbTC_f->Append(_("31"));
	cmbTC_f->Append(_("35"));
	cmbTC_f->Append(_("39"));
	cmbTC_f->Append(_("43"));
	cmbTC_f->Append(_("47"));
	cmbTC_f->Append(_("51"));
	cmbTC_f->Append(_("55"));
	cmbTC_f->Append(_("59"));
	cmbTC_f->Append(_("63"));
	FlexGridSizer8->Add(cmbTC_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticText8 = new wxStaticText(this, ID_STATICTEXT8, _("Current Setting 2:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT8"));
	FlexGridSizer8->Add(StaticText8, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText9 = new wxStaticText(this, ID_STATICTEXT9, _("Fastlock:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT9"));
	FlexGridSizer8->Add(StaticText9, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbCS2_f = new wxComboBox(this, ID_COMBOBOX6, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX6"));
	cmbCS2_f->Append(_("0"));
	cmbCS2_f->Append(_("1"));
	cmbCS2_f->Append(_("2"));
	cmbCS2_f->Append(_("3"));
	cmbCS2_f->Append(_("4"));
	cmbCS2_f->Append(_("5"));
	cmbCS2_f->Append(_("6"));
	cmbCS2_f->SetSelection( cmbCS2_f->Append(_("7")) );
	FlexGridSizer8->Add(cmbCS2_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	cmbFL_f = new wxComboBox(this, ID_COMBOBOX7, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX7"));
	cmbFL_f->SetSelection( cmbFL_f->Append(_("Disabled")) );
	cmbFL_f->Append(_("Mode 1"));
	cmbFL_f->Append(_("Mode 2"));
	FlexGridSizer8->Add(cmbFL_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer7->Add(FlexGridSizer8, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer9 = new wxFlexGridSizer(3, 1, 0, 0);
	StaticText10 = new wxStaticText(this, ID_STATICTEXT10, _("Muxout Control"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT10"));
	FlexGridSizer9->Add(StaticText10, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbMOC_f = new wxComboBox(this, ID_COMBOBOX8, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX8"));
	cmbMOC_f->Append(_("Three-State Output"));
	cmbMOC_f->SetSelection( cmbMOC_f->Append(_("Digital Lock Detect")) );
	cmbMOC_f->Append(_("N Divider Output"));
	cmbMOC_f->Append(_("DVdd"));
	cmbMOC_f->Append(_("R Divider Output"));
	cmbMOC_f->Append(_("N-Chan OD Lock Detect"));
	cmbMOC_f->Append(_("Serial Data Output"));
	cmbMOC_f->Append(_("DGND"));
	FlexGridSizer9->Add(cmbMOC_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_1[2] =
	{
		_("Negative"),
		_("Positive")
	};
	rgrPDP_f = new wxRadioBox(this, ID_RADIOBOX1, _("PD Polarity"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_1, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX1"));
	rgrPDP_f->SetSelection(1);
	FlexGridSizer9->Add(rgrPDP_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer7->Add(FlexGridSizer9, 1, wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	FlexGridSizer10 = new wxFlexGridSizer(2, 2, 0, 5);
	wxString __wxRadioBoxChoices_2[2] =
	{
		_("0"),
		_("1")
	};
	rgrPD1_f = new wxRadioBox(this, ID_RADIOBOX2, _("PD1"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_2, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX2"));
	rgrPD1_f->SetSelection(0);
	FlexGridSizer10->Add(rgrPD1_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_3[2] =
	{
		_("Normal"),
		_("R & N Reset")
	};
	rgrCR_f = new wxRadioBox(this, ID_RADIOBOX3, _("Counter Reset"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_3, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX3"));
	rgrCR_f->SetSelection(0);
	FlexGridSizer10->Add(rgrCR_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_4[2] =
	{
		_("0"),
		_("1")
	};
	rgrPD2_f = new wxRadioBox(this, ID_RADIOBOX4, _("PD2"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_4, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX4"));
	rgrPD2_f->SetSelection(0);
	FlexGridSizer10->Add(rgrPD2_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_5[2] =
	{
		_("Normal"),
		_("Three-State")
	};
	rgrCPS_f = new wxRadioBox(this, ID_RADIOBOX5, _("CP State"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_5, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX5"));
	rgrCPS_f->SetSelection(0);
	FlexGridSizer10->Add(rgrCPS_f, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer7->Add(FlexGridSizer10, 1, wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	StaticBoxSizer3->Add(FlexGridSizer7, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer3->Add(StaticBoxSizer3, 1, wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
	StaticBoxSizer5 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Initialization Latch"));
	FlexGridSizer13 = new wxFlexGridSizer(0, 3, 0, 5);
	FlexGridSizer14 = new wxFlexGridSizer(4, 2, 0, 5);
	StaticText14 = new wxStaticText(this, ID_STATICTEXT17, _("Current Setting 1:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT17"));
	FlexGridSizer14->Add(StaticText14, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText16 = new wxStaticText(this, ID_STATICTEXT18, _("Timer Counter:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT18"));
	FlexGridSizer14->Add(StaticText16, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbCS1_i = new wxComboBox(this, ID_COMBOBOX9, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX9"));
	cmbCS1_i->Append(_("0"));
	cmbCS1_i->Append(_("1"));
	cmbCS1_i->Append(_("2"));
	cmbCS1_i->Append(_("3"));
	cmbCS1_i->Append(_("4"));
	cmbCS1_i->Append(_("5"));
	cmbCS1_i->Append(_("6"));
	cmbCS1_i->SetSelection( cmbCS1_i->Append(_("7")) );
	FlexGridSizer14->Add(cmbCS1_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	cmbTC_i = new wxComboBox(this, ID_COMBOBOX10, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX10"));
	cmbTC_i->SetSelection( cmbTC_i->Append(_("3")) );
	cmbTC_i->Append(_("7"));
	cmbTC_i->Append(_("11"));
	cmbTC_i->Append(_("15"));
	cmbTC_i->Append(_("19"));
	cmbTC_i->Append(_("23"));
	cmbTC_i->Append(_("27"));
	cmbTC_i->Append(_("31"));
	cmbTC_i->Append(_("35"));
	cmbTC_i->Append(_("39"));
	cmbTC_i->Append(_("43"));
	cmbTC_i->Append(_("47"));
	cmbTC_i->Append(_("51"));
	cmbTC_i->Append(_("55"));
	cmbTC_i->Append(_("59"));
	cmbTC_i->Append(_("63"));
	FlexGridSizer14->Add(cmbTC_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticText17 = new wxStaticText(this, ID_STATICTEXT19, _("Current Setting 2:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT19"));
	FlexGridSizer14->Add(StaticText17, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText18 = new wxStaticText(this, ID_STATICTEXT20, _("Fastlock:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT20"));
	FlexGridSizer14->Add(StaticText18, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbCS2_i = new wxComboBox(this, ID_COMBOBOX11, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX11"));
	cmbCS2_i->Append(_("0"));
	cmbCS2_i->Append(_("1"));
	cmbCS2_i->Append(_("2"));
	cmbCS2_i->Append(_("3"));
	cmbCS2_i->Append(_("4"));
	cmbCS2_i->Append(_("5"));
	cmbCS2_i->Append(_("6"));
	cmbCS2_i->SetSelection( cmbCS2_i->Append(_("7")) );
	FlexGridSizer14->Add(cmbCS2_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	cmbFL_i = new wxComboBox(this, ID_COMBOBOX12, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX12"));
	cmbFL_i->SetSelection( cmbFL_i->Append(_("Disabled")) );
	cmbFL_i->Append(_("Mode 1"));
	cmbFL_i->Append(_("Mode 2"));
	FlexGridSizer14->Add(cmbFL_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer13->Add(FlexGridSizer14, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer15 = new wxFlexGridSizer(3, 1, 0, 0);
	StaticText19 = new wxStaticText(this, ID_STATICTEXT21, _("Muxout Control"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT21"));
	FlexGridSizer15->Add(StaticText19, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	cmbMOC_i = new wxComboBox(this, ID_COMBOBOX13, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMBOBOX13"));
	cmbMOC_i->Append(_("Three-State Output"));
	cmbMOC_i->SetSelection( cmbMOC_i->Append(_("Digital Lock Detect")) );
	cmbMOC_i->Append(_("N Divider Output"));
	cmbMOC_i->Append(_("DVdd"));
	cmbMOC_i->Append(_("R Divider Output"));
	cmbMOC_i->Append(_("N-Chan OD Lock Detect"));
	cmbMOC_i->Append(_("Serial Data Output"));
	cmbMOC_i->Append(_("DGND"));
	FlexGridSizer15->Add(cmbMOC_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_6[2] =
	{
		_("Negative"),
		_("Positive")
	};
	rgrPDP_i = new wxRadioBox(this, ID_RADIOBOX6, _("PD Polarity"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_6, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX6"));
	rgrPDP_i->SetSelection(0);
	FlexGridSizer15->Add(rgrPDP_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer13->Add(FlexGridSizer15, 1, wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	FlexGridSizer16 = new wxFlexGridSizer(2, 2, 0, 5);
	wxString __wxRadioBoxChoices_7[2] =
	{
		_("0"),
		_("1")
	};
	rgrPD1_i = new wxRadioBox(this, ID_RADIOBOX7, _("PD1"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_7, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX7"));
	rgrPD1_i->SetSelection(0);
	FlexGridSizer16->Add(rgrPD1_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_8[2] =
	{
		_("Normal"),
		_("R & N Reset")
	};
	rgrCR_i = new wxRadioBox(this, ID_RADIOBOX8, _("Counter Reset"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_8, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX8"));
	rgrCR_i->SetSelection(0);
	FlexGridSizer16->Add(rgrCR_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_9[2] =
	{
		_("0"),
		_("1")
	};
	rgrPD2_i = new wxRadioBox(this, ID_RADIOBOX9, _("PD2"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_9, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX9"));
	rgrPD2_i->SetSelection(0);
	FlexGridSizer16->Add(rgrPD2_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	wxString __wxRadioBoxChoices_10[2] =
	{
		_("Normal"),
		_("Three-State")
	};
	rgrCPS_i = new wxRadioBox(this, ID_RADIOBOX10, _("CP State"), wxDefaultPosition, wxDefaultSize, 2, __wxRadioBoxChoices_10, 1, wxRA_SPECIFY_COLS, wxDefaultValidator, _T("ID_RADIOBOX10"));
	rgrCPS_i->SetSelection(0);
	FlexGridSizer16->Add(rgrCPS_i, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer13->Add(FlexGridSizer16, 1, wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	StaticBoxSizer5->Add(FlexGridSizer13, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer3->Add(StaticBoxSizer5, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer1->Add(FlexGridSizer3, 1, wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
	FlexGridSizer1->Add(StaticBoxSizer1, 1, wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
	FlexGridSizer2 = new wxFlexGridSizer(0, 3, 0, 0);
	StaticBoxSizer6 = new wxStaticBoxSizer(wxVERTICAL, this, _("Calculation of R & N"));
	FlexGridSizer12 = new wxFlexGridSizer(2, 1, 0, 0);
	FlexGridSizer11 = new wxFlexGridSizer(4, 2, 0, 5);
	StaticText11 = new wxStaticText(this, ID_STATICTEXT11, _("Fref, MHz"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT11"));
	FlexGridSizer11->Add(StaticText11, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText12 = new wxStaticText(this, ID_STATICTEXT12, _("Fvco, MHz:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT12"));
	FlexGridSizer11->Add(StaticText12, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	txtFref = new wxTextCtrl(this, ID_TEXTCTRL1, _("10"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TEXTCTRL1"));
	FlexGridSizer11->Add(txtFref, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	txtFvco = new wxTextCtrl(this, ID_TEXTCTRL2, _("30.72"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TEXTCTRL2"));
	FlexGridSizer11->Add(txtFvco, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticText13 = new wxStaticText(this, ID_STATICTEXT13, _("Fvco (MHz) ="), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT13"));
	FlexGridSizer11->Add(StaticText13, 1, wxTOP|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
	lblFvco = new wxStaticText(this, ID_STATICTEXT14, _("Fvco"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT14"));
	FlexGridSizer11->Add(lblFvco, 1, wxTOP|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	StaticText15 = new wxStaticText(this, ID_STATICTEXT15, _("LCM ="), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT15"));
	FlexGridSizer11->Add(StaticText15, 1, wxTOP|wxBOTTOM|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
	lblFcomp = new wxStaticText(this, ID_STATICTEXT16, _("Fcomp"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT16"));
	FlexGridSizer11->Add(lblFcomp, 1, wxTOP|wxBOTTOM|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer12->Add(FlexGridSizer11, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	btnCalcSend = new wxButton(this, ID_BUTTON1, _("Calculate R, N & Download"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
	FlexGridSizer12->Add(btnCalcSend, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer6->Add(FlexGridSizer12, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
	FlexGridSizer2->Add(StaticBoxSizer6, 1, wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	FlexGridSizer1->Add(FlexGridSizer2, 1, wxLEFT|wxEXPAND|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
	SetSizer(FlexGridSizer1);
	FlexGridSizer1->Fit(this);
	FlexGridSizer1->SetSizeHints(this);

	Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&pnlADF::OnbtnCalcSendClick);
	//*)
}

pnlADF::~pnlADF()
{
	//(*Destroy(pnlADF)
	//*)
}

void pnlADF::SetGuiDefaults()
{
    //Reference Counter Latch
    cmbLDP->SetSelection(0);
    cmbABW->SetSelection(0);
    spinRCnt->SetValue(125);

    //N Counter Latch
    cmbCPG->SetSelection(0);
    spinNCnt->SetValue(384);

    //Function Latch
    rgrPD2_f->SetSelection(0);
    cmbCS2_f->SetSelection(7);
    cmbCS1_f->SetSelection(7);
    cmbTC_f->SetSelection(0);
    cmbFL_f->SetSelection(0);
    rgrCPS_f->SetSelection(0);
    rgrPDP_f->SetSelection(1);
    cmbMOC_f->SetSelection(1);
    rgrPD1_f->SetSelection(0);
    rgrCR_f->SetSelection(0);

    //Initialization Latch
    rgrPD2_i->SetSelection(0);
    cmbCS2_i->SetSelection(7);
    cmbCS1_i->SetSelection(7);
    cmbTC_i->SetSelection(0);
    cmbFL_i->SetSelection(0);
    rgrCPS_i->SetSelection(0);
    rgrPDP_i->SetSelection(1);
    cmbMOC_i->SetSelection(1);
    rgrPD1_i->SetSelection(0);
    rgrCR_i->SetSelection(0);
}

void pnlADF::OnbtnCalcSendClick(wxCommandEvent& event)
{
    //reference counter latch
    int ldp = cmbLDP->GetSelection();
    int abw = cmbABW->GetSelection();
    int rCount = spinRCnt->GetValue();
    LMLL_ADF_SetReferenceCounterLatch(ldp, abw, rCount);

    //n counter latch
    int cpGain = cmbCPG->GetSelection();
    int nCounter = spinNCnt->GetValue();
    LMLL_ADF_SetNCounterLatch(cpGain, nCounter);

    //function latch
    int currSetting1 = cmbCS1_f->GetSelection();
    int currSetting2 = cmbCS2_f->GetSelection();
    int tCounter = cmbTC_f->GetSelection();
    int fastLock = cmbFL_f->GetSelection();
    int muxControl = cmbMOC_f->GetSelection();

    int pdPol = rgrPDP_f->GetSelection();
    int pd1 = rgrPD1_f->GetSelection();
    int pd2 = rgrPD2_f->GetSelection();
    int counterReset = rgrCR_f->GetSelection();
    int cpState = rgrCPS_f->GetSelection();
    LMLL_ADF_SetFunctionLatch(currSetting1, currSetting2, tCounter, fastLock, muxControl);
    LMLL_ADF_SetFunctionLatchRgr(pdPol, pd1,pd2, counterReset, cpState);

    //Initialization latch
    currSetting1 = cmbCS1_i->GetSelection();
    currSetting2 = cmbCS2_i->GetSelection();
    tCounter = cmbTC_i->GetSelection();
    fastLock = cmbFL_i->GetSelection();
    muxControl = cmbMOC_i->GetSelection();

    pdPol = rgrPDP_i->GetSelection();
    pd1 = rgrPD1_i->GetSelection();
    pd2 = rgrPD2_i->GetSelection();
    counterReset = rgrCR_i->GetSelection();
    cpState = rgrCPS_i->GetSelection();
    LMLL_ADF_SetInitializationLatch(currSetting1, currSetting2, tCounter, fastLock, muxControl);
    LMLL_ADF_SetInitializationLatchRgr(pdPol, pd1,pd2, counterReset, cpState);

    double fref = 0;
    txtFref->GetValue().ToDouble(&fref);
    double fvco = 0;
    txtFvco->GetValue().ToDouble(&fvco);
    LMLL_ADF_SetFrefFvco(fref, fvco, rCount, nCounter);
    spinNCnt->SetValue(nCounter);
    spinRCnt->SetValue(rCount);
    LMLL_ADF_SendConfig();
}


text:
package com.vaadin.tests.components.absolutelayout;

import com.vaadin.server.ThemeResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

public class AbsoluteLayoutHideComponent extends AbstractTestUI {

    private AbsoluteLayout mainLayout;
    private VerticalLayout topBar = new VerticalLayout();
    private GridLayout menu;
    private TextField editEmail = new TextField();
    private PasswordField editPassword = new PasswordField();

    @Override
    protected void setup(VaadinRequest request) {
        mainLayout = new AbsoluteLayout();
        mainLayout.setImmediate(true);
        mainLayout.setWidth("100%");
        mainLayout.setHeight("100%");

        topBar.setHeight("50px");
        topBar.setWidth("100%");

        HorizontalLayout layoutLogin = new HorizontalLayout();
        layoutLogin.setSpacing(true);
        layoutLogin.setHeight("100%");

        Label label_eMail = new Label("e-Mail:");
        layoutLogin.addComponent(label_eMail);
        editEmail.setWidth("200px");
        editEmail.setTabIndex(1);
        layoutLogin.addComponent(editEmail);
        layoutLogin.addComponent(new Label(" "));

        layoutLogin.addComponent(new Label(" "));
        Label label_password = new Label("password:");
        layoutLogin.addComponent(label_password);
        editPassword.setWidth("100px");
        editPassword.setTabIndex(2);
        layoutLogin.addComponent(editPassword);
        layoutLogin.addComponent(new Label(" "));

        // btnLogin
        Button btnLogin = new Button();
        btnLogin.setCaption("Login");
        btnLogin.setImmediate(false);
        btnLogin.setWidth("-1px");
        btnLogin.setHeight("-1px");
        btnLogin.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                login();
            }
        });
        layoutLogin.addComponent(btnLogin);

        for (int index = 0; index < layoutLogin.getComponentCount(); index++) {
            layoutLogin.setComponentAlignment(layoutLogin.getComponent(index),
                    Alignment.MIDDLE_CENTER);
        }

        // =====> THIS CODE generates error
        // WITHOUT THIS CODE works fine

        Embedded e = new Embedded("", new ThemeResource(
                "../runo/icons/64/ok.png"));
        // e.setMimeType("image/jpg");
        e.setWidth("100%");
        e.setHeight("100%");
        mainLayout.addComponent(e);

        // =======

        topBar.addComponent(layoutLogin);
        mainLayout.addComponent(topBar, "left:0px;top:0px;");

        menu = buildMenu();
        menu.setVisible(false);
        mainLayout.addComponent(menu, "left:20px;top:70px;");

        setContent(mainLayout);
    }

    private GridLayout buildMenu() {
        GridLayout gridButtons = new GridLayout(2, 3);

        Button btn1 = new Button("Button one");
        btn1.setImmediate(true);
        btn1.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
            }
        });
        gridButtons.addComponent(btn1, 0, 0);

        Button btn2 = new Button("Button two");
        btn2.setImmediate(true);
        btn2.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
            }
        });
        gridButtons.addComponent(btn2, 0, 1);

        Button btn3 = new Button("Button three");
        btn3.setImmediate(true);
        btn3.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
            }
        });
        gridButtons.addComponent(btn3, 1, 0);

        return gridButtons;
    }

    private void login() {
        menu.setVisible(true);
        topBar.setVisible(false);
    }

    @Override
    protected String getTestDescription() {
        return "Clicking on the button should hide the fields and the button but leave the image";
    }

    @Override
    protected Integer getTicketNumber() {
        return 10155;
    }

}


text:
CREATE PROCEDURE [dbo].[User_Create]
	@name nvarchar(64),
	@email nvarchar(64),
	@password nvarchar(255),
	@photo bit = 0,
	@usertype smallint = 0
AS
	DECLARE @id int = NEXT VALUE FOR SequenceUsers
	INSERT INTO Users (userId, usertype, [name], email, [password], photo, datecreated)
	VALUES (@id, @Usertype, @name, @email, @password, @photo, GETDATE())

	SELECT @id


text:
layout: post
microblog: true
audio:
photo:
date: 2010-06-10 18:00:00 -0600
guid: http://craigmcclellan.micro.blog/2010/06/11/t15904782400.html
---
Man, @broken_bells were amazing live, and Centerstage Atlanta is a great venue. Thanks @laurakfagan for surprising me with the tickets!


text:
package org.escalate42.javaz.common.applicative;

import org.escalate42.javaz.common.function.Function;
import org.escalate42.javaz.common.functor.Functor;

/**
 * Created by vdubs
 * on 8/21/14.
 */
public interface Applicative<T, M extends Applicative<?, M>> extends Functor<T, M> {
    <U, MM extends Applicative<Function<T, U>, M>> M amap(MM applicativeFunction);
}


text:
layout: default
---

  {% for post in paginator.posts %}

        {{ post.title }}

    {{ post.date | date_to_string }}

    {{ post.excerpt }}

  {% endfor %}

  {% if paginator.next_page %}
    Older
  {% else %}
    Older
  {% endif %}
  {% if paginator.previous_page %}
    {% if paginator.page == 2 %}
      Newer
    {% else %}
      Newer
    {% endif %}
  {% else %}
    Newer
  {% endif %}


text:
'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	Schema = mongoose.Schema;

/**
 * Giftcard Schema
 */
var GiftcardSchema = new Schema({
	name: {
		type: String,
		default: '',
		required: 'Please fill Giftcard name',
		trim: true
	},
	created: {
		type: Date,
		default: Date.now
	},
	user: {
		type: Schema.ObjectId,
		ref: 'User'
	}
});

mongoose.model('Giftcard', GiftcardSchema);

var operationMap = {
	getAll: require('./operations/giftcard/getAll'),
	getGiftcard: require('./operations/giftcard/getGiftcard')
};
exports.operationMap = operationMap;


text:
package action

import (
	"fmt"
	"github.com/eriklupander/gotling/internal/pkg/result"
	"time"
)

type SleepAction struct {
	Duration time.Duration `yaml:"duration"`
}

func (s SleepAction) Execute(resultsChannel chan result.HttpReqResult, sessionMap map[string]string) {
	time.Sleep(s.Duration)
}

func NewSleepAction(a map[interface{}]interface{}) SleepAction {
	switch val := a["duration"].(type) {
	case int:
		return SleepAction{Duration: time.Second * time.Duration(val)}
	case string:
		dur, err := time.ParseDuration(val)
		if err != nil {
			fmt.Printf("Error trying to parse duration '%v' from string representation into Go duration format. Error: %v\n", val, err.Error())
			panic(err.Error())
		}
		return SleepAction{Duration:dur}
	case time.Duration:
		return SleepAction{Duration: val}
	default:
		fmt.Printf("unsupported Sleep value type. Supported is int or string (golang time.Duration), was %T\n", val)
		panic("unsupported sleep value")
	}
}


text:
module MultipartPost
  VERSION = "1.2.0"
end


text:
package org.bayswater.musicrest

import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.http._
import spray.http.HttpHeaders._
import StatusCodes._
import MediaTypes._
import org.bayswater.musicrest.model.TuneModel
import org.bayswater.musicrest.abc._
import org.bayswater.musicrest.abc.Tune.AbcType
import org.bayswater.musicrest.cache.Cache._
import org.bayswater.musicrest.TestData._

/* These tests exercise URLs which require content negotiation */
class ContentNegotiationSpec extends RoutingSpec with MusicRestService {
  def actorRefFactory = system

  val before = {basicUsers; basicGenres; insertTunes; clearTuneCache}

  "MusicRestService" should {

    /* Tunes */
    "return text/plain content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "text/plain")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/plain`
        responseAs[String] must contain("T: Noon Lasses")
        responseAs[String] must contain("M: 4/4")
      }
    }

    "return text/vnd.abc content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "text/vnd.abc")  ~> musicRestRoute ~> check {
        mediaType === AbcType
        responseAs[String] must contain("T: Noon Lasses")
        responseAs[String] must contain("M: 4/4")
      }
    }

   "return text/xml content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "text/xml")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/xml`
        responseAs[String] must contain("<T>Noon Lasses</T>")
      }
    }

   "return application/json content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/speed+the+plough-reel") ~> addHeader("Accept", "application/json")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/json`
        println(s"JSON Tune ${responseAs[String]}")
        responseAs[String] must contain("""T": "Speed The Plough""")
      }
    }

   "return application/pdf content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "application/pdf")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/pdf`
      }
    }

   "return audio/midi content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "audio/midi")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`audio/midi`
      }
    }

   "return image/png content when requested for tunes of this type" in {
      Get("/musicrest/genre/irish/tune/noon+lasses-reel") ~> addHeader("Accept", "image/png")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`image/png`
      }
    }

    /* Note, as of this version of Spray, this will raise a Spray exception which is caught by Spray */
   /*
    "return text/plain content when the tune doesn't exist" in {
      Get("/musicrest/genre/irish/tune/no-such-tune") ~> addHeader("Accept", "text/plain")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/plain`
      }
    }
    *
    */

   /* Genre Rhythm Lists */
   "return text/xml content when requested for a genre list of this type" in {
      Get("/musicrest/genre/scandi") ~> addHeader("Accept", "text/xml")  ~> sealRoute(musicRestRoute) ~> check {
        mediaType === MediaTypes.`text/xml`
        responseAs[String] must contain("<rhythm>polska</rhythm>")
      }
    }

    "return application/json content when requested for a genre list of this type" in {
      Get("/musicrest/genre/scandi") ~> addHeader("Accept", "application/json")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/json`
        responseAs[String] must contain("""{ "rhythm" :[""")
      }
    }

  "return text/html content when requested for a genre list of this type" in {
      Get("/musicrest/genre/scandi") ~> addHeader("Accept", "text/html")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/html`
        responseAs[String] must contain("
polska")
      }
    }

   /* Genre Lists */
   "return text/xml content when requested for a genre list of this type" in {
      Get("/musicrest/genre") ~> addHeader("Accept", "text/xml")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/xml`
        responseAs[String] must contain("<genre>scandi</genre>")
      }
    }

    "return application/json content when requested for a genre list of this type" in {
      Get("/musicrest/genre") ~> addHeader("Accept", "application/json")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/json`
        responseAs[String] must contain("""["scottish","scandi","irish","klezmer"]""")
      }
    }

  "return text/html content when requested for a genre list of this type" in {
      Get("/musicrest/genre") ~> addHeader("Accept", "text/html")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/html`
        responseAs[String] must contain("
scandi")
      }
    }

   /* Tune Lists */
   "return text/xml content when requested for a tune list of this type" in {
      Get("/musicrest/genre/irish/tune") ~> addHeader("Accept", "text/xml")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/xml`
        responseAs[String] must contain("<tunes>")
        responseAs[String] must contain("""<uri>noon+lasses-reel</uri>""")
        responseAs[String] must contain("""<pagination><page>1</page><size>10</size><maxPages>1</maxPages></pagination>""")
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

    "return application/json content when requested for a tune list of this type" in {
      Get("/musicrest/genre/irish/tune") ~> addHeader("Accept", "application/json")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/json`
        // println(s"JSON Tune List ${responseAs[String]}")
        responseAs[String] must contain(""""uri": "noon+lasses-reel"""")
        responseAs[String] must contain(""" "pagination" : """)
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

  "return text/html content when requested for a tune list of this type" in {
      Get("/musicrest/genre/irish/tune") ~> addHeader("Accept", "text/html")  ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/html`
        responseAs[String] must contain("""noon lasses""")
        responseAs[String] must contain("""""")
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

    /* User Lists */
   "return text/xml content when requested for a user list of this type" in {
      Get("/musicrest/user") ~> addHeader("Accept", "text/xml") ~> Authorization(BasicHttpCredentials("administrator", "adm1n1str80r")) ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/xml`
        responseAs[String] must contain("<name>administrator</name>")
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

    "return application/json content when requested for a user list of this type" in {
      Get("/musicrest/user") ~> addHeader("Accept", "application/json")  ~> Authorization(BasicHttpCredentials("administrator", "adm1n1str80r")) ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`application/json`
        responseAs[String] must contain(""""name": "administrator" """)
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

  "return text/html content when requested for a user list of this type" in {
      Get("/musicrest/user") ~> addHeader("Accept", "text/html")  ~> Authorization(BasicHttpCredentials("administrator", "adm1n1str80r")) ~> musicRestRoute ~> check {
        mediaType === MediaTypes.`text/html`
        responseAs[String] must contain("administrator	")
        checkPaginationHeader(header("Musicrest-Pagination"))
      }
    }

  }

  def checkPaginationHeader(h: Option[spray.http.HttpHeader]): Boolean = h match {
    case None => validationFailure("No pagination header")
    case Some(h) => h.value must contain ("1 of 1")
  }

  // this is a hack to get the types to match up - must find out how to do it properly
  def validationFailure (msg: String) =
     msg must_== "true"

  def insertTunes = {
   val dbName = "tunedbtest"
   val tuneModel = TuneModel()
   val genre = "irish"
   tuneModel.delete(genre)
   val validNoonLasses = abcFor(genre, noonLasses)
   validNoonLasses.fold(e => println("unexpected error in test data: " + e), s => s.upsert("irish"))
   val validSpeedThePlough = abcFor(genre, speedThePlough)
   validSpeedThePlough.fold(e => println("unexpected error in test data: " + e), s => s.upsert("irish"))
  }

  def clearTuneCache = {
    val cacheDir = new java.io.File("cache/test")
    clearCache(cacheDir, 0)
  }

}