DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 5/7] net/ixgbe/base: use clause 22 MDIO functions for Marvell PHYs
From: Wei Dai @ 2017-01-12 14:53 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, helin.zhang, konstantin.ananyev, Wei Dai
In-Reply-To: <1484232811-39257-1-git-send-email-wei.dai@intel.com>

This patch sets the MDIO(Management Data Input/Output Interface)
read/write function ponters for Marvell PHYs on some X550 platforms
to use the clause 22 functions. Marvell PHYs do not support clause 45.

Signed-off-by: Wei Dai <wei.dai@intel.com>
---
 drivers/net/ixgbe/base/ixgbe_x550.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ixgbe/base/ixgbe_x550.c b/drivers/net/ixgbe/base/ixgbe_x550.c
index 1fd7ffb..e15054b 100644
--- a/drivers/net/ixgbe/base/ixgbe_x550.c
+++ b/drivers/net/ixgbe/base/ixgbe_x550.c
@@ -2373,6 +2373,10 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
 		/* set up for CS4227 usage */
 		hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
 		break;
+	case IXGBE_DEV_ID_X550EM_X_1G_T:
+		phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi_22;
+		phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi_22;
+		break;
 	default:
 		break;
 	}
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 6/7] net/ixgbe/base: add some debug traces
From: Wei Dai @ 2017-01-12 14:53 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, helin.zhang, konstantin.ananyev, Wei Dai
In-Reply-To: <1484232811-39257-1-git-send-email-wei.dai@intel.com>

This patch adds some traces in the reset_hw logic
and semaphore acquisition logic to help debugging.

Signed-off-by: Wei Dai <wei.dai@intel.com>
---
 drivers/net/ixgbe/base/ixgbe_common.c |  7 ++++-
 drivers/net/ixgbe/base/ixgbe_phy.c    | 16 +++++++++---
 drivers/net/ixgbe/base/ixgbe_x540.c   | 11 ++++++--
 drivers/net/ixgbe/base/ixgbe_x550.c   | 49 +++++++++++++++++++++++++++++------
 4 files changed, 69 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ixgbe/base/ixgbe_common.c b/drivers/net/ixgbe/base/ixgbe_common.c
index 0dd33b8..9645667 100644
--- a/drivers/net/ixgbe/base/ixgbe_common.c
+++ b/drivers/net/ixgbe/base/ixgbe_common.c
@@ -410,8 +410,10 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
 
 	/* Setup flow control */
 	ret_val = ixgbe_setup_fc(hw);
-	if (ret_val != IXGBE_SUCCESS && ret_val != IXGBE_NOT_IMPLEMENTED)
+	if (ret_val != IXGBE_SUCCESS && ret_val != IXGBE_NOT_IMPLEMENTED) {
+		DEBUGOUT1("Flow control setup failed, returning %d\n", ret_val);
 		return ret_val;
+	}
 
 	/* Cache bit indicating need for crosstalk fix */
 	switch (hw->mac.type) {
@@ -501,6 +503,9 @@ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw)
 	/* Initialize the LED link active for LED blink support */
 	hw->mac.ops.init_led_link_act(hw);
 
+	if (status != IXGBE_SUCCESS)
+		DEBUGOUT1("Failed to initialize HW, STATUS = %d\n", status);
+
 	return status;
 }
 
diff --git a/drivers/net/ixgbe/base/ixgbe_phy.c b/drivers/net/ixgbe/base/ixgbe_phy.c
index e0d7125..c953805 100644
--- a/drivers/net/ixgbe/base/ixgbe_phy.c
+++ b/drivers/net/ixgbe/base/ixgbe_phy.c
@@ -291,8 +291,11 @@ static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
 {
 	u16 ext_ability = 0;
 
-	if (!ixgbe_validate_phy_addr(hw, phy_addr))
+	if (!ixgbe_validate_phy_addr(hw, phy_addr)) {
+		DEBUGOUT1("Unable to validate PHY address 0x%04X\n",
+			phy_addr);
 		return false;
+	}
 
 	if (ixgbe_get_phy_id(hw))
 		return false;
@@ -411,6 +414,8 @@ bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
 	if (phy_id != 0xFFFF && phy_id != 0x0)
 		valid = true;
 
+	DEBUGOUT1("PHY ID HIGH is 0x%04X\n", phy_id);
+
 	return valid;
 }
 
@@ -439,6 +444,9 @@ s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
 		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
 		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
 	}
+	DEBUGOUT2("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n",
+		  phy_id_high, phy_id_low);
+
 	return status;
 }
 
@@ -570,7 +578,7 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
  *  @phy_data: Pointer to read data from PHY register
  **/
 s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
-		       u16 *phy_data)
+			   u16 *phy_data)
 {
 	u32 i, data, command;
 
@@ -592,12 +600,13 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
 
 		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
 		if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-				break;
+			break;
 	}
 
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n");
+		DEBUGOUT("PHY address command did not complete, returning IXGBE_ERR_PHY\n");
 		return IXGBE_ERR_PHY;
 	}
 
@@ -627,6 +636,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n");
+		DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n");
 		return IXGBE_ERR_PHY;
 	}
 
diff --git a/drivers/net/ixgbe/base/ixgbe_x540.c b/drivers/net/ixgbe/base/ixgbe_x540.c
index 49bf154..499b1fa 100644
--- a/drivers/net/ixgbe/base/ixgbe_x540.c
+++ b/drivers/net/ixgbe/base/ixgbe_x540.c
@@ -775,8 +775,10 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
 		/* SW NVM semaphore bit is used for access to all
 		 * SW_FW_SYNC bits (not just NVM)
 		 */
-		if (ixgbe_get_swfw_sync_semaphore(hw))
+		if (ixgbe_get_swfw_sync_semaphore(hw)) {
+			DEBUGOUT("Failed to get NVM access and register semaphore, returning IXGBE_ERR_SWFW_SYNC\n");
 			return IXGBE_ERR_SWFW_SYNC;
+		}
 
 		swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw));
 		if (!(swfw_sync & (fwmask | swmask | hwmask))) {
@@ -798,6 +800,7 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
 	if (swmask == IXGBE_GSSR_SW_MNG_SM) {
 		ERROR_REPORT1(IXGBE_ERROR_POLLING,
 			     "Failed to get SW only semaphore");
+		DEBUGOUT("Failed to get SW only semaphore, returning IXGBE_ERR_SWFW_SYNC\n");
 		return IXGBE_ERR_SWFW_SYNC;
 	}
 
@@ -806,8 +809,10 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
 	 * of the requested resource(s) while ignoring the corresponding FW/HW
 	 * bits in the SW_FW_SYNC register.
 	 */
-	if (ixgbe_get_swfw_sync_semaphore(hw))
+	if (ixgbe_get_swfw_sync_semaphore(hw)) {
+		DEBUGOUT("Failed to get NVM sempahore and register semaphore while forcefully ignoring FW sempahore bit(s) and setting SW semaphore bit(s), returning IXGBE_ERR_SWFW_SYNC\n");
 		return IXGBE_ERR_SWFW_SYNC;
+	}
 	swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw));
 	if (swfw_sync & (fwmask | hwmask)) {
 		swfw_sync |= swmask;
@@ -829,9 +834,11 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
 			rmask |= IXGBE_GSSR_I2C_MASK;
 		ixgbe_release_swfw_sync_X540(hw, rmask);
 		ixgbe_release_swfw_sync_semaphore(hw);
+		DEBUGOUT("Resource not released by other SW, returning IXGBE_ERR_SWFW_SYNC\n");
 		return IXGBE_ERR_SWFW_SYNC;
 	}
 	ixgbe_release_swfw_sync_semaphore(hw);
+	DEBUGOUT("Returning error IXGBE_ERR_SWFW_SYNC\n");
 
 	return IXGBE_ERR_SWFW_SYNC;
 }
diff --git a/drivers/net/ixgbe/base/ixgbe_x550.c b/drivers/net/ixgbe/base/ixgbe_x550.c
index e15054b..6f9c034 100644
--- a/drivers/net/ixgbe/base/ixgbe_x550.c
+++ b/drivers/net/ixgbe/base/ixgbe_x550.c
@@ -1311,13 +1311,20 @@ s32 ixgbe_get_phy_token(struct ixgbe_hw *hw)
 					      sizeof(token_cmd),
 					      IXGBE_HI_COMMAND_TIMEOUT,
 					      true);
-	if (status)
+	if (status) {
+		DEBUGOUT1("Issuing host interface command failed with Status = %d\n",
+			  status);
 		return status;
+	}
 	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
 		return IXGBE_SUCCESS;
-	if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY)
+	if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) {
+		DEBUGOUT1("Host interface command returned 0x%08x , returning IXGBE_ERR_FW_RESP_INVALID\n",
+			  token_cmd.hdr.cmd_or_resp.ret_status);
 		return IXGBE_ERR_FW_RESP_INVALID;
+	}
 
+	DEBUGOUT("Returning  IXGBE_ERR_TOKEN_RETRY\n");
 	return IXGBE_ERR_TOKEN_RETRY;
 }
 
@@ -2495,9 +2502,10 @@ s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
 
 	/* Call adapter stop to disable Tx/Rx and clear interrupts */
 	status = hw->mac.ops.stop_adapter(hw);
-	if (status != IXGBE_SUCCESS)
+	if (status != IXGBE_SUCCESS) {
+		DEBUGOUT1("Failed to stop adapter, STATUS = %d\n", status);
 		return status;
-
+	}
 	/* flush pending Tx transactions */
 	ixgbe_clear_tx_pending(hw);
 
@@ -2506,14 +2514,23 @@ s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
 	/* PHY ops must be identified and initialized prior to reset */
 	status = hw->phy.ops.init(hw);
 
-	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (status)
+		DEBUGOUT1("Failed to initialize PHY ops, STATUS = %d\n",
+			  status);
+
+	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+		DEBUGOUT("Returning from reset HW since PHY ops init returned IXGBE_ERR_SFP_NOT_SUPPORTED\n");
 		return status;
+	}
 
 	/* start the external PHY */
 	if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
 		status = ixgbe_init_ext_t_x550em(hw);
-		if (status)
+		if (status) {
+			DEBUGOUT1("Failed to start the external PHY, STATUS = %d\n",
+				  status);
 			return status;
+		}
 	}
 
 	/* Setup SFP module if there is one present. */
@@ -2587,6 +2604,9 @@ s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
 		ixgbe_setup_mux_ctl(hw);
 
+	if (status != IXGBE_SUCCESS)
+		DEBUGOUT1("Reset HW failed, STATUS = %d\n", status);
+
 	return status;
 }
 
@@ -4336,21 +4356,34 @@ STATIC s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask)
 		status = IXGBE_SUCCESS;
 		if (hmask)
 			status = ixgbe_acquire_swfw_sync_X540(hw, hmask);
-		if (status)
+		if (status) {
+			DEBUGOUT1("Could not acquire SWFW semaphore, Status = %d\n",
+				  status);
 			return status;
+		}
 		if (!(mask & IXGBE_GSSR_TOKEN_SM))
 			return IXGBE_SUCCESS;
 
 		status = ixgbe_get_phy_token(hw);
+		if (status == IXGBE_ERR_TOKEN_RETRY)
+			DEBUGOUT1("Could not acquire PHY token, Status = %d\n",
+				  status);
+
 		if (status == IXGBE_SUCCESS)
 			return IXGBE_SUCCESS;
 
 		if (hmask)
 			ixgbe_release_swfw_sync_X540(hw, hmask);
-		if (status != IXGBE_ERR_TOKEN_RETRY)
+
+		if (status != IXGBE_ERR_TOKEN_RETRY) {
+			DEBUGOUT1("Unable to retry acquiring the PHY token, Status = %d\n",
+				  status);
 			return status;
+		}
 	}
 
+	DEBUGOUT1("Semaphore acquisition retries failed!: PHY ID = 0x%08X\n",
+		  hw->phy.id);
 	return status;
 }
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 7/7] net/ixgbe/base: update version of shared code
From: Wei Dai @ 2017-01-12 14:53 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, helin.zhang, konstantin.ananyev, Wei Dai
In-Reply-To: <1484232811-39257-1-git-send-email-wei.dai@intel.com>

update version of shared code to 2017-01-05 in README.

Signed-off-by: Wei Dai <wei.dai@intel.com>
---
 drivers/net/ixgbe/base/README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ixgbe/base/README b/drivers/net/ixgbe/base/README
index 1936191..0a6054f 100644
--- a/drivers/net/ixgbe/base/README
+++ b/drivers/net/ixgbe/base/README
@@ -34,7 +34,7 @@ Intel® IXGBE driver
 ===================
 
 This directory contains source code of FreeBSD ixgbe driver of version
-cid-10g-shared-code.2016.11.21 released by the team which develop
+cid-10g-shared-code.2017.01.05 released by the team which develop
 basic drivers for any ixgbe NIC. The sub-directory of base/
 contains the original source package.
 This driver is valid for the product(s) listed below
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v3 3/3] pci: Pass rte_pci_addr to functions instead of separate args
From: Thomas Monjalon @ 2017-01-12 14:58 UTC (permalink / raw)
  To: Ben Walker; +Cc: dev
In-Reply-To: <20170111171012.126251-3-benjamin.walker@intel.com>

2017-01-11 10:10, Ben Walker:
> Instead of passing domain, bus, devid, func, just pass
> an rte_pci_addr.
> 
> Signed-off-by: Ben Walker <benjamin.walker@intel.com>

Added v2 acks from Shreyansh and removed unnecessary empty lines as Shreyansh commented, and
Series applied, thanks

^ permalink raw reply

* Re: [dpdk-stable] [PATCH 1/2] net/virtio: fix performance regression due to TSO enabling
From: Jan Viktorin @ 2017-01-12 15:02 UTC (permalink / raw)
  To: Yuanhan Liu
  Cc: Thomas Monjalon, Jianbo Liu, Jerin Jacob, Chao Zhu, dev,
	Tan Jianfeng, Wang Zhihong, Olivier Matz, Maxime Coquelin,
	Michael S. Tsirkin, Orsák Michal
In-Reply-To: <20170112023058.GF2402@yliu-dev.sh.intel.com>

On Thu, 12 Jan 2017 10:30:58 +0800
Yuanhan Liu <yuanhan.liu@linux.intel.com> wrote:

> On Wed, Jan 11, 2017 at 03:51:22PM +0100, Thomas Monjalon wrote:
> > 2017-01-11 12:27, Yuanhan Liu:  
> > > The fact that virtio net header is initiated to zero in PMD driver
> > > init stage means that these costly writes are unnecessary and could
> > > be avoided:
> > > 
> > >     if (hdr->csum_start != 0)
> > >         hdr->csum_start = 0;
> > > 
> > > And that's what the macro ASSIGN_UNLESS_EQUAL does. With this, the
> > > performance drop introduced by TSO enabling is recovered: it could
> > > be up to 20% in micro benchmarking.  
> > 
> > This patch is adding a condition to assignments.
> > We need a benchmark on other architectures like ARM. Please anyone?  
> 
> I think the cost of condition should be way lower than the cost from the
> penalty introduced by the cache issue, that I don't see it would perform
> bad on other platforms.
> 
> But, of course, testing is always welcome!
> 
> 	--yliu

Hello,

we've done a synthetic measurement, principle briefly:

== Without condition check ==

start = gettimeofday();

for (i = 0; i < 1024*1024*128; ++i) {
	hdr->csum_start = 0;
	hdr->csum_offset = 0;
	hdr->flags = 0;
}

end = gettimeofday();


== With condition check ==

start = gettimeofday();

for (i = 0; i < 1024*1024*128; ++i) {
	ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
	ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
	ASSIGN_UNLESS_EQUAL(hdr->flags, 0);
}

end = gettimeofday();


== Results ==

Computed as total time of all threads:

for i = 1..THREAD_COUNT:
	result += end[i] - start[i]

cpu           threads  without-check (ms)  with-check
Xeon E5-2670        1            516              529
Xeon E5-2670        2           1155              953
Xeon E5-2670        8           8947             5044
Xeon E5-2670       16          23335            16836
Zynq-7020 (armv7)   1           6735             7205
Zynq-7020 (armv7)   2          13753            14418

The advantage for Intel is evident when increasing the number
of threads.

However, on 32-bit ARMs we might expect some performance drop.

Regards
Jan

> > 
> > 
> > [...]  
> > > +/* avoid write operation when necessary, to lessen cache issues */
> > > +#define ASSIGN_UNLESS_EQUAL(var, val) do {	\
> > > +	if ((var) != (val))			\
> > > +		(var) = (val);			\
> > > +} while (0)  

^ permalink raw reply

* Re: [PATCH] app/testpmd: fix static build link ordering
From: Ferruh Yigit @ 2017-01-12 15:27 UTC (permalink / raw)
  To: Jerin Jacob, Thomas Monjalon; +Cc: dev, stable
In-Reply-To: <20170112135830.GA11208@localhost.localdomain>

On 1/12/2017 1:58 PM, Jerin Jacob wrote:
> On Thu, Jan 12, 2017 at 10:26:08AM +0100, Thomas Monjalon wrote:
>> 2017-01-12 13:16, Jerin Jacob:
>>> +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
>>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += -lrte_pmd_ixgbe
>>> +endif
>>
>> _LDLIBS is an internal variable of rte.app.mk.
>> Please could you check that there is no issue when using LDLIBS instead
>> of _LDLIBS?
> 
> Tested it. Suggested change has issue in shared lib configuration.
> 
> [dpdk-master] $ git diff
> diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
> index 050663a..27cadd5 100644
> --- a/app/test-pmd/Makefile
> +++ b/app/test-pmd/Makefile
> @@ -59,9 +59,7 @@ SRCS-y += csumonly.c
>  SRCS-y += icmpecho.c
>  SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
>  
> -ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> -_LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += -lrte_pmd_ixgbe
> -endif
> +LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += -lrte_pmd_ixgbe

It is LDLIBS instead of LDLIBS-y, following may work:

-_LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += -lrte_pmd_ixgbe
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y)
+LDLIBS += -lrte_pmd_ixgbe
+endif
+endif


Also using EXTRA_LDLIBS instead of LDLIBS may remove the requirement of
the SHARED_LIB check, because of where it is located, but this seems
just coincidental.

^ permalink raw reply

* Re: [PATCH v6 1/4] lib: add information metrics library
From: Remy Horton @ 2017-01-12 15:30 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev
In-Reply-To: <1951093.Zqtj2Qm3TA@xps13>


On 12/01/2017 13:22, Thomas Monjalon wrote:
> 2017-01-12 00:03, Remy Horton:
[..]
>> --- /dev/null
>> +++ b/lib/librte_metrics/rte_metrics.h
>> +/** Used to indicate port-independent information */
>> +#define RTE_METRICS_NONPORT -1
>
> I do not understand this constant.
> Why using the word "port" to name any device?
> What means independent?

The metric library hold two sets of values: Ones specific to ports, and 
ones that are global/aggregate. Agree "non port" is not the clearest 
choice of name..


>> +/**
>> + * Metric name
>> + */
>> +struct rte_metric_name {
>> +	/** String describing metric */
>> +	char name[RTE_METRICS_MAX_NAME_LEN];
>> +};
>
> Why a struct for a simple string?

It is modelled after xstats, which does the same thing. In this case 
thinking was that using:

rte_metrics_get_names(struct rte_metric_name *names,
	uint16_t capacity)

would be tidier than (e.g.):

rte_metrics_get_names(char *names[RTE_METRICS_MAX_NAME_LEN],
	uint16_t capacity)


>> + */
>> +struct rte_metric_value {
>> +	/** Numeric identifier of metric */
>> +	uint16_t key;
>
> How the key is bound to the name?

Corresponds to array position in struct rte_metric_name. Will amend 
doxygen comments.


> Remember how the xstats comments were improved:
> 	http://dpdk.org/commit/6d52d1d

Will take account for them. I wrote this code back in October, so it 
slipped my mind to apply the same comments to this module.

^ permalink raw reply

* Re: [PATCH v5 12/18] net/ixgbe: parse ethertype filter
From: Ferruh Yigit @ 2017-01-12 15:39 UTC (permalink / raw)
  To: Wei Zhao, dev; +Cc: Wenzhuo Lu
In-Reply-To: <1484212665-1635-13-git-send-email-wei.zhao1@intel.com>

On 1/12/2017 9:17 AM, Wei Zhao wrote:
> check if the rule is a ethertype rule, and get the ethertype info.
> 
> Signed-off-by: Wei Zhao <wei.zhao1@intel.com>
> Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
> ---
>  drivers/net/ixgbe/ixgbe_flow.c | 278 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 278 insertions(+)
> 
> diff --git a/drivers/net/ixgbe/ixgbe_flow.c b/drivers/net/ixgbe/ixgbe_flow.c
> index ac9f663..2f97129 100644
> --- a/drivers/net/ixgbe/ixgbe_flow.c
> +++ b/drivers/net/ixgbe/ixgbe_flow.c
> @@ -90,6 +90,18 @@ ixgbe_parse_ntuple_filter(const struct rte_flow_attr *attr,
>  					struct rte_eth_ntuple_filter *filter,
>  					struct rte_flow_error *error);
>  static int
> +cons_parse_ethertype_filter(const struct rte_flow_attr *attr,

Although this is static function, you may prefer to keep ixgbe_
namespace in the function.

> +			    const struct rte_flow_item *pattern,
> +			    const struct rte_flow_action *actions,
> +			    struct rte_eth_ethertype_filter *filter,
> +			    struct rte_flow_error *error);
> +static int
> +ixgbe_parse_ethertype_filter(const struct rte_flow_attr *attr,
> +				const struct rte_flow_item pattern[],
> +				const struct rte_flow_action actions[],
> +				struct rte_eth_ethertype_filter *filter,
> +				struct rte_flow_error *error);
> +static int
>  ixgbe_flow_validate(__rte_unused struct rte_eth_dev *dev,
>  		const struct rte_flow_attr *attr,
>  		const struct rte_flow_item pattern[],
> @@ -480,6 +492,265 @@ ixgbe_parse_ntuple_filter(const struct rte_flow_attr *attr,
>  }
>  
>  /**
> + * Parse the rule to see if it is a ethertype rule.
> + * And get the ethertype filter info BTW.
> + * pattern:
> + * The first not void item can be ETH.
> + * The next not void item must be END.

This documents item.type, can you please also document expected/valid
item->spec, item->last and item->mask values.

Same for all parse functions.

I am aware this is lots of comment when you think all parse functions,
but I believe this can be very useful in the future.
And it is very unlikely that it will be done later, if it has not been
done now.

Thanks,
ferruh

> + * action:
> + * The first not void action should be QUEUE.
> + * The next not void action should be END.
> + */
> +static int
> +cons_parse_ethertype_filter(const struct rte_flow_attr *attr,
> +			    const struct rte_flow_item *pattern,
> +			    const struct rte_flow_action *actions,
> +			    struct rte_eth_ethertype_filter *filter,
> +			    struct rte_flow_error *error)

<...>

^ permalink raw reply

* Re: [PATCH v5 11/18] net/ixgbe: parse n-tuple filter
From: Ferruh Yigit @ 2017-01-12 15:40 UTC (permalink / raw)
  To: Wei Zhao, dev; +Cc: Wenzhuo Lu
In-Reply-To: <1484212665-1635-12-git-send-email-wei.zhao1@intel.com>

On 1/12/2017 9:17 AM, Wei Zhao wrote:
> Add rule validate function and check if the rule is a n-tuple rule,
> and get the n-tuple info.
> 
> Signed-off-by: Wei Zhao <wei.zhao1@intel.com>
> Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
> ---
<...>
>  /*  Destroy all flow rules associated with a port on ixgbe. */
>  static int
>  ixgbe_flow_flush(struct rte_eth_dev *dev,
> @@ -99,15 +516,17 @@ ixgbe_flow_flush(struct rte_eth_dev *dev,
>  
>  	ret = ixgbe_clear_all_fdir_filter(dev);
>  	if (ret < 0) {
> -		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
> -					NULL, "Failed to flush rule");
> +		rte_flow_error_set(error, EINVAL,
> +				RTE_FLOW_ERROR_TYPE_HANDLE,
> +				NULL, "Failed to flush rule");
>  		return ret;
>  	}
>  
>  	ret = ixgbe_clear_all_l2_tn_filter(dev);
>  	if (ret < 0) {
> -		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
> -					NULL, "Failed to flush rule");
> +		rte_flow_error_set(error, EINVAL,
> +				RTE_FLOW_ERROR_TYPE_HANDLE,
> +				NULL, "Failed to flush rule");
>  		return ret;
>  	}

These are syntax modification to the updates added in previous patch.
They can be fixed when they added at first place.

^ permalink raw reply

* Re: [PATCH v5 00/18] net/ixgbe: Consistent filter API
From: Ferruh Yigit @ 2017-01-12 15:43 UTC (permalink / raw)
  To: Wei Zhao, dev
In-Reply-To: <1484212665-1635-1-git-send-email-wei.zhao1@intel.com>

Hi Wei,

On 1/12/2017 9:17 AM, Wei Zhao wrote:
> The patches mainly finish following functions:
> 1) Store and restore all kinds of filters.
> 2) Parse all kinds of filters.
> 3) Add flow validate function.
> 4) Add flow create function.
> 5) Add flow destroy function.
> 6) Add flow flush function.

Overall patchset looks good, only major comment is adding more comments
on parse_filter functions for expected/valid rules.

You can keep Beilei's Ack for next version of the patchset.

Thanks,
ferruh

^ permalink raw reply

* [PATCH] kvargs: make pointers in string arrays const
From: Bruce Richardson @ 2017-01-12 16:18 UTC (permalink / raw)
  To: olivier.matz; +Cc: dev, Bruce Richardson

Change the parameters of functions from const char *valid[] to
const char * const valid[]. This additional const is needed to
allow us to fix some checkpatch warnings, as well as being good
programming practice.

For the checkpatch warnings, if we have a set of command line
args that we want to check defined as:
	static const char *args[] = { "arg1", "arg2", NULL };
	kvlist = rte_kvargs_parse(params, args);

checkpatch will complain:
	WARNING:STATIC_CONST_CHAR_ARRAY: static const char *
	array should probably be static const char * const

Adding the additional const to the definition of the args
will then trigger a compiler error in the absense of this
change to the kvargs library, as we lose the const in the
call to kvargs_parse.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
 lib/librte_kvargs/rte_kvargs.c | 8 ++++----
 lib/librte_kvargs/rte_kvargs.h | 3 ++-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 8d56abd..854ac83 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -92,9 +92,9 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
  * into a list of valid keys.
  */
 static int
-is_valid_key(const char *valid[], const char *key_match)
+is_valid_key(const char * const valid[], const char *key_match)
 {
-	const char **valid_ptr;
+	const char * const *valid_ptr;
 
 	for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) {
 		if (strcmp(key_match, *valid_ptr) == 0)
@@ -109,7 +109,7 @@ is_valid_key(const char *valid[], const char *key_match)
  */
 static int
 check_for_valid_keys(struct rte_kvargs *kvlist,
-		const char *valid[])
+		const char * const valid[])
 {
 	unsigned i, ret;
 	struct rte_kvargs_pair *pair;
@@ -187,7 +187,7 @@ rte_kvargs_free(struct rte_kvargs *kvlist)
  * check if only valid keys were used.
  */
 struct rte_kvargs *
-rte_kvargs_parse(const char *args, const char *valid_keys[])
+rte_kvargs_parse(const char *args, const char * const valid_keys[])
 {
 	struct rte_kvargs *kvlist;
 
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index ae9ae79..5821c72 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -97,7 +97,8 @@ struct rte_kvargs {
  *   - A pointer to an allocated rte_kvargs structure on success
  *   - NULL on error
  */
-struct rte_kvargs *rte_kvargs_parse(const char *args, const char *valid_keys[]);
+struct rte_kvargs *rte_kvargs_parse(const char *args,
+		const char *const valid_keys[]);
 
 /**
  * Free a rte_kvargs structure
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH v2 0/7] update ixgbe shared code to version 2017-01-05
From: Ferruh Yigit @ 2017-01-12 17:15 UTC (permalink / raw)
  To: Wei Dai, dev; +Cc: helin.zhang, konstantin.ananyev
In-Reply-To: <1484232811-39257-1-git-send-email-wei.dai@intel.com>

On 1/12/2017 2:53 PM, Wei Dai wrote:
> This patch set updates ixgbe shared code to cid-ixgbe.2017.01.05.tar.gz .
> The shared codes are in drivers/net/ixgbe/base/ and are developed by 
> another Intel team.
> 
> This patch add more supports to some future new Intel ixgbe X550  platforms.
> A new device id and two PHY types are introduced and also 
> add some debug traces to help debugging.
> 
> Wei Dai (7):
>   net/ixgbe/base: support XFI backplane for X550
>   net/ixgbe/base: remove a compiler warning
>   net/ixgbe/base: configure speeds for KR/KX backplane
>   net/ixgbe/base: support Marvell 1000BASE-T PHYs
>   net/ixgbe/base: use clause 22 MDIO functions for Marvell PHYs
>   net/ixgbe/base: add some debug traces
>   net/ixgbe/base: update version of shared code
> 
>  drivers/net/ixgbe/base/README         |  2 +-
>  drivers/net/ixgbe/base/ixgbe_api.c    |  1 +
>  drivers/net/ixgbe/base/ixgbe_common.c |  9 +++-
>  drivers/net/ixgbe/base/ixgbe_phy.c    | 20 +++++++--
>  drivers/net/ixgbe/base/ixgbe_type.h   |  3 ++
>  drivers/net/ixgbe/base/ixgbe_x540.c   | 11 ++++-
>  drivers/net/ixgbe/base/ixgbe_x550.c   | 77 ++++++++++++++++++++++++++++++-----
>  7 files changed, 104 insertions(+), 19 deletions(-)
> 

Series applied to dpdk-next-net/master, thanks.

(some commit logs slightly updated, can you please confirm them?)

^ permalink raw reply

* Re: [PATCH v6 1/4] lib: add information metrics library
From: Thomas Monjalon @ 2017-01-12 19:05 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev
In-Reply-To: <d68dcbe6-296f-aaed-3514-76a321db7c20@intel.com>

2017-01-12 15:30, Remy Horton:
> 
> On 12/01/2017 13:22, Thomas Monjalon wrote:
> > 2017-01-12 00:03, Remy Horton:
> [..]
> >> --- /dev/null
> >> +++ b/lib/librte_metrics/rte_metrics.h
> >> +/** Used to indicate port-independent information */
> >> +#define RTE_METRICS_NONPORT -1
> >
> > I do not understand this constant.
> > Why using the word "port" to name any device?
> > What means independent?
> 
> The metric library hold two sets of values: Ones specific to ports, and 
> ones that are global/aggregate. Agree "non port" is not the clearest 
> choice of name..

I think you should not use the word "port" at all.

^ permalink raw reply

* Re: [PATCH v3 15/29] crypto/qat: use eal I/O device memory read/write API
From: Ferruh Yigit @ 2017-01-12 19:09 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: konstantin.ananyev, thomas.monjalon, bruce.richardson, jianbo.liu,
	viktorin, santosh.shukla, John Griffin, Fiona Trahe,
	Deepak Kumar Jain
In-Reply-To: <1484212646-10338-16-git-send-email-jerin.jacob@caviumnetworks.com>

Hi Jerin,

On 1/12/2017 9:17 AM, Jerin Jacob wrote:
<...>

> +#include <rte_io.h>
> +
>  /* CSR write macro */
> -#define ADF_CSR_WR(csrAddr, csrOffset, val) \
> -	(void)((*((volatile uint32_t *)(((uint8_t *)csrAddr) + csrOffset)) \
> -			= (val)))
> +#define ADF_CSR_WR(csrAddr, csrOffset, val)		\
> +	rte_write32(val, (((uint8_t *)csrAddr) + csrOffset))

For IA, this update introduces an extra compiler barrier (rte_io_wmb()),
which is indeed not a must, is this correct?

If so, does it make sense to override these functions for x86, and make
rte_writeX = rte_writeX_relaxed
rte_readX = rte_readX_relaxed

>  
>  /* CSR read macro */
> -#define ADF_CSR_RD(csrAddr, csrOffset) \
> -	(*((volatile uint32_t *)(((uint8_t *)csrAddr) + csrOffset)))
> +#define ADF_CSR_RD(csrAddr, csrOffset)			\
> +	rte_read32((((uint8_t *)csrAddr) + csrOffset))

This patchset both introduces new rte_readX/rte_writeX functions, also
applies them into drivers.

While applying them, it changes the behavior.
Like above code was doing a read, but after update it does read and
read_memory_barrier.

What do you think this patchset updates usage in a manner that keeps
behavior exact same. Like using rte_read32_relaxed for this case.
And doing architecture related updates in a different patchset?

This both makes easy to see architecture specific updates, and makes
easy to trace any possible performance issues by this patchset.

>  
>  #define ADF_BANK_INT_SRC_SEL_MASK_0 0x4444444CUL
>  #define ADF_BANK_INT_SRC_SEL_MASK_X 0x44444444UL
> 

^ permalink raw reply

* Re: [PATCH v3 16/29] net/bnxt: use eal I/O device memory read/write API
From: Ferruh Yigit @ 2017-01-12 19:10 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: konstantin.ananyev, thomas.monjalon, bruce.richardson, jianbo.liu,
	viktorin, santosh.shukla, Stephen Hurd, Ajit Khaparde
In-Reply-To: <1484212646-10338-17-git-send-email-jerin.jacob@caviumnetworks.com>

On 1/12/2017 9:17 AM, Jerin Jacob wrote:
<...>
>  #define B_CP_DB_REARM(cpr, raw_cons)					\
> -		(*(uint32_t *)((cpr)->cp_doorbell) = (DB_CP_REARM_FLAGS | \
> -				RING_CMP(cpr->cp_ring_struct, raw_cons)))
> +	rte_write32((DB_CP_REARM_FLAGS |				\

Just asking, can this be rte_write32_relaxed() since there is explicit
memory barrier defined for B_CP_DIS_DB but not for here?

> +		    RING_CMP(((cpr)->cp_ring_struct), raw_cons)),	\
> +		    ((cpr)->cp_doorbell))
>  
>  #define B_CP_DIS_DB(cpr, raw_cons)					\
> -		rte_smp_wmb();						\
> -		(*(uint32_t *)((cpr)->cp_doorbell) = (DB_CP_FLAGS |	\
> -				RING_CMP(cpr->cp_ring_struct, raw_cons)))
> +	rte_write32((DB_CP_FLAGS |					\
> +		    RING_CMP(((cpr)->cp_ring_struct), raw_cons)),	\
> +		    ((cpr)->cp_doorbell))
>  

<...>

> @@ -80,11 +82,12 @@ static int bnxt_hwrm_send_message_locked(struct bnxt *bp, void *msg,
>  	for (; i < bp->max_req_len; i += 4) {
>  		bar = (uint8_t *)bp->bar0 + i;
>  		*(volatile uint32_t *)bar = 0;

Should this line be removed?

> +		rte_write32(0, bar);
>  	}
>  
>  	/* Ring channel doorbell */
>  	bar = (uint8_t *)bp->bar0 + 0x100;
> -	*(volatile uint32_t *)bar = 1;
> +	rte_write32(1, bar);
>  
>  	/* Poll for the valid bit */
>  	for (i = 0; i < HWRM_CMD_TIMEOUT; i++) {
<...>

^ permalink raw reply

* Re: [PATCH v3 17/29] net/bnx2x: use eal I/O device memory read/write API
From: Ferruh Yigit @ 2017-01-12 19:11 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: konstantin.ananyev, thomas.monjalon, bruce.richardson, jianbo.liu,
	viktorin, santosh.shukla, Harish Patil, Rasesh Mody
In-Reply-To: <1484212646-10338-18-git-send-email-jerin.jacob@caviumnetworks.com>

On 1/12/2017 9:17 AM, Jerin Jacob wrote:
<...>
>  
> @@ -1560,11 +1556,9 @@ bnx2x_reg_read32(struct bnx2x_softc *sc, size_t offset)
>  #define DPM_TRIGGER_TYPE 0x40
>  
>  /* Doorbell macro */
> -#define BNX2X_DB_WRITE(db_bar, val) \
> -	*((volatile uint32_t *)(db_bar)) = (val)
> +#define BNX2X_DB_WRITE(db_bar, val) rte_write32_relaxed((val), (db_bar))

What is the rule to use relaxed version or not?

I don't know about memory barrier requirements, if it is easy, would you
mind explaining? Because I have same question for many different parts
of this patchset.

Thanks,
ferruh

^ permalink raw reply

* Re: [PATCH v3 18/29] net/cxgbe: use eal I/O device memory read/write API
From: Ferruh Yigit @ 2017-01-12 19:12 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: konstantin.ananyev, thomas.monjalon, bruce.richardson, jianbo.liu,
	viktorin, santosh.shukla, Rahul Lakkireddy
In-Reply-To: <1484212646-10338-19-git-send-email-jerin.jacob@caviumnetworks.com>

On 1/12/2017 9:17 AM, Jerin Jacob wrote:
<...>

>  
> -#define CXGBE_PCI_REG_WRITE(reg, value) ({ \
> -	CXGBE_PCI_REG((reg)) = (value); })
> +#define CXGBE_PCI_REG_WRITE(reg, value) rte_write32((value), (reg))

Almost all (if not all) PMD write macros' argument order is like
write(address, value), but rte_writeX has rte_writex(value, address)

What is the common usage for this kind of function?
What do you think reverting argument order?

As a similar example, dpdk ether_addr_copy(src, dst) function argument
order is revers according common usage, and keeps confusing people.

<...>

^ permalink raw reply

* [PATCH 0/2] make a couple eth_dev_ops const
From: Stephen Hemminger @ 2017-01-12 19:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Really trivial patches.

I also consider this a litmus test of how long it takes DPDK
project to merge trivial maintaince patches.

Stephen Hemminger (2):
  bnx: make eth_dev_ops const
  ena: make eth_dev_ops const

 drivers/net/bnxt/bnxt_ethdev.c | 2 +-
 drivers/net/ena/ena_ethdev.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

-- 
2.11.0

^ permalink raw reply

* Re: [PATCH 0/2] make a couple eth_dev_ops const
From: Ferruh Yigit @ 2017-01-12 21:54 UTC (permalink / raw)
  To: Stephen Hemminger, dev
In-Reply-To: <20170112191212.22710-1-stephen@networkplumber.org>

On 1/12/2017 7:12 PM, Stephen Hemminger wrote:
> Really trivial patches.

Patches are not in patchwork, and not in the mail list.

> 
> I also consider this a litmus test of how long it takes DPDK
> project to merge trivial maintaince patches.
> 
> Stephen Hemminger (2):
>   bnx: make eth_dev_ops const
>   ena: make eth_dev_ops const
> 
>  drivers/net/bnxt/bnxt_ethdev.c | 2 +-
>  drivers/net/ena/ena_ethdev.c   | 2 +-

Right, ena and bnxt are missing const for eth_dev_ops. Do you want me
send patches?

>  2 files changed, 2 insertions(+), 2 deletions(-)
> 

^ permalink raw reply

* [PATCH v3 0/5] Elastic Flow Distributor
From: Pablo de Lara @ 2017-01-12 22:15 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara
In-Reply-To: <1483751166-32423-1-git-send-email-pablo.de.lara.guarch@intel.com>

EFD is a distributor library that uses perfect hashing to determine a
target/value for a given incoming flow key. It has the following advantages:
first, because it uses perfect hashing it does not store the key itself and
hence lookup performance is not dependent on the key size. Second, the
target/value can be any arbitrary value hence the system designer and/or
operator can better optimize service rates and inter-cluster network traffic
locating.  Third, since the storage requirement is much smaller than a
hash-based flow table (i.e. better fit for CPU cache), EFD can scale to millions
of flow keys. Finally, with current optimized library implementation performance
is fully scalable with number of CPU cores.

The basic idea of EFD is when a given key is to be inserted, a family of hash
functions is searched until the correct hash function that maps the input key to
the correct value is found. However, rather than explicitly storing all keys and
their associated values, EFD stores only indices of hash functions that map keys
to values, and thereby consumes much less space than conventional  flow-based
tables. The lookup operation is very simple, similar to computational-based
scheme, given an input key the lookup operation is reduced to hashing that key
with the correct hash function.

Intuitively, finding a hash function that maps each of a large number (millions)
of input keys to the correct output value is effectively impossible, as a result
EFD, breaks the problem into smaller pieces (divide and conquer). EFD divides
the entire input key set into many small groups. Each group consists of
approximately 20-28 keys (a configurable parameter for the library), then, for
each small group, a brute force search to find a hash function that produces the
correct outputs for each key in the group.
It should be mentioned that since in the online lookup table for EFD doesn’t
store the key itself, the size of the EFD table is independent of the key size
and hence EFD lookup performance which is almost constant irrespective of the
length of the key which is a highly desirable feature especially for longer
keys.

Library code is included in the patch, plus an sample application that shows
how the library can be used.

RFC for this library was already sent:
http://dpdk.org/ml/archives/dev/2016-October/049238.html

For more information on the library, check out the following document: 
https://github.com/pablodelara/perfect_hash_flow_distributor/blob/master/EFD_description.pdf

Changes in v3:

- Fixed SVG files
- Fixed copyright dates
- Reformatted parts of documentation


Changes in v2:

- Added documentation for library and sample app
- Fixed checkpatch errors/warnings
- Added functional and performance tests
- Made key size variable at runtime
- Made code multi-architecture compatible at runtime

Pablo de Lara (5):
  efd: new Elastic Flow Distributor library
  app/test: add EFD functional and perf tests
  examples/flow_distributor: sample app to demonstrate EFD usage
  doc: add EFD library section in Programmers guide
  doc: add flow distributor guide

 MAINTAINERS                                       |    9 +
 app/test/Makefile                                 |    5 +-
 app/test/test_efd.c                               |  494 ++++++++
 app/test/test_efd_perf.c                          |  407 +++++++
 config/common_base                                |    5 +
 doc/api/doxy-api-index.md                         |    3 +-
 doc/api/doxy-api.conf                             |    1 +
 doc/api/examples.dox                              |    4 +
 doc/guides/prog_guide/efd_lib.rst                 |  428 +++++++
 doc/guides/prog_guide/img/efd_i1.svg              |  130 ++
 doc/guides/prog_guide/img/efd_i10.svg             |  384 ++++++
 doc/guides/prog_guide/img/efd_i11.svg             |  319 +++++
 doc/guides/prog_guide/img/efd_i12.svg             | 1008 +++++++++++++++
 doc/guides/prog_guide/img/efd_i2.svg              |  280 +++++
 doc/guides/prog_guide/img/efd_i3.svg              |  634 ++++++++++
 doc/guides/prog_guide/img/efd_i4.svg              |  203 +++
 doc/guides/prog_guide/img/efd_i5.svg              |  183 +++
 doc/guides/prog_guide/img/efd_i6.svg              | 1254 +++++++++++++++++++
 doc/guides/prog_guide/img/efd_i7.svg              |  790 ++++++++++++
 doc/guides/prog_guide/img/efd_i8.svg              |  182 +++
 doc/guides/prog_guide/img/efd_i9.svg              |  390 ++++++
 doc/guides/prog_guide/index.rst                   |   23 +
 doc/guides/rel_notes/release_17_02.rst            |   15 +
 doc/guides/sample_app_ug/flow_distributor.rst     |  494 ++++++++
 doc/guides/sample_app_ug/img/flow_distributor.svg | 1254 +++++++++++++++++++
 doc/guides/sample_app_ug/index.rst                |    1 +
 examples/Makefile                                 |    1 +
 examples/flow_distributor/Makefile                |   44 +
 examples/flow_distributor/distributor/Makefile    |   57 +
 examples/flow_distributor/distributor/args.c      |  200 +++
 examples/flow_distributor/distributor/args.h      |   39 +
 examples/flow_distributor/distributor/init.c      |  371 ++++++
 examples/flow_distributor/distributor/init.h      |   76 ++
 examples/flow_distributor/distributor/main.c      |  362 ++++++
 examples/flow_distributor/node/Makefile           |   48 +
 examples/flow_distributor/node/node.c             |  417 +++++++
 examples/flow_distributor/shared/common.h         |   99 ++
 lib/Makefile                                      |    3 +-
 lib/librte_eal/common/include/rte_log.h           |    3 +-
 lib/librte_efd/Makefile                           |   56 +
 lib/librte_efd/rte_efd.c                          | 1354 +++++++++++++++++++++
 lib/librte_efd/rte_efd.h                          |  294 +++++
 lib/librte_efd/rte_efd_version.map                |   12 +
 mk/rte.app.mk                                     |    3 +-
 44 files changed, 12334 insertions(+), 5 deletions(-)
 create mode 100644 app/test/test_efd.c
 create mode 100644 app/test/test_efd_perf.c
 create mode 100644 doc/guides/prog_guide/efd_lib.rst
 create mode 100644 doc/guides/prog_guide/img/efd_i1.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i10.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i11.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i12.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i2.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i3.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i4.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i5.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i6.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i7.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i8.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i9.svg
 create mode 100644 doc/guides/sample_app_ug/flow_distributor.rst
 create mode 100644 doc/guides/sample_app_ug/img/flow_distributor.svg
 create mode 100644 examples/flow_distributor/Makefile
 create mode 100644 examples/flow_distributor/distributor/Makefile
 create mode 100644 examples/flow_distributor/distributor/args.c
 create mode 100644 examples/flow_distributor/distributor/args.h
 create mode 100644 examples/flow_distributor/distributor/init.c
 create mode 100644 examples/flow_distributor/distributor/init.h
 create mode 100644 examples/flow_distributor/distributor/main.c
 create mode 100644 examples/flow_distributor/node/Makefile
 create mode 100644 examples/flow_distributor/node/node.c
 create mode 100644 examples/flow_distributor/shared/common.h
 create mode 100644 lib/librte_efd/Makefile
 create mode 100644 lib/librte_efd/rte_efd.c
 create mode 100644 lib/librte_efd/rte_efd.h
 create mode 100644 lib/librte_efd/rte_efd_version.map

-- 
2.7.4

^ permalink raw reply

* [PATCH v3 1/5] efd: new Elastic Flow Distributor library
From: Pablo de Lara @ 2017-01-12 22:15 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Byron Marohn, Saikrishna Edupuganti
In-Reply-To: <1484259360-198276-1-git-send-email-pablo.de.lara.guarch@intel.com>

Elastic Flow Distributor (EFD) is a distributor library that uses
perfect hashing to determine a target/value for a given incoming flow key.
It has the following advantages:

- First, because it uses perfect hashing, it does not store
  the key itself and hence lookup performance is not dependent
  on the key size.

- Second, the target/value can be any arbitrary value hence
  the system designer and/or operator can better optimize service rates
  and inter-cluster network traffic locating.

- Third, since the storage requirement is much smaller than a hash-based
  flow table (i.e. better fit for CPU cache), EFD can scale to
  millions of flow keys.
  Finally, with current optimized library implementation performance
  is fully scalable with number of CPU cores.

Signed-off-by: Byron Marohn <byron.marohn@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
Acked-by: Christian Maciocco <christian.maciocco@intel.com>
---
 MAINTAINERS                             |    5 +
 config/common_base                      |    5 +
 doc/api/doxy-api-index.md               |    3 +-
 doc/api/doxy-api.conf                   |    1 +
 doc/guides/rel_notes/release_17_02.rst  |   12 +
 lib/Makefile                            |    3 +-
 lib/librte_eal/common/include/rte_log.h |    3 +-
 lib/librte_efd/Makefile                 |   56 ++
 lib/librte_efd/rte_efd.c                | 1354 +++++++++++++++++++++++++++++++
 lib/librte_efd/rte_efd.h                |  294 +++++++
 lib/librte_efd/rte_efd_version.map      |   12 +
 mk/rte.app.mk                           |    3 +-
 12 files changed, 1747 insertions(+), 4 deletions(-)
 create mode 100644 lib/librte_efd/Makefile
 create mode 100644 lib/librte_efd/rte_efd.c
 create mode 100644 lib/librte_efd/rte_efd.h
 create mode 100644 lib/librte_efd/rte_efd_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 9645c9b..9c60d67 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -528,6 +528,11 @@ F: app/test/test_acl.*
 F: examples/l3fwd-acl/
 F: doc/guides/sample_app_ug/l3_forward_access_ctrl.rst
 
+EFD
+M: Byron Marohn <byron.marohn@intel.com>
+M: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>
+F: lib/librte_efd/
+
 Hashes
 M: Bruce Richardson <bruce.richardson@intel.com>
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
diff --git a/config/common_base b/config/common_base
index 8e9dcfa..869d8fb 100644
--- a/config/common_base
+++ b/config/common_base
@@ -467,6 +467,11 @@ CONFIG_RTE_LIBRTE_HASH=y
 CONFIG_RTE_LIBRTE_HASH_DEBUG=n
 
 #
+# Compile librte_efd
+#
+CONFIG_RTE_LIBRTE_EFD=y
+
+#
 # Compile librte_jobstats
 #
 CONFIG_RTE_LIBRTE_JOBSTATS=y
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 72d59b2..0d34e2f 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -90,7 +90,8 @@ There are many libraries, so their headers may be grouped by topics:
   [frag/reass]         (@ref rte_ip_frag.h),
   [LPM IPv4 route]     (@ref rte_lpm.h),
   [LPM IPv6 route]     (@ref rte_lpm6.h),
-  [ACL]                (@ref rte_acl.h)
+  [ACL]                (@ref rte_acl.h),
+  [EFD]                (@ref rte_efd.h)
 
 - **QoS**:
   [metering]           (@ref rte_meter.h),
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index b340fcf..6892315 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -40,6 +40,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_compat \
                           lib/librte_cryptodev \
                           lib/librte_distributor \
+                          lib/librte_efd \
                           lib/librte_ether \
                           lib/librte_hash \
                           lib/librte_ip_frag \
diff --git a/doc/guides/rel_notes/release_17_02.rst b/doc/guides/rel_notes/release_17_02.rst
index 180af82..5023038 100644
--- a/doc/guides/rel_notes/release_17_02.rst
+++ b/doc/guides/rel_notes/release_17_02.rst
@@ -53,6 +53,18 @@ New Features
   information.
 
 
+* **Added Elastic Flow Distributor library (rte_efd).**
+
+  This new library uses perfect hashing to determine a target/value for a
+  given incoming flow key.
+
+  It does not store the key itself for lookup operations, and therefore,
+  lookup performance is not dependent on the key size. Also, the target/value
+  can be any arbitrary value (8 bits by default). Finally, the storage requirement
+  is much smaller than a hash-based flow table and therefore, it can better fit for
+  CPU cache, being able to scale to millions of flow keys.
+
+
 Resolved Issues
 ---------------
 
diff --git a/lib/Makefile b/lib/Makefile
index 990f23a..4178325 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_EFD) += librte_efd
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 671e274..954b96c 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_EFD     0x00040000 /**< Log related to EFD. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/lib/librte_efd/Makefile b/lib/librte_efd/Makefile
new file mode 100644
index 0000000..58d34af
--- /dev/null
+++ b/lib/librte_efd/Makefile
@@ -0,0 +1,56 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_efd.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+EXPORT_MAP := rte_efd_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_EFD) := rte_efd.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_EFD)-include := rte_efd.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_efd/rte_efd.c b/lib/librte_efd/rte_efd.c
new file mode 100644
index 0000000..917e076
--- /dev/null
+++ b/lib/librte_efd/rte_efd.c
@@ -0,0 +1,1354 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <immintrin.h>
+#include <math.h>
+#include <sys/queue.h>
+
+#include <rte_log.h>
+#include <rte_eal_memconfig.h>
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_prefetch.h>
+#include <rte_branch_prediction.h>
+#include <rte_memcpy.h>
+#include <rte_ring.h>
+#include <rte_jhash.h>
+#include <rte_hash_crc.h>
+
+#include "rte_efd.h"
+
+#define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len))
+/** Hash function used to determine chunk_id and bin_id for a group */
+#define EFD_HASH(key, table) \
+	(uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34))
+/** Hash function used as constant component of perfect hash search */
+#define EFD_HASHFUNCA(key, table) \
+	(uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35))
+/** Hash function used as multiplicative component of perfect hash search */
+#define EFD_HASHFUNCB(key, table) \
+	(uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36))
+
+/*************************************************************************
+ * Fixed constants
+ *************************************************************************/
+
+/* These parameters are fixed by the efd_bin_to_group balancing table */
+#define EFD_CHUNK_NUM_GROUPS (64)
+#define EFD_CHUNK_NUM_BINS   (256)
+#define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \
+	(EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
+
+/*
+ * Target number of rules that each chunk is created to handle.
+ * Used when initially allocating the table
+ */
+#define EFD_TARGET_CHUNK_NUM_RULES  \
+	(EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
+/*
+ * Max number of rules that each chunk is created to handle.
+ * Used when initially allocating the table
+ */
+#define EFD_TARGET_CHUNK_MAX_NUM_RULES  \
+	(EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES)
+
+/** This is fixed based on the bin_to_group permutation array */
+#define EFD_MAX_GROUP_NUM_BINS (16)
+
+/**
+ * The end of the chunks array needs some extra padding to ensure
+ * that vectorization over-reads on the last online chunk stay within
+allocated memory
+ */
+#define EFD_NUM_CHUNK_PADDING_BYTES (256)
+
+#define EFD_LOOKUPTBL_SHIFT (32 - 4)
+typedef uint16_t efd_lookuptbl_t;
+typedef uint16_t efd_hashfunc_t;
+
+/* All different signature compare functions */
+enum rte_efd_compare_function {
+	RTE_HASH_COMPARE_SCALAR = 0,
+	RTE_HASH_COMPARE_AVX2,
+	RTE_HASH_COMPARE_NUM
+};
+
+TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_efd_tailq = {
+	.name = "RTE_EFD",
+};
+EAL_REGISTER_TAILQ(rte_efd_tailq);
+
+/** Internal permutation array used to shuffle bins into pseudorandom groups */
+const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
+	{
+		0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+		4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+		8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+		12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+		16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+		20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+		24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+		28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+		32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+		36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+		40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+		44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+		48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
+		52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
+		56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
+		60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
+	},
+	{
+		34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
+		44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
+		46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
+		1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
+		6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
+		51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
+		54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
+		45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
+		13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
+		56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
+		2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
+		22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
+		0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
+		53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
+		63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
+		49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
+	},
+	{
+		32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
+		55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
+		40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
+		41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
+		13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
+		38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
+		5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
+		24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
+		25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
+		57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
+		13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
+		33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
+		8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
+		18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
+		47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
+		6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
+	},
+	{
+		29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
+		59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
+		35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
+		13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
+		55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
+		17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
+		14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
+		39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
+		55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
+		31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
+		27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
+		47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
+		29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
+		35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
+		38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
+		24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
+	},
+};
+
+/*************************************************************************
+ * Offline region structures
+ *************************************************************************/
+
+/** Online group containing number of rules, values, keys and their bins
+ * for EFD_MAX_GROUP_NUM_RULES rules.
+ */
+struct efd_offline_group_rules {
+	uint32_t num_rules;
+	/**< Sum of the number of rules in all bins assigned to this group. */
+
+	uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES];
+	/**< Array with all keys of the group. */
+	efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
+	/**< Array with all values of the keys of the group. */
+
+	uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
+	/**< Stores the bin for each correspending key to
+	 * avoid having to recompute it
+	 */
+};
+
+/** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
+ * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
+ */
+struct efd_offline_chunk_rules {
+	uint16_t num_rules;
+	/**< Number of rules in the entire chunk;
+	 * used to detect unbalanced groups
+	 */
+
+	struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
+	/**< Array of all groups in the chunk. */
+};
+
+/*************************************************************************
+ * Online region structures
+ *************************************************************************/
+
+/** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
+struct efd_online_group_entry {
+	efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS];
+	efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS];
+} __attribute__((__packed__));
+
+/**
+ * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
+ * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
+ */
+struct efd_online_chunk {
+	uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
+	/**< This is a packed indirection index into the 'groups' array.
+	 * Each byte contains four two-bit values which index into
+	 * the efd_bin_to_group array.
+	 * The efd_bin_to_group array returns the index into the groups array
+	 */
+
+	struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
+	/**< Array of all the groups in the chunk. */
+} __attribute__((__packed__));
+
+/**
+ * EFD table structure
+ */
+struct rte_efd_table {
+	char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
+
+	uint32_t key_len; /**< Length of the key stored offline */
+
+	uint32_t max_num_rules;
+	/**< Static maximum number of entries the table was constructed to hold. */
+
+	uint32_t num_rules;
+	/**< Number of entries currently in the table . */
+
+	uint32_t num_chunks;
+	/**< Number of chunks in the table needed to support num_rules. */
+
+	uint32_t num_chunks_shift;
+	/**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
+
+	enum rte_efd_compare_function cmp_fn;
+	/**< Indicates which compare function to use. */
+
+	struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
+	/**< Dynamic array of size num_chunks of chunk records. */
+
+	struct efd_offline_chunk_rules *offline_chunks;
+	/**< Dynamic array of size num_chunks of key-value pairs. */
+
+	struct rte_ring *free_slots;
+	/**< Ring that stores all indexes of the free slots in the key table */
+
+	uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */
+};
+
+/**
+ * Computes the chunk ID for a given key hash
+ *
+ * @param table
+ *   EFD table to reference
+ * @param hashed_key
+ *   32-bit key hash returned by EFD_HASH
+ *
+ * @return
+ *   chunk ID containing this key hash
+ */
+static inline uint32_t
+efd_get_chunk_id(const struct rte_efd_table * const table,
+		const uint32_t hashed_key)
+{
+	return hashed_key & (table->num_chunks - 1);
+}
+
+/**
+ * Computes the bin ID for a given key hash
+ *
+ * @param table
+ *   EFD table to reference
+ * @param hashed_key
+ *   32-bit key hash returned by EFD_HASH
+ *
+ * @return bin ID containing this key hash
+ */
+static inline uint32_t
+efd_get_bin_id(const struct rte_efd_table * const table,
+		const uint32_t hashed_key)
+{
+	return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
+}
+
+/**
+ * Looks up the current permutation choice for a particular bin in the online table
+ *
+ * @param table
+ *  EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to look up existing values (ideally caller's socket id)
+ * @param chunk_id
+ *   Chunk ID of bin to look up
+ * @param bin_id
+ *   Bin ID to look up
+ *
+ * @return
+ *   Currently active permutation choice in the online table
+ */
+static inline uint8_t
+efd_get_choice(const struct rte_efd_table * const table,
+		const unsigned int socket_id, const uint32_t chunk_id,
+		const uint32_t bin_id)
+{
+	struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
+
+	/*
+	 * Grab the chunk (byte) that contains the choices
+	 * for four neighboring bins.
+	 */
+	uint8_t choice_chunk =
+			chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
+
+	/*
+	 * Compute the offset into the chunk that contains
+	 * the group_id lookup position
+	 */
+	int offset = (bin_id & 0x3) * 2;
+
+	/* Extract from the byte just the desired lookup position */
+	return (uint8_t) ((choice_chunk >> offset) & 0x3);
+}
+
+/**
+ * Compute the chunk_id and bin_id for a given key
+ *
+ * @param table
+ *   EFD table to reference
+ * @param key
+ *   Key to hash and find location of
+ * @param chunk_id
+ *   Computed chunk ID
+ * @param bin_id
+ *   Computed bin ID
+ *
+ */
+static inline void
+efd_compute_ids(const struct rte_efd_table * const table,
+		const void *key, uint32_t * const chunk_id, uint32_t * const bin_id)
+{
+	/* Compute the position of the entry in the hash table */
+	uint32_t h = EFD_HASH(key, table);
+
+	/* Compute the chunk_id where that entry can be found */
+	*chunk_id = efd_get_chunk_id(table, h);
+
+	/*
+	 * Compute the bin within that chunk where the entry
+	 * can be found (0 - 255)
+	 */
+	*bin_id = efd_get_bin_id(table, h);
+}
+
+/**
+ * Search for a hash function for a group that satisfies all group results
+ */
+static inline int
+efd_search_hash(struct rte_efd_table * const table,
+		const struct efd_offline_group_rules * const off_group,
+		struct efd_online_group_entry * const on_group)
+{
+	efd_hashfunc_t hash_idx;
+	efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS];
+	efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS];
+
+	uint32_t i, j, rule_id;
+	uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
+	uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
+	uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
+
+
+	rte_prefetch0(off_group->value);
+
+	/*
+	 * Prepopulate the hash_val tables by running the two hash functions
+	 * for each provided rule
+	 */
+	for (i = 0; i < off_group->num_rules; i++) {
+		void *key_stored = EFD_KEY(off_group->key_idx[i], table);
+		hash_val_b[i] = EFD_HASHFUNCB(key_stored, table);
+		hash_val_a[i] = EFD_HASHFUNCA(key_stored, table);
+	}
+
+	for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
+		hash_idx = on_group->hash_idx[i];
+		start_hash_idx[i] = hash_idx;
+		start_lookup_table[i] = on_group->lookup_table[i];
+
+		do {
+			efd_lookuptbl_t lookup_table = 0;
+			efd_lookuptbl_t lookup_table_complement = 0;
+
+			for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
+				hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
+					hash_val_b[rule_id]);
+
+			/*
+			 * The goal here is to find a hash function for this
+			 * particular bit entry that meets the following criteria:
+			 * The most significant bits of the hash result define a
+			 * shift into the lookup table where the bit will be stored
+			 */
+
+			/* Iterate over each provided rule */
+			for (rule_id = 0; rule_id < off_group->num_rules;
+					rule_id++) {
+				/*
+				 * Use the few most significant bits (number based on
+				 * EFD_LOOKUPTBL_SIZE) to see what position the
+				 * expected bit should be set in the lookup_table
+				 */
+				uint32_t bucket_idx = hash_val[rule_id] >>
+						EFD_LOOKUPTBL_SHIFT;
+
+				/*
+				 * Get the current bit of interest.
+				 * This only find an appropriate hash function
+				 * for one bit at a time of the rule
+				 */
+				efd_lookuptbl_t expected =
+						(off_group->value[rule_id] >> i) & 0x1;
+
+				/*
+				 * Add the expected bit (if set) to a map
+				 * (lookup_table). Also set its complement
+				 * in lookup_table_complement
+				 */
+				lookup_table |= expected << bucket_idx;
+				lookup_table_complement |= (1 - expected)
+						<< bucket_idx;
+
+				/*
+				 * If ever the hash function of two different
+				 * elements result in different values at the
+				 * same location in the lookup_table,
+				 * the current hash_idx is not valid.
+				 */
+				if (lookup_table & lookup_table_complement)
+					break;
+			}
+
+			/*
+			 * Check if the previous loop completed without
+			 * breaking early
+			 */
+			if (rule_id == off_group->num_rules) {
+				/*
+				 * Current hash function worked, store it
+				 * for the current group
+				 */
+				on_group->hash_idx[i] = hash_idx;
+				on_group->lookup_table[i] = lookup_table;
+
+				/*
+				 * Make sure that the hash function has changed
+				 * from the starting value
+				 */
+				hash_idx = start_hash_idx[i] + 1;
+				break;
+			}
+			hash_idx++;
+
+		} while (hash_idx != start_hash_idx[i]);
+
+		/* Failed to find perfect hash for this group */
+		if (hash_idx == start_hash_idx[i]) {
+			/*
+			 * Restore previous hash_idx and lookup_table
+			 * for all value bits
+			 */
+			for (j = 0; j < i; j++) {
+				on_group->hash_idx[j] = start_hash_idx[j];
+				on_group->lookup_table[j] = start_lookup_table[j];
+			}
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+struct rte_efd_table *
+rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
+		uint8_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket)
+{
+	struct rte_efd_table *table = NULL;
+	uint8_t *key_array = NULL;
+	uint32_t num_chunks, num_chunks_shift;
+	uint8_t socket_id;
+	struct rte_efd_list *efd_list = NULL;
+	struct rte_tailq_entry *te;
+	uint64_t offline_table_size;
+	char ring_name[RTE_RING_NAMESIZE];
+	struct rte_ring *r = NULL;
+	unsigned int i;
+
+	efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
+
+	if (online_cpu_socket_bitmask == 0) {
+		RTE_LOG(ERR, EFD, "At least one CPU socket must be enabled "
+				"in the bitmask\n");
+		return NULL;
+	}
+
+	if (max_num_rules == 0) {
+		RTE_LOG(ERR, EFD, "Max num rules must be higher than 0\n");
+		return NULL;
+	}
+
+	/*
+	 * Compute the minimum number of chunks (smallest power of 2)
+	 * that can hold all of the rules
+	 */
+	if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
+		num_chunks = rte_align32pow2(max_num_rules /
+			EFD_TARGET_CHUNK_NUM_RULES);
+	else
+		num_chunks = rte_align32pow2((max_num_rules /
+			EFD_TARGET_CHUNK_NUM_RULES) + 1);
+
+	num_chunks_shift = log2(num_chunks);
+
+	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+	/*
+	 * Guarantee there's no existing: this is normally already checked
+	 * by ring creation above
+	 */
+	TAILQ_FOREACH(te, efd_list, next)
+	{
+		table = (struct rte_efd_table *) te->data;
+		if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
+			break;
+	}
+
+	table = NULL;
+	if (te != NULL) {
+		rte_errno = EEXIST;
+		te = NULL;
+		goto error_unlock_exit;
+	}
+
+	te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
+	if (te == NULL) {
+		RTE_LOG(ERR, EFD, "tailq entry allocation failed\n");
+		goto error_unlock_exit;
+	}
+
+	/* Create a new EFD table management structure */
+	table = (struct rte_efd_table *) rte_zmalloc_socket(NULL,
+			sizeof(struct rte_efd_table),
+			RTE_CACHE_LINE_SIZE,
+			offline_cpu_socket);
+	if (table == NULL) {
+		RTE_LOG(ERR, EFD, "Allocating EFD table management structure"
+				" on socket %u failed\n",
+				offline_cpu_socket);
+		goto error_unlock_exit;
+	}
+
+
+	RTE_LOG(DEBUG, EFD, "Allocated EFD table management structure "
+			"on socket %u\n", offline_cpu_socket);
+
+	table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES;
+	table->num_rules = 0;
+	table->num_chunks = num_chunks;
+	table->num_chunks_shift = num_chunks_shift;
+	table->key_len = key_len;
+
+	/* key_array */
+	key_array = (uint8_t *) rte_zmalloc_socket(NULL,
+			table->max_num_rules * table->key_len,
+			RTE_CACHE_LINE_SIZE,
+			offline_cpu_socket);
+	if (key_array == NULL) {
+		RTE_LOG(ERR, EFD, "Allocating key array"
+				" on socket %u failed\n",
+				offline_cpu_socket);
+		goto error_unlock_exit;
+	}
+	table->keys = key_array;
+	snprintf(table->name, sizeof(table->name), "%s", name);
+
+	RTE_LOG(DEBUG, EFD, "Creating an EFD table with %u chunks,"
+			" which potentially supports %u entries\n",
+			num_chunks, table->max_num_rules);
+
+	/* Make sure all the allocatable table pointers are NULL initially */
+	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
+		table->chunks[socket_id] = NULL;
+	table->offline_chunks = NULL;
+
+	/*
+	 * Allocate one online table per socket specified
+	 * in the user-supplied bitmask
+	 */
+	uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
+			EFD_NUM_CHUNK_PADDING_BYTES;
+
+	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
+		if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
+			/*
+			 * Allocate all of the EFD table chunks (the online portion)
+			 * as a continuous block
+			 */
+			table->chunks[socket_id] =
+				(struct efd_online_chunk *) rte_zmalloc_socket(
+				NULL,
+				online_table_size,
+				RTE_CACHE_LINE_SIZE,
+				socket_id);
+			if (table->chunks[socket_id] == NULL) {
+				RTE_LOG(ERR, EFD,
+						"Allocating EFD online table on "
+						"socket %u failed\n",
+						socket_id);
+				goto error_unlock_exit;
+			}
+			RTE_LOG(DEBUG, EFD,
+					"Allocated EFD online table of size "
+					"%"PRIu64" bytes (%.2f MB) on socket %u\n",
+					online_table_size,
+					(float) online_table_size /
+						(1024.0F * 1024.0F),
+					socket_id);
+		}
+	}
+
+#if defined(RTE_ARCH_X86)
+	if (RTE_EFD_VALUE_NUM_BITS > 3 && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+		table->cmp_fn = RTE_HASH_COMPARE_AVX2;
+	else
+#endif
+		table->cmp_fn = RTE_HASH_COMPARE_SCALAR;
+
+	/*
+	 * Allocate the EFD table offline portion (with the actual rules
+	 * mapping keys to values) as a continuous block.
+	 * This could be several gigabytes of memory.
+	 */
+	offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
+	table->offline_chunks =
+			(struct efd_offline_chunk_rules *) rte_zmalloc_socket(NULL,
+			offline_table_size,
+			RTE_CACHE_LINE_SIZE,
+			offline_cpu_socket);
+	if (table->offline_chunks == NULL) {
+		RTE_LOG(ERR, EFD, "Allocating EFD offline table on socket %u "
+				"failed\n", offline_cpu_socket);
+		goto error_unlock_exit;
+	}
+
+	RTE_LOG(DEBUG, EFD,
+			"Allocated EFD offline table of size %"PRIu64" bytes "
+			" (%.2f MB) on socket %u\n", offline_table_size,
+			(float) offline_table_size / (1024.0F * 1024.0F),
+			offline_cpu_socket);
+
+	te->data = (void *) table;
+	TAILQ_INSERT_TAIL(efd_list, te, next);
+	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+	snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name);
+	/* Create ring (Dummy slot index is not enqueued) */
+	r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules),
+			offline_cpu_socket, 0);
+	if (r == NULL) {
+		RTE_LOG(ERR, EFD, "memory allocation failed\n");
+		goto error_unlock_exit;
+	}
+
+	/* Populate free slots ring. Entry zero is reserved for key misses. */
+	for (i = 0; i < table->max_num_rules; i++)
+		rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i));
+
+	table->free_slots = r;
+	return table;
+
+error_unlock_exit:
+	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+	rte_efd_free(table);
+
+	return NULL;
+}
+
+struct rte_efd_table *
+rte_efd_find_existing(const char *name)
+{
+	struct rte_efd_table *table = NULL;
+	struct rte_tailq_entry *te;
+	struct rte_efd_list *efd_list;
+
+	efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
+
+	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
+
+	TAILQ_FOREACH(te, efd_list, next)
+	{
+		table = (struct rte_efd_table *) te->data;
+		if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
+			break;
+	}
+	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+	if (te == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+	return table;
+}
+
+void
+rte_efd_free(struct rte_efd_table *table)
+{
+	uint8_t socket_id;
+
+	if (table == NULL)
+		return;
+
+	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
+		rte_free(table->chunks[socket_id]);
+
+	rte_ring_free(table->free_slots);
+	rte_free(table->offline_chunks);
+	rte_free(table->keys);
+	rte_free(table);
+}
+
+/**
+ * Applies a previously computed table entry to the specified table for all
+ * socket-local copies of the online table.
+ * Intended to apply an update for only a single change
+ * to a key/value pair at a time
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing values (ideally caller's socket id)
+ * @param chunk_id
+ *   Chunk index to update
+ * @param group_id
+ *   Group index to update
+ * @param bin_id
+ *   Bin within the group that this update affects
+ * @param new_bin_choice
+ *   Newly chosen permutation which this bin should use - only lower 2 bits
+ * @param new_group_entry
+ *   Previously computed updated chunk/group entry
+ */
+static inline void
+efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id,
+		const uint32_t chunk_id, const uint32_t group_id,
+		const uint32_t bin_id, const uint8_t new_bin_choice,
+		const struct efd_online_group_entry * const new_group_entry)
+{
+	int i;
+	struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
+	uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
+
+	/*
+	 * Grab the current byte that contains the choices
+	 * for four neighboring bins
+	 */
+	uint8_t choice_chunk =
+			chunk->bin_choice_list[bin_index];
+
+
+	/* Compute the offset into the chunk that needs to be updated */
+	int offset = (bin_id & 0x3) * 2;
+
+	/* Zero the two bits of interest and set them to new_bin_choice */
+	choice_chunk = (choice_chunk & (~(0x03 << offset)))
+			| ((new_bin_choice & 0x03) << offset);
+
+	/* Update the online table with the new data across all sockets */
+	for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
+		if (table->chunks[i] != NULL) {
+			memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
+					new_group_entry,
+					sizeof(struct efd_online_group_entry));
+			table->chunks[i][chunk_id].bin_choice_list[bin_index] =
+					choice_chunk;
+		}
+	}
+}
+
+/*
+ * Move the bin from prev group to the new group
+ */
+static inline void
+move_groups(uint32_t bin_id, uint8_t bin_size,
+		struct efd_offline_group_rules *new_group,
+		struct efd_offline_group_rules * const current_group)
+{
+
+	uint8_t empty_idx = 0;
+	unsigned int i;
+
+	if (new_group == current_group)
+		return;
+
+	for (i = 0; i < current_group->num_rules; i++) {
+		/*
+		 * Move keys that belong to the same bin
+		 * to the new group
+		 */
+		if (current_group->bin_id[i] == bin_id) {
+			new_group->key_idx[new_group->num_rules] =
+					current_group->key_idx[i];
+			new_group->value[new_group->num_rules] =
+					current_group->value[i];
+			new_group->bin_id[new_group->num_rules] =
+					current_group->bin_id[i];
+			new_group->num_rules++;
+		} else {
+			if (i != empty_idx) {
+				/*
+				 * Need to move this key towards
+				 * the top of the array
+				 */
+				current_group->key_idx[empty_idx] =
+						current_group->key_idx[i];
+				current_group->value[empty_idx] =
+						current_group->value[i];
+				current_group->bin_id[empty_idx] =
+						current_group->bin_id[i];
+			}
+			empty_idx++;
+		}
+
+	}
+	current_group->num_rules -= bin_size;
+}
+
+/*
+ * Revert group/s to their previous state before
+ * trying to insert/add a new key
+ */
+static inline void
+revert_groups(struct efd_offline_group_rules *previous_group,
+		struct efd_offline_group_rules *current_group, uint8_t bin_size)
+{
+	unsigned int i;
+
+	if (current_group == previous_group)
+		return;
+
+	/* Move keys back to previous group */
+	for (i = current_group->num_rules - bin_size;
+			i < current_group->num_rules; i++) {
+		previous_group->key_idx[previous_group->num_rules] =
+				current_group->key_idx[i];
+		previous_group->value[previous_group->num_rules] =
+				current_group->value[i];
+		previous_group->bin_id[previous_group->num_rules] =
+				current_group->bin_id[i];
+		previous_group->num_rules++;
+	}
+
+	/*
+	 * Decrease number of rules after the move
+	 * in the new group
+	 */
+	current_group->num_rules -= bin_size;
+}
+
+/**
+ * Computes an updated table entry where the supplied key points to a new host.
+ * If no entry exists, one is inserted.
+ *
+ * This function does NOT modify the online table(s)
+ * This function DOES modify the offline table
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing values (ideally caller's socket id)
+ * @param key
+ *   Key to insert
+ * @param value
+ *   Value to associate with key
+ * @param chunk_id
+ *   Chunk ID of the chunk that was modified
+ * @param group_id
+ *   Group ID of the group that was modified
+ * @param bin_id
+ *   Bin ID that was modified
+ * @param new_bin_choice
+ *   Newly chosen permutation which this bin will use
+ * @param entry
+ *   Newly computed online entry to apply later with efd_apply_update
+ *
+ * @return
+ *   RTE_EFD_UPDATE_WARN_GROUP_FULL
+ *     Operation is insert, and the last available space in the
+ *     key's group was just used. Future inserts may fail as groups fill up.
+ *     This operation was still successful, and entry contains a valid update
+ *   RTE_EFD_UPDATE_FAILED
+ *     Either the EFD failed to find a suitable perfect hash or the group was full
+ *     This is a fatal error, and the table is now in an indeterminite state
+ *   RTE_EFD_UPDATE_NO_CHANGE
+ *     Operation resulted in no change to the table (same value already exists)
+ *   0
+ *     Insert or update was successful, and the new efd_online_group_entry
+ *     is stored in *entry
+ *
+ * @warning
+ *   Note that entry will be UNCHANGED if the update has no effect, and thus any
+ *   subsequent use of the entry content will likely be invalid
+ */
+static inline int
+efd_compute_update(struct rte_efd_table * const table,
+		const unsigned int socket_id, const void *key,
+		const efd_value_t value, uint32_t * const chunk_id,
+		uint32_t * const group_id, uint32_t * const bin_id,
+		uint8_t * const new_bin_choice,
+		struct efd_online_group_entry * const entry)
+{
+	unsigned int i;
+	int ret;
+	uint32_t new_idx;
+	void *new_k, *slot_id = NULL;
+	int status = EXIT_SUCCESS;
+	unsigned int found = 0;
+
+	efd_compute_ids(table, key, chunk_id, bin_id);
+
+	struct efd_offline_chunk_rules * const chunk =
+			&table->offline_chunks[*chunk_id];
+	struct efd_offline_group_rules *new_group;
+
+	uint8_t current_choice = efd_get_choice(table, socket_id,
+			*chunk_id, *bin_id);
+	uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
+	struct efd_offline_group_rules * const current_group =
+			&chunk->group_rules[current_group_id];
+	uint8_t bin_size = 0;
+	uint8_t key_changed_index = 0;
+	efd_value_t key_changed_previous_value = 0;
+	uint32_t key_idx_previous = 0;
+
+	/* Scan the current group and see if the key is already present */
+	for (i = 0; i < current_group->num_rules; i++) {
+		if (current_group->bin_id[i] == *bin_id)
+			bin_size++;
+		else
+			continue;
+
+		void *key_stored = EFD_KEY(current_group->key_idx[i], table);
+		if (found == 0 && unlikely(memcmp(key_stored, key,
+				table->key_len) == 0)) {
+			/* Key is already present */
+
+			/*
+			 * If previous value is same as new value,
+			 * no additional work is required
+			 */
+			if (current_group->value[i] == value)
+				return RTE_EFD_UPDATE_NO_CHANGE;
+
+			key_idx_previous = current_group->key_idx[i];
+			key_changed_previous_value = current_group->value[i];
+			key_changed_index = i;
+			current_group->value[i] = value;
+			found = 1;
+		}
+	}
+
+	if (found == 0) {
+		/* Key does not exist. Insert the rule into the bin/group */
+		if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
+			RTE_LOG(ERR, EFD,
+					"Fatal: No room remaining for insert into "
+					"chunk %u group %u bin %u\n",
+					*chunk_id,
+					current_group_id, *bin_id);
+			return RTE_EFD_UPDATE_FAILED;
+		}
+
+		if (unlikely(current_group->num_rules ==
+				(EFD_MAX_GROUP_NUM_RULES - 1))) {
+			RTE_LOG(INFO, EFD, "Warn: Insert into last "
+					"available slot in chunk %u "
+					"group %u bin %u\n", *chunk_id,
+					current_group_id, *bin_id);
+			status = RTE_EFD_UPDATE_WARN_GROUP_FULL;
+		}
+
+		if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0)
+			return RTE_EFD_UPDATE_FAILED;
+
+		new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id *
+					table->key_len);
+		rte_prefetch0(new_k);
+		new_idx = (uint32_t) ((uintptr_t) slot_id);
+
+		rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len);
+		current_group->key_idx[current_group->num_rules] = new_idx;
+		current_group->value[current_group->num_rules] = value;
+		current_group->bin_id[current_group->num_rules] = *bin_id;
+		current_group->num_rules++;
+		table->num_rules++;
+		bin_size++;
+	} else {
+		uint32_t last = current_group->num_rules - 1;
+		/* Swap the key with the last key inserted*/
+		current_group->key_idx[key_changed_index] =
+				current_group->key_idx[last];
+		current_group->value[key_changed_index] =
+				current_group->value[last];
+		current_group->bin_id[key_changed_index] =
+				current_group->bin_id[last];
+
+		/*
+		 * Key to be updated will always be available
+		 * at the end of the group
+		 */
+		current_group->key_idx[last] = key_idx_previous;
+		current_group->value[last] = value;
+		current_group->bin_id[last] = *bin_id;
+	}
+
+	*new_bin_choice = current_choice;
+	*group_id = current_group_id;
+	new_group = current_group;
+
+	/* Group need to be rebalanced when it starts to get loaded */
+	if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
+
+		/*
+		 * Subtract the number of entries in the bin from
+		 * the original group
+		 */
+		current_group->num_rules -= bin_size;
+
+		/*
+		 * Figure out which of the available groups that this bin
+		 * can map to is the smallest (using the current group
+		 * as baseline)
+		 */
+		uint8_t smallest_choice = current_choice;
+		uint8_t smallest_size = current_group->num_rules;
+		uint32_t smallest_group_id = current_group_id;
+		unsigned char choice;
+
+		for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
+				choice++) {
+			uint32_t test_group_id =
+					efd_bin_to_group[choice][*bin_id];
+			uint32_t num_rules =
+					chunk->group_rules[test_group_id].num_rules;
+			if (num_rules < smallest_size) {
+				smallest_choice = choice;
+				smallest_size = num_rules;
+				smallest_group_id = test_group_id;
+			}
+		}
+
+		*new_bin_choice = smallest_choice;
+		*group_id = smallest_group_id;
+		new_group = &chunk->group_rules[smallest_group_id];
+		current_group->num_rules += bin_size;
+
+	}
+
+	uint8_t choice = 0;
+	for (;;) {
+		if (current_group != new_group &&
+				new_group->num_rules + bin_size >
+					EFD_MAX_GROUP_NUM_RULES) {
+			RTE_LOG(DEBUG, EFD,
+					"Unable to move_groups to dest group "
+					"containing %u entries."
+					"bin_size:%u choice:%02x\n",
+					new_group->num_rules, bin_size,
+					choice - 1);
+			goto next_choice;
+		}
+		move_groups(*bin_id, bin_size, new_group, current_group);
+		/*
+		 * Recompute the hash function for the modified group,
+		 * and return it to the caller
+		 */
+		ret = efd_search_hash(table, new_group, entry);
+
+		if (!ret)
+			return status;
+
+		RTE_LOG(DEBUG, EFD,
+				"Failed to find perfect hash for group "
+				"containing %u entries. bin_size:%u choice:%02x\n",
+				new_group->num_rules, bin_size, choice - 1);
+		/* Restore groups modified to their previous state */
+		revert_groups(current_group, new_group, bin_size);
+
+next_choice:
+		if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS)
+			break;
+		*new_bin_choice = choice;
+		*group_id = efd_bin_to_group[choice][*bin_id];
+		new_group = &chunk->group_rules[*group_id];
+		choice++;
+	}
+
+	if (!found) {
+		current_group->num_rules--;
+		table->num_rules--;
+	} else
+		current_group->value[current_group->num_rules - 1] =
+			key_changed_previous_value;
+	return RTE_EFD_UPDATE_FAILED;
+}
+
+int
+rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id,
+		const void *key, const efd_value_t value)
+{
+	uint32_t chunk_id = 0, group_id = 0, bin_id = 0;
+	uint8_t new_bin_choice = 0;
+	struct efd_online_group_entry entry;
+
+	int status = efd_compute_update(table, socket_id, key, value,
+			&chunk_id, &group_id, &bin_id,
+			&new_bin_choice, &entry);
+
+	if (status == RTE_EFD_UPDATE_NO_CHANGE)
+		return EXIT_SUCCESS;
+
+	if (status == RTE_EFD_UPDATE_FAILED)
+		return status;
+
+	efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
+			new_bin_choice, &entry);
+	return status;
+}
+
+int
+rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id,
+		const void *key, efd_value_t * const prev_value)
+{
+	unsigned int i;
+	uint32_t chunk_id, bin_id;
+	uint8_t not_found = 1;
+
+	efd_compute_ids(table, key, &chunk_id, &bin_id);
+
+	struct efd_offline_chunk_rules * const chunk =
+			&table->offline_chunks[chunk_id];
+
+	uint8_t current_choice = efd_get_choice(table, socket_id,
+			chunk_id, bin_id);
+	uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
+	struct efd_offline_group_rules * const current_group =
+			&chunk->group_rules[current_group_id];
+
+	/*
+	 * Search the current group for the specified key.
+	 * If it exists, remove it and re-pack the other values
+	 */
+	for (i = 0; i < current_group->num_rules; i++) {
+		if (not_found) {
+			/* Found key that needs to be removed */
+			if (memcmp(EFD_KEY(current_group->key_idx[i], table),
+					key, table->key_len) == 0) {
+				/* Store previous value if requested by caller */
+				if (prev_value != NULL)
+					*prev_value = current_group->value[i];
+
+				not_found = 0;
+				rte_ring_sp_enqueue(table->free_slots,
+					(void *)((uintptr_t)current_group->key_idx[i]));
+			}
+		} else {
+			/*
+			 * If the desired key has been found,
+			 * need to shift other values up one
+			 */
+
+			/* Need to shift this entry back up one index */
+			current_group->key_idx[i - 1] = current_group->key_idx[i];
+			current_group->value[i - 1] = current_group->value[i];
+			current_group->bin_id[i - 1] = current_group->bin_id[i];
+		}
+	}
+
+	if (not_found == 0) {
+		table->num_rules--;
+		current_group->num_rules--;
+	}
+
+	return not_found;
+}
+
+
+#if (RTE_EFD_VALUE_NUM_BITS == 8 || RTE_EFD_VALUE_NUM_BITS == 16 || \
+	RTE_EFD_VALUE_NUM_BITS == 24 || RTE_EFD_VALUE_NUM_BITS == 32)
+#define EFD_LOAD_SI128(val) _mm_load_si128(val)
+#else
+#define EFD_LOAD_SI128(val) _mm_lddqu_si128(val)
+#endif
+
+static inline efd_value_t
+efd_lookup_internal(const struct efd_online_group_entry * const group,
+		const uint32_t hash_val_a, const uint32_t hash_val_b,
+		enum rte_efd_compare_function cmp_fn)
+{
+	efd_value_t value = 0;
+	uint32_t i;
+
+	switch (cmp_fn) {
+#ifdef RTE_MACHINE_CPUFLAG_AVX2
+	case RTE_HASH_COMPARE_AVX2:
+
+		i = 0;
+		__m256i vhash_val_a = _mm256_set1_epi32(hash_val_a);
+		__m256i vhash_val_b = _mm256_set1_epi32(hash_val_b);
+
+		for (; i < RTE_EFD_VALUE_NUM_BITS; i += 8) {
+			__m256i vhash_idx =
+					_mm256_cvtepu16_epi32(EFD_LOAD_SI128(
+					(__m128i const *) &group->hash_idx[i]));
+			__m256i vlookup_table = _mm256_cvtepu16_epi32(
+					EFD_LOAD_SI128((__m128i const *)
+					&group->lookup_table[i]));
+			__m256i vhash = _mm256_add_epi32(vhash_val_a,
+					_mm256_mullo_epi32(vhash_idx, vhash_val_b));
+			__m256i vbucket_idx = _mm256_srli_epi32(vhash,
+					EFD_LOOKUPTBL_SHIFT);
+			__m256i vresult = _mm256_srlv_epi32(vlookup_table,
+					vbucket_idx);
+
+			value |= (_mm256_movemask_ps(
+				(__m256) _mm256_slli_epi32(vresult, 31))
+				& ((1 << (RTE_EFD_VALUE_NUM_BITS - i)) - 1)) << i;
+		}
+		break;
+#endif
+	default:
+
+		i = 0;
+		for (; i < RTE_EFD_VALUE_NUM_BITS; i++) {
+			value <<= 1;
+
+			uint32_t h = hash_val_a + (hash_val_b *
+				group->hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]);
+			uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
+
+			value |= (group->lookup_table[
+					RTE_EFD_VALUE_NUM_BITS - i - 1] >>
+					bucket_idx) & 0x1;
+		}
+	}
+	return value;
+}
+
+efd_value_t
+rte_efd_lookup(const struct rte_efd_table * const table,
+		const unsigned int socket_id, const void *key)
+{
+	uint32_t chunk_id, group_id, bin_id;
+	uint8_t bin_choice;
+	const struct efd_online_group_entry *group;
+	const struct efd_online_chunk * const chunks = table->chunks[socket_id];
+
+	/* Determine the chunk and group location for the given key */
+	efd_compute_ids(table, key, &chunk_id, &bin_id);
+	bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
+	group_id = efd_bin_to_group[bin_choice][bin_id];
+	group = &chunks[chunk_id].groups[group_id];
+
+	return efd_lookup_internal(group,
+			EFD_HASHFUNCA(key, table),
+			EFD_HASHFUNCB(key, table),
+			table->cmp_fn);
+}
+
+void rte_efd_lookup_bulk(const struct rte_efd_table * const table,
+		const unsigned int socket_id, const int num_keys,
+		const void **key_list, efd_value_t * const value_list)
+{
+	int i;
+	uint32_t chunk_id_list[RTE_EFD_BURST_MAX];
+	uint32_t bin_id_list[RTE_EFD_BURST_MAX];
+	uint8_t bin_choice_list[RTE_EFD_BURST_MAX];
+	uint32_t group_id_list[RTE_EFD_BURST_MAX];
+	struct efd_online_group_entry *group;
+
+	struct efd_online_chunk *chunks = table->chunks[socket_id];
+
+	for (i = 0; i < num_keys; i++) {
+		efd_compute_ids(table, key_list[i], &chunk_id_list[i],
+				&bin_id_list[i]);
+		rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
+	}
+
+	for (i = 0; i < num_keys; i++) {
+		bin_choice_list[i] = efd_get_choice(table, socket_id,
+				chunk_id_list[i], bin_id_list[i]);
+		group_id_list[i] =
+				efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
+		group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
+		rte_prefetch0(group);
+	}
+
+	for (i = 0; i < num_keys; i++) {
+		group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
+		value_list[i] = efd_lookup_internal(group,
+				EFD_HASHFUNCA(key_list[i], table),
+				EFD_HASHFUNCB(key_list[i], table),
+				table->cmp_fn);
+	}
+}
diff --git a/lib/librte_efd/rte_efd.h b/lib/librte_efd/rte_efd.h
new file mode 100644
index 0000000..a728096
--- /dev/null
+++ b/lib/librte_efd/rte_efd.h
@@ -0,0 +1,294 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_EFD_H_
+#define _RTE_EFD_H_
+
+/**
+ * @file
+ *
+ * RTE EFD Table
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************************
+ * User selectable constants
+ *************************************************************************/
+
+/*
+ * If possible, best lookup performance will be achieved by ensuring that
+ * the entire table fits in the L3 cache.
+ *
+ * Some formulas for calculating various sizes are listed below:
+ *
+ * # of chunks =
+ *   2 ^ (ceiling(log2((requested # of rules) /
+ *            (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES))))
+ *
+ * Target # of rules = (# of chunks) * EFD_CHUNK_NUM_GROUPS *
+ *            EFD_TARGET_GROUP_NUM_RULES
+ *
+ * Group Size (in bytes) = 4 (per value bit)
+ *
+ * Table size (in bytes) = RTE_EFD_VALUE_NUM_BITS * (# of chunks) *
+ *            EFD_CHUNK_NUM_GROUPS * (group size)
+ */
+
+/**
+ * !!! This parameter should be adjusted for your application !!!
+ *
+ * This parameter adjusts the number of bits of value that can be
+ * stored in the table.
+ * For example, setting the number of bits to 3 will allow storing 8 values
+ * in the table (between 0 and 7).
+ *
+ * This number directly affects the performance of both lookups and insertion.
+ * In general, performance decreases as more bits are stored in the table.
+ *
+ * This number is directly proportional to the size of the online region
+ * used for lookups.
+ *
+ * Note that due to the way the CPU operates on memory, best lookup performance
+ * will be achieved when RTE_EFD_VALUE_NUM_BITS is a multiple of 8.
+ * These values align the hash indexes on 16-byte boundaries.
+ * The greatest performance drop is moving from 8->9 bits, 16->17 bits, etc.
+ *
+ * This value must be between 1 and 32
+ */
+#ifndef RTE_EFD_VALUE_NUM_BITS
+#define RTE_EFD_VALUE_NUM_BITS (8)
+#endif
+
+/*
+ * EFD_TARGET_GROUP_NUM_RULES:
+ *   Adjusts how many groups/chunks are allocated at table creation time
+ *   to support the requested number of rules. Higher values pack entries
+ *   more tightly in memory, resulting in a smaller memory footprint
+ *   for the online table.
+ *   This comes at the cost of lower insert/update performance.
+ *
+ * EFD_MAX_GROUP_NUM_RULES:
+ *   This adjusts the amount of offline memory allocated to store key/value
+ *   pairs for the table. The recommended numbers are upper-bounds for
+ *   this parameter
+ *   - any higher and it becomes very unlikely that a perfect hash function
+ *   can be found for that group size. This value should be at
+ *   least 40% larger than EFD_TARGET_GROUP_NUM_RULES
+ *
+ * Recommended values for various lookuptable and hashfunc sizes are:
+ *
+ *   HASH_FUNC_SIZE = 16, LOOKUPTBL_SIZE = 16:
+ *     EFD_TARGET_GROUP_NUM_RULES = 22
+ *     EFD_MAX_GROUP_NUM_RULES = 28
+ */
+#define EFD_TARGET_GROUP_NUM_RULES (22)
+#define EFD_MAX_GROUP_NUM_RULES (28LU)
+
+#define EFD_MIN_BALANCED_NUM_RULES      5
+
+/**
+ * Maximum number of keys that can be looked up in one call to efd_lookup_bulk
+ */
+#ifndef RTE_EFD_BURST_MAX
+#define RTE_EFD_BURST_MAX (32)
+#endif
+
+/** Maximum number of characters in efd name.*/
+#define RTE_EFD_NAMESIZE			32
+
+#if (RTE_EFD_VALUE_NUM_BITS > 0 && RTE_EFD_VALUE_NUM_BITS <= 8)
+typedef uint8_t efd_value_t;
+#elif (RTE_EFD_VALUE_NUM_BITS > 8 && RTE_EFD_VALUE_NUM_BITS <= 16)
+typedef uint16_t efd_value_t;
+#elif (RTE_EFD_VALUE_NUM_BITS > 16 && RTE_EFD_VALUE_NUM_BITS <= 32)
+typedef uint32_t efd_value_t;
+#else
+#error("RTE_EFD_VALUE_NUM_BITS must be in the range [1:32]")
+#endif
+
+/**
+ * Creates an EFD table with a single offline region and multiple per-socket
+ * internally-managed copies of the online table used for lookups
+ *
+ * @param name
+ *   EFD table name
+ * @param max_num_rules
+ *   Minimum number of rules the table should be sized to hold.
+ *   Will be rounded up to the next smallest valid table size
+ * @param online_cpu_socket_bitmask
+ *   Bitmask specifying which sockets should get a copy of the online table.
+ *   LSB = socket 0, etc.
+ * @param offline_cpu_socket
+ *   Identifies the socket where the offline table will be allocated
+ *   (and most efficiently accessed in the case of updates/insertions)
+ *
+ * @return
+ *   EFD table, or NULL if table allocation failed or the bitmask is invalid
+ */
+struct rte_efd_table *
+rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
+	uint8_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket);
+
+/**
+ * Releases the resources from an EFD table
+ *
+ * @param table
+ *   Table to free
+ */
+void
+rte_efd_free(struct rte_efd_table *table);
+
+/**
+ * Find an existing EFD table object and return a pointer to it.
+ *
+ * @param name
+ *   Name of the EFD table as passed to rte_efd_create()
+ * @return
+ *   Pointer to EFD table or NULL if object not found
+ *   with rte_errno set appropriately. Possible rte_errno values include:
+ *    - ENOENT - value not available for return
+ */
+struct rte_efd_table*
+rte_efd_find_existing(const char *name);
+
+#define RTE_EFD_UPDATE_WARN_GROUP_FULL   (1)
+#define RTE_EFD_UPDATE_NO_CHANGE         (2)
+#define RTE_EFD_UPDATE_FAILED            (3)
+
+/**
+ * Computes an updated table entry for the supplied key/value pair.
+ * The update is then immediately applied to the provided table and
+ * all socket-local copies of the chunks are updated.
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ *   EFD table key to modify
+ * @param value
+ *   Value to associate with the key
+ *
+ * @return
+ *  RTE_EFD_UPDATE_WARN_GROUP_FULL
+ *     Operation is insert, and the last available space in the
+ *     key's group was just used
+ *     Future inserts may fail as groups fill up
+ *     This operation was still successful, and entry contains a valid update
+ *  RTE_EFD_UPDATE_FAILED
+ *     Either the EFD failed to find a suitable perfect hash or the group was full
+ *     This is a fatal error, and the table is now in an indeterminite state
+ *  RTE_EFD_UPDATE_NO_CHANGE
+ *     Operation resulted in no change to the table (same value already exists)
+ *  0 - success
+ */
+int
+rte_efd_update(struct rte_efd_table *table, unsigned int socket_id,
+	const void *key, efd_value_t value);
+
+/**
+ * Removes any value currently associated with the specified key from the table
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ *   EFD table key to delete
+ * @param prev_value
+ *   If not NULL, will store the previous value here before deleting it
+ *
+ * @return
+ *   0 - successfully found and deleted the key
+ *   nonzero otherwise
+ */
+int
+rte_efd_delete(struct rte_efd_table *table, unsigned int socket_id,
+	const void *key, efd_value_t *prev_value);
+
+/**
+ * Looks up the value associated with a key
+ *
+ * NOTE: Lookups will *always* succeed - this is a property of
+ * using a perfect hash table.
+ * If the specified key was never inserted, a pseudorandom answer will be returned.
+ * There is no way to know based on the lookup if the key was ever inserted
+ * originally, so this must be tracked elsewhere.
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ *   EFD table key to look up
+ *
+ * @return
+ *   Value associated with the key, or random junk if they key was never inserted
+ */
+efd_value_t
+rte_efd_lookup(const struct rte_efd_table *table, unsigned int socket_id,
+		const void *key);
+
+/**
+ * Looks up the value associated with several keys.
+ *
+ * NOTE: Lookups will *always* succeed - this is a property of
+ * using a perfect hash table.
+ * If the specified key was never inserted, a pseudorandom answer will be returned.
+ * There is no way to know based on the lookup if the key was ever inserted
+ * originally, so this must be tracked elsewhere.
+ *
+ * @param table
+ *   EFD table to reference
+ * @param socket_id
+ *   Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param num_keys
+ *   Number of keys in the key_list array, must be less than RTE_EFD_BURST_MAX
+ * @param key_list
+ *   Array of num_keys pointers which point to keys to look up
+ * @param value_list
+ *   Array of size num_keys where lookup values will be stored
+ */
+void
+rte_efd_lookup_bulk(const struct rte_efd_table *table, unsigned int socket_id,
+		int num_keys, const void **key_list,
+		efd_value_t *value_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_EFD_H_ */
diff --git a/lib/librte_efd/rte_efd_version.map b/lib/librte_efd/rte_efd_version.map
new file mode 100644
index 0000000..91810b3
--- /dev/null
+++ b/lib/librte_efd/rte_efd_version.map
@@ -0,0 +1,12 @@
+DPDK_17.02 {
+	global:
+
+	rte_efd_create;
+	rte_efd_delete;
+	rte_efd_free;
+	rte_efd_lookup;
+	rte_efd_lookup_bulk;
+	rte_efd_update;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index f75f0e2..ed1e68a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -86,6 +86,7 @@ _LDLIBS-y += --whole-archive
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH)           += -lrte_hash
+_LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 2/5] app/test: add EFD functional and perf tests
From: Pablo de Lara @ 2017-01-12 22:15 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Byron Marohn, Karla Saur, Saikrishna Edupuganti
In-Reply-To: <1484259360-198276-1-git-send-email-pablo.de.lara.guarch@intel.com>

Signed-off-by: Byron Marohn <byron.marohn@intel.com>
Signed-off-by: Karla Saur <karla.saur@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Christian Maciocco <christian.maciocco@intel.com>
---
 MAINTAINERS              |   1 +
 app/test/Makefile        |   5 +-
 app/test/test_efd.c      | 494 +++++++++++++++++++++++++++++++++++++++++++++++
 app/test/test_efd_perf.c | 407 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 906 insertions(+), 1 deletion(-)
 create mode 100644 app/test/test_efd.c
 create mode 100644 app/test/test_efd_perf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9c60d67..d812962 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -532,6 +532,7 @@ EFD
 M: Byron Marohn <byron.marohn@intel.com>
 M: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>
 F: lib/librte_efd/
+F: app/test/test_efd*
 
 Hashes
 M: Bruce Richardson <bruce.richardson@intel.com>
diff --git a/app/test/Makefile b/app/test/Makefile
index 5be023a..9de301f 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -123,6 +123,9 @@ SRCS-y += test_logs.c
 SRCS-y += test_memcpy.c
 SRCS-y += test_memcpy_perf.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd.c
+SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd_perf.c
+
 SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash.c
 SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_thash.c
 SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_perf.c
diff --git a/app/test/test_efd.c b/app/test/test_efd.c
new file mode 100644
index 0000000..d5c3bd9
--- /dev/null
+++ b/app/test/test_efd.c
@@ -0,0 +1,494 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_memcpy.h>
+#include <rte_malloc.h>
+#include <rte_efd.h>
+#include <rte_byteorder.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ip.h>
+
+#include "test.h"
+
+#define EFD_TEST_KEY_LEN 8
+#define TABLE_SIZE (1 << 21)
+#define ITERATIONS 3
+static unsigned int test_socket_id;
+
+/* 5-tuple key type */
+struct flow_key {
+	uint32_t ip_src;
+	uint32_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint8_t proto;
+} __attribute__((packed));
+/*
+ * Print out result of unit test efd operation.
+ */
+#if defined(UNIT_TEST_EFD_VERBOSE)
+
+static void print_key_info(const char *msg, const struct flow_key *key,
+		efd_value_t val)
+{
+	const uint8_t *p = (const uint8_t *) key;
+	unsigned int i;
+
+	printf("%s key:0x", msg);
+	for (i = 0; i < sizeof(struct flow_key); i++)
+		printf("%02X", p[i]);
+
+	printf(" @ val %d\n", val);
+}
+#else
+
+static void print_key_info(__attribute__((unused)) const char *msg,
+		__attribute__((unused)) const struct flow_key *key,
+		__attribute__((unused)) efd_value_t val)
+{
+}
+#endif
+
+/* Keys used by unit test functions */
+static struct flow_key keys[5] = {
+	{
+		.ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
+		.ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
+		.port_src = 0x0908,
+		.port_dst = 0x0b0a,
+		.proto = 0x0c,
+	},
+	{
+		.ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
+		.ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
+		.port_src = 0x1918,
+		.port_dst = 0x1b1a,
+		.proto = 0x1c,
+	},
+	{
+		.ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
+		.ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
+		.port_src = 0x2928,
+		.port_dst = 0x2b2a,
+		.proto = 0x2c,
+	},
+	{
+		.ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
+		.ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
+		.port_src = 0x3938,
+		.port_dst = 0x3b3a,
+		.proto = 0x3c,
+	},
+	{
+		.ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
+		.ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
+		.port_src = 0x4948,
+		.port_dst = 0x4b4a,
+		.proto = 0x4c,
+	}
+};
+/* Array to store the data */
+efd_value_t data[5];
+
+static inline uint8_t efd_get_all_sockets_bitmask(void)
+{
+	uint8_t all_cpu_sockets_bitmask = 0;
+	unsigned int i;
+	unsigned int next_lcore = rte_get_master_lcore();
+	const int val_true = 1, val_false = 0;
+	for (i = 0; i < rte_lcore_count(); i++) {
+		all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore);
+		next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true);
+	}
+
+	return all_cpu_sockets_bitmask;
+}
+
+/*
+ * Basic sequence of operations for a single key:
+ *      - add
+ *      - lookup (hit)
+ *      - delete
+ * Note: lookup (miss) is not applicable since this is a filter
+ */
+static int test_add_delete(void)
+{
+	struct rte_efd_table *handle;
+	/* test with standard add/lookup/delete functions */
+	efd_value_t prev_value;
+	printf("Entering %s\n", __func__);
+
+	handle = rte_efd_create("test_add_delete",
+			TABLE_SIZE, sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	TEST_ASSERT_NOT_NULL(handle, "Error creating the EFD table\n");
+
+	data[0] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
+	TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[0],
+			data[0]),
+			"Error inserting the key");
+	print_key_info("Add", &keys[0], data[0]);
+
+	TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[0]),
+			data[0],
+			"failed to find key");
+
+	TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[0],
+			&prev_value),
+			"failed to delete key");
+	TEST_ASSERT_EQUAL(prev_value, data[0],
+			"failed to delete the expected value, got %d, "
+			"expected %d", prev_value, data[0]);
+	print_key_info("Del", &keys[0], data[0]);
+
+	rte_efd_free(handle);
+
+	return 0;
+}
+
+/*
+ * Sequence of operations for a single key:
+ *      - add
+ *      - lookup: hit
+ *      - add: update
+ *      - lookup: hit (updated data)
+ *      - delete: hit
+ */
+static int test_add_update_delete(void)
+{
+	struct rte_efd_table *handle;
+	printf("Entering %s\n", __func__);
+	/* test with standard add/lookup/delete functions */
+	efd_value_t prev_value;
+	data[1] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
+
+	handle = rte_efd_create("test_add_update_delete", TABLE_SIZE,
+			sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
+
+	TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1],
+			data[1]), "Error inserting the key");
+	print_key_info("Add", &keys[1], data[1]);
+
+	TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]),
+			data[1], "failed to find key");
+	print_key_info("Lkp", &keys[1], data[1]);
+
+	data[1] = data[1] + 1;
+	TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1],
+			data[1]), "Error re-inserting the key");
+	print_key_info("Add", &keys[1], data[1]);
+
+	TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]),
+			data[1], "failed to find key");
+	print_key_info("Lkp", &keys[1], data[1]);
+
+	TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[1],
+			&prev_value), "failed to delete key");
+	TEST_ASSERT_EQUAL(prev_value, data[1],
+			"failed to delete the expected value, got %d, "
+			"expected %d", prev_value, data[1]);
+	print_key_info("Del", &keys[1], data[1]);
+
+
+	rte_efd_free(handle);
+	return 0;
+}
+
+/*
+ * Sequence of operations for find existing EFD table
+ *
+ *  - create table
+ *  - find existing table: hit
+ *  - find non-existing table: miss
+ *
+ */
+static int test_efd_find_existing(void)
+{
+	struct rte_efd_table *handle = NULL, *result = NULL;
+
+	printf("Entering %s\n", __func__);
+
+	/* Create EFD table. */
+	handle = rte_efd_create("efd_find_existing", TABLE_SIZE,
+			sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
+
+	/* Try to find existing EFD table */
+	result = rte_efd_find_existing("efd_find_existing");
+	TEST_ASSERT_EQUAL(result, handle, "could not find existing efd table");
+
+	/* Try to find non-existing EFD table */
+	result = rte_efd_find_existing("efd_find_non_existing");
+	TEST_ASSERT_NULL(result, "found table that shouldn't exist");
+
+	/* Cleanup. */
+	rte_efd_free(handle);
+
+	return 0;
+}
+
+/*
+ * Sequence of operations for 5 keys
+ *      - add keys
+ *      - lookup keys: hit  (bulk)
+ *      - add keys (update)
+ *      - lookup keys: hit (updated data)
+ *      - delete keys : hit
+ */
+static int test_five_keys(void)
+{
+	struct rte_efd_table *handle;
+	const void *key_array[5] = {0};
+	efd_value_t result[5] = {0};
+	efd_value_t prev_value;
+	unsigned int i;
+	printf("Entering %s\n", __func__);
+
+	handle = rte_efd_create("test_five_keys", TABLE_SIZE,
+			sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
+
+	/* Setup data */
+	for (i = 0; i < 5; i++)
+		data[i] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
+
+	/* Add */
+	for (i = 0; i < 5; i++) {
+		TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id,
+				&keys[i], data[i]),
+				"Error inserting the key");
+		print_key_info("Add", &keys[i], data[i]);
+	}
+
+	/* Lookup */
+	for (i = 0; i < 5; i++)
+		key_array[i] = &keys[i];
+
+	rte_efd_lookup_bulk(handle, test_socket_id, 5,
+			(const void **) (void *) &key_array, result);
+
+	for (i = 0; i < 5; i++) {
+		TEST_ASSERT_EQUAL(result[i], data[i],
+				"bulk: failed to find key. Expected %d, got %d",
+				data[i], result[i]);
+		print_key_info("Lkp", &keys[i], data[i]);
+	}
+
+	/* Modify data (bulk) */
+	for (i = 0; i < 5; i++)
+		data[i] = data[i] + 1;
+
+	/* Add - update */
+	for (i = 0; i < 5; i++) {
+		TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id,
+				&keys[i], data[i]),
+				"Error inserting the key");
+		print_key_info("Add", &keys[i], data[i]);
+	}
+
+	/* Lookup */
+	for (i = 0; i < 5; i++) {
+		TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id,
+				&keys[i]), data[i],
+				"failed to find key");
+		print_key_info("Lkp", &keys[i], data[i]);
+	}
+
+	/* Delete */
+	for (i = 0; i < 5; i++) {
+		TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id,
+				&keys[i], &prev_value),
+				"failed to delete key");
+		TEST_ASSERT_EQUAL(prev_value, data[i],
+				"failed to delete the expected value, got %d, "
+				"expected %d", prev_value, data[i]);
+		print_key_info("Del", &keys[i], data[i]);
+	}
+
+
+	rte_efd_free(handle);
+
+	return 0;
+}
+
+/*
+ * Test to see the average table utilization (entries added/max entries)
+ * before hitting a random entry that cannot be added
+ */
+static int test_average_table_utilization(void)
+{
+	struct rte_efd_table *handle = NULL;
+	uint32_t num_rules_in = TABLE_SIZE;
+	uint8_t simple_key[EFD_TEST_KEY_LEN];
+	unsigned int i, j;
+	unsigned int added_keys, average_keys_added = 0;
+
+	printf("Evaluating table utilization and correctness, please wait\n");
+	fflush(stdout);
+
+	for (j = 0; j < ITERATIONS; j++) {
+		handle = rte_efd_create("test_efd", num_rules_in,
+				EFD_TEST_KEY_LEN, efd_get_all_sockets_bitmask(),
+				test_socket_id);
+		if (handle == NULL) {
+			printf("efd table creation failed\n");
+			return -1;
+		}
+
+		unsigned int succeeded = 0;
+		unsigned int lost_keys = 0;
+
+		/* Add random entries until key cannot be added */
+		for (added_keys = 0; added_keys < num_rules_in; added_keys++) {
+
+			for (i = 0; i < EFD_TEST_KEY_LEN; i++)
+				simple_key[i] = rte_rand() & 0xFF;
+
+			efd_value_t val = simple_key[0];
+
+			if (rte_efd_update(handle, test_socket_id, simple_key,
+						val))
+				break; /* continue;*/
+			if (rte_efd_lookup(handle, test_socket_id, simple_key)
+					!= val)
+				lost_keys++;
+			else
+				succeeded++;
+		}
+
+		average_keys_added += succeeded;
+
+		/* Reset the table */
+		rte_efd_free(handle);
+
+		/* Print progress on operations */
+		printf("Added %10u	Succeeded %10u	Lost %10u\n",
+				added_keys, succeeded, lost_keys);
+		fflush(stdout);
+	}
+
+	average_keys_added /= ITERATIONS;
+
+	printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
+			((double) average_keys_added / num_rules_in * 100),
+			average_keys_added, num_rules_in);
+
+	return 0;
+}
+
+/*
+ * Do tests for EFD creation with bad parameters.
+ */
+static int test_efd_creation_with_bad_parameters(void)
+{
+	struct rte_efd_table *handle, *tmp;
+	printf("Entering %s, **Errors are expected **\n", __func__);
+
+	handle = rte_efd_create("creation_with_bad_parameters_0", TABLE_SIZE, 0,
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	if (handle != NULL) {
+		rte_efd_free(handle);
+		printf("Impossible creating EFD table successfully "
+			"if key_len in parameter is zero\n");
+		return -1;
+	}
+
+	handle = rte_efd_create("creation_with_bad_parameters_1", TABLE_SIZE,
+			sizeof(struct flow_key), 0, test_socket_id);
+	if (handle != NULL) {
+		rte_efd_free(handle);
+		printf("Impossible creating EFD table successfully "
+			"with invalid socket bitmask\n");
+		return -1;
+	}
+
+	handle = rte_efd_create("creation_with_bad_parameters_2", TABLE_SIZE,
+			sizeof(struct flow_key), efd_get_all_sockets_bitmask(),
+			255);
+	if (handle != NULL) {
+		rte_efd_free(handle);
+		printf("Impossible creating EFD table successfully "
+			"with invalid socket\n");
+		return -1;
+	}
+
+	/* test with same name should fail */
+	handle = rte_efd_create("same_name", TABLE_SIZE,
+			sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), 0);
+	if (handle == NULL) {
+		printf("Cannot create first EFD table with 'same_name'\n");
+		return -1;
+	}
+	tmp = rte_efd_create("same_name", TABLE_SIZE, sizeof(struct flow_key),
+			efd_get_all_sockets_bitmask(), 0);
+	if (tmp != NULL) {
+		printf("Creation of EFD table with same name should fail\n");
+		rte_efd_free(handle);
+		rte_efd_free(tmp);
+		return -1;
+	}
+	rte_efd_free(handle);
+
+	printf("# Test successful. No more errors expected\n");
+
+	return 0;
+}
+
+static int
+test_efd(void)
+{
+
+	/* Unit tests */
+	if (test_add_delete() < 0)
+		return -1;
+	if (test_efd_find_existing() < 0)
+		return -1;
+	if (test_add_update_delete() < 0)
+		return -1;
+	if (test_five_keys() < 0)
+		return -1;
+	if (test_efd_creation_with_bad_parameters() < 0)
+		return -1;
+	if (test_average_table_utilization() < 0)
+		return -1;
+
+	return 0;
+}
+
+REGISTER_TEST_COMMAND(efd_autotest, test_efd);
diff --git a/app/test/test_efd_perf.c b/app/test/test_efd_perf.c
new file mode 100644
index 0000000..998a25b
--- /dev/null
+++ b/app/test/test_efd_perf.c
@@ -0,0 +1,407 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_random.h>
+#include <rte_efd.h>
+#include <rte_memcpy.h>
+#include <rte_thash.h>
+
+#include "test.h"
+#define NUM_KEYSIZES 10
+#define NUM_SHUFFLES 10
+#define MAX_KEYSIZE 64
+#define MAX_ENTRIES (1 << 19)
+#define KEYS_TO_ADD (MAX_ENTRIES * 3 / 4) /* 75% table utilization */
+#define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
+static unsigned int test_socket_id;
+
+static inline uint8_t efd_get_all_sockets_bitmask(void)
+{
+	uint8_t all_cpu_sockets_bitmask = 0;
+	unsigned int i;
+	unsigned int next_lcore = rte_get_master_lcore();
+	const int val_true = 1, val_false = 0;
+	for (i = 0; i < rte_lcore_count(); i++) {
+		all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore);
+		next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true);
+	}
+
+	return all_cpu_sockets_bitmask;
+}
+
+enum operations {
+	ADD = 0,
+	LOOKUP,
+	LOOKUP_MULTI,
+	DELETE,
+	NUM_OPERATIONS
+};
+
+struct efd_perf_params {
+	struct rte_efd_table *efd_table;
+	uint32_t key_size;
+	unsigned int cycle;
+};
+
+static uint32_t hashtest_key_lens[] = {
+	/* standard key sizes */
+	4, 8, 16, 32, 48, 64,
+	/* IPv4 SRC + DST + protocol, unpadded */
+	9,
+	/* IPv4 5-tuple, unpadded */
+	13,
+	/* IPv6 5-tuple, unpadded */
+	37,
+	/* IPv6 5-tuple, padded to 8-byte boundary */
+	40
+};
+
+/* Array to store number of cycles per operation */
+uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS];
+
+/* Array to store the data */
+efd_value_t data[KEYS_TO_ADD];
+
+/* Array to store all input keys */
+uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];
+
+/* Shuffle the keys that have been added, so lookups will be totally random */
+static void
+shuffle_input_keys(struct efd_perf_params *params)
+{
+	efd_value_t temp_data;
+	unsigned int i;
+	uint32_t swap_idx;
+	uint8_t temp_key[MAX_KEYSIZE];
+
+	for (i = KEYS_TO_ADD - 1; i > 0; i--) {
+		swap_idx = rte_rand() % i;
+
+		memcpy(temp_key, keys[i], hashtest_key_lens[params->cycle]);
+		temp_data = data[i];
+
+		memcpy(keys[i], keys[swap_idx], hashtest_key_lens[params->cycle]);
+		data[i] = data[swap_idx];
+
+		memcpy(keys[swap_idx], temp_key, hashtest_key_lens[params->cycle]);
+		data[swap_idx] = temp_data;
+	}
+}
+
+static int key_compare(const void *key1, const void *key2)
+{
+	return memcmp(key1, key2, MAX_KEYSIZE);
+}
+
+/*
+ * TODO: we could "error proof" these as done in test_hash_perf.c ln 165:
+ *
+ * The current setup may give errors if too full in some cases which we check
+ * for. However, since EFD allows for ~99% capacity, these errors are rare for
+ * #"KEYS_TO_ADD" which is 75% capacity.
+ */
+static int
+setup_keys_and_data(struct efd_perf_params *params, unsigned int cycle)
+{
+	unsigned int i, j;
+	int num_duplicates;
+
+	params->key_size = hashtest_key_lens[cycle];
+	params->cycle = cycle;
+
+	/* Reset all arrays */
+	for (i = 0; i < params->key_size; i++)
+		keys[0][i] = 0;
+
+	/* Generate a list of keys, some of which may be duplicates */
+	for (i = 0; i < KEYS_TO_ADD; i++) {
+		for (j = 0; j < params->key_size; j++)
+			keys[i][j] = rte_rand() & 0xFF;
+
+		data[i] = rte_rand() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
+	}
+
+	/* Remove duplicates from the keys array */
+	do {
+		num_duplicates = 0;
+
+		/* Sort the list of keys to make it easier to find duplicates */
+		qsort(keys, KEYS_TO_ADD, MAX_KEYSIZE, key_compare);
+
+		/* Sift through the list of keys and look for duplicates */
+		int num_duplicates = 0;
+		for (i = 0; i < KEYS_TO_ADD - 1; i++) {
+			if (memcmp(keys[i], keys[i + 1], params->key_size) == 0) {
+				/* This key already exists, try again */
+				num_duplicates++;
+				for (j = 0; j < params->key_size; j++)
+					keys[i][j] = rte_rand() & 0xFF;
+			}
+		}
+	} while (num_duplicates != 0);
+
+	/* Shuffle the random values again */
+	shuffle_input_keys(params);
+
+	params->efd_table = rte_efd_create("test_efd_perf",
+			MAX_ENTRIES, params->key_size,
+			efd_get_all_sockets_bitmask(), test_socket_id);
+	TEST_ASSERT_NOT_NULL(params->efd_table, "Error creating the efd table\n");
+
+	return 0;
+}
+
+static int
+timed_adds(struct efd_perf_params *params)
+{
+	const uint64_t start_tsc = rte_rdtsc();
+	unsigned int i, a;
+	int32_t ret;
+
+	for (i = 0; i < KEYS_TO_ADD; i++) {
+		ret = rte_efd_update(params->efd_table, test_socket_id, keys[i],
+				data[i]);
+		if (ret != 0) {
+			printf("Error %d in rte_efd_update - key=0x", ret);
+			for (a = 0; a < params->key_size; a++)
+				printf("%02x", keys[i][a]);
+			printf(" value=%d\n", data[i]);
+
+			return -1;
+		}
+	}
+
+	const uint64_t end_tsc = rte_rdtsc();
+	const uint64_t time_taken = end_tsc - start_tsc;
+
+	cycles[params->cycle][ADD] = time_taken / KEYS_TO_ADD;
+	return 0;
+}
+
+static int
+timed_lookups(struct efd_perf_params *params)
+{
+	unsigned int i, j, a;
+	const uint64_t start_tsc = rte_rdtsc();
+	efd_value_t ret_data;
+
+	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
+		for (j = 0; j < KEYS_TO_ADD; j++) {
+			ret_data = rte_efd_lookup(params->efd_table,
+					test_socket_id, keys[j]);
+			if (ret_data != data[j]) {
+				printf("Value mismatch using rte_efd_lookup: "
+						"key #%d (0x", i);
+				for (a = 0; a < params->key_size; a++)
+					printf("%02x", keys[i][a]);
+				printf(")\n");
+				printf("  Expected %d, got %d\n", data[i],
+						ret_data);
+
+				return -1;
+			}
+
+		}
+	}
+
+	const uint64_t end_tsc = rte_rdtsc();
+	const uint64_t time_taken = end_tsc - start_tsc;
+
+	cycles[params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS;
+
+	return 0;
+}
+
+static int
+timed_lookups_multi(struct efd_perf_params *params)
+{
+	unsigned int i, j, k, a;
+	efd_value_t result[RTE_EFD_BURST_MAX] = {0};
+	const void *keys_burst[RTE_EFD_BURST_MAX];
+	const uint64_t start_tsc = rte_rdtsc();
+
+	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
+		for (j = 0; j < KEYS_TO_ADD / RTE_EFD_BURST_MAX; j++) {
+			for (k = 0; k < RTE_EFD_BURST_MAX; k++)
+				keys_burst[k] = keys[j * RTE_EFD_BURST_MAX + k];
+
+			rte_efd_lookup_bulk(params->efd_table, test_socket_id,
+					RTE_EFD_BURST_MAX,
+					keys_burst, result);
+
+			for (k = 0; k < RTE_EFD_BURST_MAX; k++) {
+				uint32_t data_idx = j * RTE_EFD_BURST_MAX + k;
+				if (result[k] != data[data_idx]) {
+					printf("Value mismatch using "
+						"rte_efd_lookup_bulk: key #%d "
+						"(0x", i);
+					for (a = 0; a < params->key_size; a++)
+						printf("%02x",
+							keys[data_idx][a]);
+					printf(")\n");
+					printf("  Expected %d, got %d\n",
+						data[data_idx], result[k]);
+
+					return -1;
+				}
+			}
+		}
+	}
+
+	const uint64_t end_tsc = rte_rdtsc();
+	const uint64_t time_taken = end_tsc - start_tsc;
+
+	cycles[params->cycle][LOOKUP_MULTI] = time_taken / NUM_LOOKUPS;
+
+	return 0;
+}
+
+static int
+timed_deletes(struct efd_perf_params *params)
+{
+	unsigned int i, a;
+	const uint64_t start_tsc = rte_rdtsc();
+	int32_t ret;
+
+	for (i = 0; i < KEYS_TO_ADD; i++) {
+		ret = rte_efd_delete(params->efd_table, test_socket_id, keys[i],
+				NULL);
+
+		if (ret != 0) {
+			printf("Error %d in rte_efd_delete - key=0x", ret);
+			for (a = 0; a < params->key_size; a++)
+				printf("%02x", keys[i][a]);
+			printf("\n");
+
+			return -1;
+		}
+	}
+
+	const uint64_t end_tsc = rte_rdtsc();
+	const uint64_t time_taken = end_tsc - start_tsc;
+
+	cycles[params->cycle][DELETE] = time_taken / KEYS_TO_ADD;
+
+	return 0;
+}
+
+static void
+perform_frees(struct efd_perf_params *params)
+{
+	if (params->efd_table != NULL) {
+		rte_efd_free(params->efd_table);
+		params->efd_table = NULL;
+	}
+}
+
+static int
+exit_with_fail(const char *testname, struct efd_perf_params *params,
+		unsigned int i)
+{
+
+	printf("<<<<<Test %s failed at keysize %d iteration %d >>>>>\n",
+			testname, hashtest_key_lens[params->cycle], i);
+	perform_frees(params);
+	return -1;
+}
+
+static int
+run_all_tbl_perf_tests(void)
+{
+	unsigned int i, j;
+	struct efd_perf_params params;
+
+	printf("Measuring performance, please wait\n");
+	fflush(stdout);
+
+	test_socket_id = rte_socket_id();
+
+	for (i = 0; i < NUM_KEYSIZES; i++) {
+
+		if (setup_keys_and_data(&params, i) < 0) {
+			printf("Could not create keys/data/table\n");
+			return -1;
+		}
+
+		if (timed_adds(&params) < 0)
+			return exit_with_fail("timed_adds", &params, i);
+
+		for (j = 0; j < NUM_SHUFFLES; j++)
+			shuffle_input_keys(&params);
+
+		if (timed_lookups(&params) < 0)
+			return exit_with_fail("timed_lookups", &params, i);
+
+		if (timed_lookups_multi(&params) < 0)
+			return exit_with_fail("timed_lookups_multi", &params, i);
+
+		if (timed_deletes(&params) < 0)
+			return exit_with_fail("timed_deletes", &params, i);
+
+		/* Print a dot to show progress on operations */
+		printf(".");
+		fflush(stdout);
+
+		perform_frees(&params);
+	}
+
+	printf("\nResults (in CPU cycles/operation)\n");
+	printf("-----------------------------------\n");
+	printf("\n%-18s%-18s%-18s%-18s%-18s\n",
+			"Keysize", "Add", "Lookup", "Lookup_bulk", "Delete");
+	for (i = 0; i < NUM_KEYSIZES; i++) {
+		printf("%-18d", hashtest_key_lens[i]);
+		for (j = 0; j < NUM_OPERATIONS; j++)
+			printf("%-18"PRIu64, cycles[i][j]);
+		printf("\n");
+	}
+	return 0;
+}
+
+static int
+test_efd_perf(void)
+{
+
+	if (run_all_tbl_perf_tests() < 0)
+		return -1;
+
+	return 0;
+}
+
+REGISTER_TEST_COMMAND(efd_perf_autotest, test_efd_perf);
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 3/5] examples/flow_distributor: sample app to demonstrate EFD usage
From: Pablo de Lara @ 2017-01-12 22:15 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Saikrishna Edupuganti
In-Reply-To: <1484259360-198276-1-git-send-email-pablo.de.lara.guarch@intel.com>

This new sample app, based on the client/server sample app,
shows the user an scenario using the EFD library.
It consists of:

- A front-end server which has an EFD table that stores the
  node id for each flow key, which will distribute the incoming
  packets to the different nodes

- A back-end node, which has a hash table where node checks,
  after reading packets coming from the server, whether the packet
  is meant to be used in such node, in which case it will be TXed,
  or not, in which case, packet will be dropped.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
Acked-by: Christian Maciocco <christian.maciocco@intel.com>
---
 MAINTAINERS                                    |   1 +
 doc/api/examples.dox                           |   4 +
 examples/Makefile                              |   1 +
 examples/flow_distributor/Makefile             |  44 +++
 examples/flow_distributor/distributor/Makefile |  57 ++++
 examples/flow_distributor/distributor/args.c   | 200 ++++++++++++
 examples/flow_distributor/distributor/args.h   |  39 +++
 examples/flow_distributor/distributor/init.c   | 371 ++++++++++++++++++++++
 examples/flow_distributor/distributor/init.h   |  76 +++++
 examples/flow_distributor/distributor/main.c   | 362 +++++++++++++++++++++
 examples/flow_distributor/node/Makefile        |  48 +++
 examples/flow_distributor/node/node.c          | 417 +++++++++++++++++++++++++
 examples/flow_distributor/shared/common.h      |  99 ++++++
 13 files changed, 1719 insertions(+)
 create mode 100644 examples/flow_distributor/Makefile
 create mode 100644 examples/flow_distributor/distributor/Makefile
 create mode 100644 examples/flow_distributor/distributor/args.c
 create mode 100644 examples/flow_distributor/distributor/args.h
 create mode 100644 examples/flow_distributor/distributor/init.c
 create mode 100644 examples/flow_distributor/distributor/init.h
 create mode 100644 examples/flow_distributor/distributor/main.c
 create mode 100644 examples/flow_distributor/node/Makefile
 create mode 100644 examples/flow_distributor/node/node.c
 create mode 100644 examples/flow_distributor/shared/common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d812962..b124f6e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -533,6 +533,7 @@ M: Byron Marohn <byron.marohn@intel.com>
 M: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>
 F: lib/librte_efd/
 F: app/test/test_efd*
+F: examples/flow_distributor/
 
 Hashes
 M: Bruce Richardson <bruce.richardson@intel.com>
diff --git a/doc/api/examples.dox b/doc/api/examples.dox
index 1626852..c13e574 100644
--- a/doc/api/examples.dox
+++ b/doc/api/examples.dox
@@ -52,6 +52,10 @@
 @example load_balancer/init.c
 @example load_balancer/main.c
 @example load_balancer/runtime.c
+@example flow_distributor/distributor/args.c
+@example flow_distributor/distributor/init.c
+@example flow_distributor/distributor/main.c
+@example flow_distributor/node/node.c
 @example multi_process/client_server_mp/mp_client/client.c
 @example multi_process/client_server_mp/mp_server/args.c
 @example multi_process/client_server_mp/mp_server/init.c
diff --git a/examples/Makefile b/examples/Makefile
index d49c7f2..b404982 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -45,6 +45,7 @@ DIRS-y += dpdk_qat
 endif
 DIRS-y += ethtool
 DIRS-y += exception_path
+DIRS-$(CONFIG_RTE_LIBRTE_EFD) += flow_distributor
 DIRS-y += helloworld
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += ip_pipeline
 ifeq ($(CONFIG_RTE_LIBRTE_LPM),y)
diff --git a/examples/flow_distributor/Makefile b/examples/flow_distributor/Makefile
new file mode 100644
index 0000000..5bae706
--- /dev/null
+++ b/examples/flow_distributor/Makefile
@@ -0,0 +1,44 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += distributor
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += node
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/flow_distributor/distributor/Makefile b/examples/flow_distributor/distributor/Makefile
new file mode 100644
index 0000000..8714151
--- /dev/null
+++ b/examples/flow_distributor/distributor/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV), "linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = distributor
+
+# all source are stored in SRCS-y
+SRCS-y := main.c init.c args.c
+
+INC := $(wildcard *.h)
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/distributor/args.c b/examples/flow_distributor/distributor/args.c
new file mode 100644
index 0000000..ee29203
--- /dev/null
+++ b/examples/flow_distributor/distributor/args.c
@@ -0,0 +1,200 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/* 1M flows by default */
+#define DEFAULT_NUM_FLOWS    0x100000
+
+/* global var for number of nodes - extern in header */
+uint8_t num_nodes;
+/* global var for number of flows - extern in header */
+uint32_t num_flows = DEFAULT_NUM_FLOWS;
+
+static const char *progname;
+
+/**
+ * Prints out usage information to stdout
+ */
+static void
+usage(void)
+{
+	printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n"
+		" -p PORTMASK: hexadecimal bitmask of ports to use\n"
+		" -n NUM_NODES: number of node processes to use\n"
+		" -f NUM_FLOWS: number of flows to be added in the EFD table\n",
+		progname);
+}
+
+/**
+ * The ports to be used by the application are passed in
+ * the form of a bitmask. This function parses the bitmask
+ * and places the port numbers to be used into the port[]
+ * array variable
+ */
+static int
+parse_portmask(uint8_t max_ports, const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+	uint8_t count = 0;
+
+	if (portmask == NULL || *portmask == '\0')
+		return -1;
+
+	/* convert parameter to a number and verify */
+	pm = strtoul(portmask, &end, 16);
+	if (end == NULL || *end != '\0' || pm == 0)
+		return -1;
+
+	/* loop through bits of the mask and mark ports */
+	while (pm != 0) {
+		if (pm & 0x01) { /* bit is set in mask, use port */
+			if (count >= max_ports)
+				printf("WARNING: requested port %u not present"
+				" - ignoring\n", (unsigned int)count);
+			else
+			    info->id[info->num_ports++] = count;
+		}
+		pm = (pm >> 1);
+		count++;
+	}
+
+	return 0;
+}
+
+/**
+ * Take the number of nodes parameter passed to the app
+ * and convert to a number to store in the num_nodes variable
+ */
+static int
+parse_num_nodes(const char *nodes)
+{
+	char *end = NULL;
+	unsigned long temp;
+
+	if (nodes == NULL || *nodes == '\0')
+		return -1;
+
+	temp = strtoul(nodes, &end, 10);
+	if (end == NULL || *end != '\0' || temp == 0)
+		return -1;
+
+	num_nodes = (uint8_t)temp;
+	return 0;
+}
+
+static int
+parse_num_flows(const char *flows)
+{
+	char *end = NULL;
+
+	/* parse hexadecimal string */
+	num_flows = strtoul(flows, &end, 16);
+	if ((flows[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (num_flows == 0)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * The application specific arguments follow the DPDK-specific
+ * arguments which are stripped by the DPDK init. This function
+ * processes these application arguments, printing usage info
+ * on error.
+ */
+int
+parse_app_args(uint8_t max_ports, int argc, char *argv[])
+{
+	int option_index, opt;
+	char **argvopt = argv;
+	static struct option lgopts[] = { /* no long options */
+		{NULL, 0, 0, 0 }
+	};
+	progname = argv[0];
+
+	while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case 'p':
+			if (parse_portmask(max_ports, optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		case 'n':
+			if (parse_num_nodes(optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		case 'f':
+			if (parse_num_flows(optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		default:
+			printf("ERROR: Unknown option '%c'\n", opt);
+			usage();
+			return -1;
+		}
+	}
+
+	if (info->num_ports == 0 || num_nodes == 0) {
+		usage();
+		return -1;
+	}
+
+	if (info->num_ports % 2 != 0) {
+		printf("ERROR: application requires an even "
+				"number of ports to use\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/examples/flow_distributor/distributor/args.h b/examples/flow_distributor/distributor/args.h
new file mode 100644
index 0000000..cacf395
--- /dev/null
+++ b/examples/flow_distributor/distributor/args.h
@@ -0,0 +1,39 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+int parse_app_args(uint8_t max_ports, int argc, char *argv[]);
+
+#endif /* ifndef _ARGS_H_ */
diff --git a/examples/flow_distributor/distributor/init.c b/examples/flow_distributor/distributor/init.c
new file mode 100644
index 0000000..3b0aa85
--- /dev/null
+++ b/examples/flow_distributor/distributor/init.c
@@ -0,0 +1,371 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_atomic.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_debug.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_efd.h>
+#include <rte_hash.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+#define MBUFS_PER_NODE 1536
+#define MBUFS_PER_PORT 1536
+#define MBUF_CACHE_SIZE 512
+
+#define RTE_MP_RX_DESC_DEFAULT 512
+#define RTE_MP_TX_DESC_DEFAULT 512
+#define NODE_QUEUE_RINGSIZE 128
+
+#define NO_FLAGS 0
+
+/* The mbuf pool for packet rx */
+struct rte_mempool *pktmbuf_pool;
+
+/* array of info/queues for nodes */
+struct node *nodes;
+
+/* Flow distributor table */
+struct rte_efd_table *efd_table;
+
+/* Shared info between distributor and nodes */
+struct shared_info *info;
+
+/**
+ * Initialise the mbuf pool for packet reception for the NIC, and any other
+ * buffer pools needed by the app - currently none.
+ */
+static int
+init_mbuf_pools(void)
+{
+	const unsigned int num_mbufs = (num_nodes * MBUFS_PER_NODE) +
+			(info->num_ports * MBUFS_PER_PORT);
+
+	/*
+	 * Don't pass single-producer/single-consumer flags to mbuf create as it
+	 * seems faster to use a cache instead
+	 */
+	printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
+			PKTMBUF_POOL_NAME, num_mbufs);
+	pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
+		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+
+	return pktmbuf_pool == NULL; /* 0  on success */
+}
+
+/**
+ * Initialise an individual port:
+ * - configure number of rx and tx rings
+ * - set up each rx ring, to pull from the main mbuf pool
+ * - set up each tx ring
+ * - start the port and report its status to stdout
+ */
+static int
+init_port(uint8_t port_num)
+{
+	/* for port configuration all features are off by default */
+	const struct rte_eth_conf port_conf = {
+		.rxmode = {
+			.mq_mode = ETH_MQ_RX_RSS
+		}
+	};
+	const uint16_t rx_rings = 1, tx_rings = num_nodes;
+	const uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
+	const uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
+
+	uint16_t q;
+	int retval;
+
+	printf("Port %u init ... ", (unsigned int)port_num);
+	fflush(stdout);
+
+	/*
+	 * Standard DPDK port initialisation - config port, then set up
+	 * rx and tx rings.
+	 */
+	retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings, &port_conf);
+	if (retval != 0)
+		return retval;
+
+	for (q = 0; q < rx_rings; q++) {
+		retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
+				rte_eth_dev_socket_id(port_num),
+				NULL, pktmbuf_pool);
+		if (retval < 0)
+			return retval;
+	}
+
+	for (q = 0; q < tx_rings; q++) {
+		retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
+				rte_eth_dev_socket_id(port_num),
+				NULL);
+		if (retval < 0)
+			return retval;
+	}
+
+	rte_eth_promiscuous_enable(port_num);
+
+	retval = rte_eth_dev_start(port_num);
+	if (retval < 0)
+		return retval;
+
+	printf("done:\n");
+
+	return 0;
+}
+
+/**
+ * Set up the DPDK rings which will be used to pass packets, via
+ * pointers, between the multi-process distributor and node processes.
+ * Each node needs one RX queue.
+ */
+static int
+init_shm_rings(void)
+{
+	unsigned int i;
+	unsigned int socket_id;
+	const char *q_name;
+	const unsigned int ringsize = NODE_QUEUE_RINGSIZE;
+
+	nodes = rte_malloc("node details",
+		sizeof(*nodes) * num_nodes, 0);
+	if (nodes == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate memory for "
+				"node program details\n");
+
+	for (i = 0; i < num_nodes; i++) {
+		/* Create an RX queue for each node */
+		socket_id = rte_socket_id();
+		q_name = get_rx_queue_name(i);
+		nodes[i].rx_q = rte_ring_create(q_name,
+				ringsize, socket_id,
+				RING_F_SP_ENQ | RING_F_SC_DEQ);
+		if (nodes[i].rx_q == NULL)
+			rte_exit(EXIT_FAILURE, "Cannot create rx ring queue "
+					"for node %u\n", i);
+	}
+	return 0;
+}
+
+/*
+ * Create flow distributor table which will contain all the flows
+ * that will be distributed among the nodes
+ */
+static void
+create_flow_distributor_table(void)
+{
+	uint8_t socket_id = rte_socket_id();
+
+	/* create table */
+	efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
+			1 << socket_id,	socket_id);
+
+	if (efd_table == NULL)
+		rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
+}
+
+static void
+populate_flow_distributor_table(void)
+{
+	unsigned int i;
+	int32_t ret;
+	uint32_t ip_dst;
+	uint8_t socket_id = rte_socket_id();
+	uint64_t node_id;
+
+	/* Add flows in table */
+	for (i = 0; i < num_flows; i++) {
+		node_id = i % num_nodes;
+
+		ip_dst = rte_cpu_to_be_32(i);
+		ret = rte_efd_update(efd_table, socket_id,
+				(void *)&ip_dst, (efd_value_t)node_id);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
+					"flow distributor table\n", i);
+	}
+
+	printf("EFD table: Adding 0x%x keys\n", num_flows);
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << info->id[portid])) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(info->id[portid], &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", info->id[portid],
+						(unsigned int)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)info->id[portid]);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == ETH_LINK_DOWN) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+/**
+ * Main init function for the multi-process distributor app,
+ * calls subfunctions to do each stage of the initialisation.
+ */
+int
+init(int argc, char *argv[])
+{
+	int retval;
+	const struct rte_memzone *mz;
+	uint8_t i, total_ports;
+
+	/* init EAL, parsing EAL args */
+	retval = rte_eal_init(argc, argv);
+	if (retval < 0)
+		return -1;
+	argc -= retval;
+	argv += retval;
+
+	/* get total number of ports */
+	total_ports = rte_eth_dev_count();
+
+	/* set up array for port data */
+	mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
+				rte_socket_id(), NO_FLAGS);
+	if (mz == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot reserve memory zone "
+				"for port information\n");
+	memset(mz->addr, 0, sizeof(*info));
+	info = mz->addr;
+
+	/* parse additional, application arguments */
+	retval = parse_app_args(total_ports, argc, argv);
+	if (retval != 0)
+		return -1;
+
+	/* initialise mbuf pools */
+	retval = init_mbuf_pools();
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
+
+	/* now initialise the ports we will use */
+	for (i = 0; i < info->num_ports; i++) {
+		retval = init_port(info->id[i]);
+		if (retval != 0)
+			rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
+					(unsigned int) i);
+	}
+
+	check_all_ports_link_status(info->num_ports, (~0x0));
+
+	/* initialise the node queues/rings for inter-eu comms */
+	init_shm_rings();
+
+	/* Create the flow distributor table */
+	create_flow_distributor_table();
+
+	/* Populate the flow distributor table */
+	populate_flow_distributor_table();
+
+	/* Share the total number of nodes */
+	info->num_nodes = num_nodes;
+
+	/* Share the total number of flows */
+	info->num_flows = num_flows;
+	return 0;
+}
diff --git a/examples/flow_distributor/distributor/init.h b/examples/flow_distributor/distributor/init.h
new file mode 100644
index 0000000..d11aacf
--- /dev/null
+++ b/examples/flow_distributor/distributor/init.h
@@ -0,0 +1,76 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _INIT_H_
+#define _INIT_H_
+
+/*
+ * #include <rte_ring.h>
+ * #include "args.h"
+ */
+
+/*
+ * Define a node structure with all needed info, including
+ * stats from the nodes.
+ */
+struct node {
+	struct rte_ring *rx_q;
+	unsigned int node_id;
+	/* these stats hold how many packets the node will actually receive,
+	 * and how many packets were dropped because the node's queue was full.
+	 * The port-info stats, in contrast, record how many packets were received
+	 * or transmitted on an actual NIC port.
+	 */
+	struct {
+		uint64_t rx;
+		uint64_t rx_drop;
+	} stats;
+};
+
+extern struct rte_efd_table *efd_table;
+extern struct node *nodes;
+
+/*
+ * shared information between distributor and nodes: number of clients,
+ * port numbers, rx and tx stats etc.
+ */
+extern struct shared_info *info;
+
+extern struct rte_mempool *pktmbuf_pool;
+extern uint8_t num_nodes;
+extern unsigned int num_sockets;
+extern uint32_t num_flows;
+
+int init(int argc, char *argv[]);
+
+#endif /* ifndef _INIT_H_ */
diff --git a/examples/flow_distributor/distributor/main.c b/examples/flow_distributor/distributor/main.c
new file mode 100644
index 0000000..f97f003
--- /dev/null
+++ b/examples/flow_distributor/distributor/main.c
@@ -0,0 +1,362 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <inttypes.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <netinet/ip.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_atomic.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ethdev.h>
+#include <rte_byteorder.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_efd.h>
+#include <rte_ip.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/*
+ * When doing reads from the NIC or the node queues,
+ * use this batch size
+ */
+#define PACKET_READ_SIZE 32
+
+/*
+ * Local buffers to put packets in, used to send packets in bursts to the
+ * nodes
+ */
+struct node_rx_buf {
+	struct rte_mbuf *buffer[PACKET_READ_SIZE];
+	uint16_t count;
+};
+
+struct flow_distributor_stats {
+	uint64_t distributed;
+	uint64_t drop;
+} flow_dist_stats;
+
+/* One buffer per node rx queue - dynamically allocate array */
+static struct node_rx_buf *cl_rx_buf;
+
+static const char *
+get_printable_mac_addr(uint8_t port)
+{
+	static const char err_address[] = "00:00:00:00:00:00";
+	static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)];
+	struct ether_addr mac;
+
+	if (unlikely(port >= RTE_MAX_ETHPORTS))
+		return err_address;
+	if (unlikely(addresses[port][0] == '\0')) {
+		rte_eth_macaddr_get(port, &mac);
+		snprintf(addresses[port], sizeof(addresses[port]),
+				"%02x:%02x:%02x:%02x:%02x:%02x\n",
+				mac.addr_bytes[0], mac.addr_bytes[1],
+				mac.addr_bytes[2], mac.addr_bytes[3],
+				mac.addr_bytes[4], mac.addr_bytes[5]);
+	}
+	return addresses[port];
+}
+
+/*
+ * This function displays the recorded statistics for each port
+ * and for each node. It uses ANSI terminal codes to clear
+ * screen when called. It is called from a single non-master
+ * thread in the distributor process, when the process is run with more
+ * than one lcore enabled.
+ */
+static void
+do_stats_display(void)
+{
+	unsigned int i, j;
+	const char clr[] = {27, '[', '2', 'J', '\0'};
+	const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
+	uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
+	uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
+
+	/* to get TX stats, we need to do some summing calculations */
+	memset(port_tx, 0, sizeof(port_tx));
+	memset(port_tx_drop, 0, sizeof(port_tx_drop));
+	memset(node_tx, 0, sizeof(node_tx));
+	memset(node_tx_drop, 0, sizeof(node_tx_drop));
+
+	for (i = 0; i < num_nodes; i++) {
+		const struct tx_stats *tx = &info->tx_stats[i];
+
+		for (j = 0; j < info->num_ports; j++) {
+			const uint64_t tx_val = tx->tx[info->id[j]];
+			const uint64_t drop_val = tx->tx_drop[info->id[j]];
+
+			port_tx[j] += tx_val;
+			port_tx_drop[j] += drop_val;
+			node_tx[i] += tx_val;
+			node_tx_drop[i] += drop_val;
+		}
+	}
+
+	/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("PORTS\n");
+	printf("-----\n");
+	for (i = 0; i < info->num_ports; i++)
+		printf("Port %u: '%s'\t", (unsigned int)info->id[i],
+				get_printable_mac_addr(info->id[i]));
+	printf("\n\n");
+	for (i = 0; i < info->num_ports; i++) {
+		printf("Port %u - rx: %9"PRIu64"\t"
+				"tx: %9"PRIu64"\n",
+				(unsigned int)info->id[i], info->rx_stats.rx[i],
+				port_tx[i]);
+	}
+
+	printf("\nFLOW DISTRIBUTOR\n");
+	printf("-----\n");
+	printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
+			flow_dist_stats.distributed, flow_dist_stats.drop);
+
+	printf("\nNODES\n");
+	printf("-------\n");
+	for (i = 0; i < num_nodes; i++) {
+		const unsigned long long rx = nodes[i].stats.rx;
+		const unsigned long long rx_drop = nodes[i].stats.rx_drop;
+		const struct filter_stats *filter = &info->filter_stats[i];
+
+		printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
+				"            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
+				"            filter_passed: %9"PRIu64", "
+				"filter_drop: %9"PRIu64"\n",
+				i, rx, rx_drop, node_tx[i], node_tx_drop[i],
+				filter->passed, filter->drop);
+	}
+
+	printf("\n");
+}
+
+/*
+ * The function called from each non-master lcore used by the process.
+ * The test_and_set function is used to randomly pick a single lcore on which
+ * the code to display the statistics will run. Otherwise, the code just
+ * repeatedly sleeps.
+ */
+static int
+sleep_lcore(__attribute__((unused)) void *dummy)
+{
+	/* Used to pick a display thread - static, so zero-initialised */
+	static rte_atomic32_t display_stats;
+
+	/* Only one core should display stats */
+	if (rte_atomic32_test_and_set(&display_stats)) {
+		const unsigned int sleeptime = 1;
+
+		printf("Core %u displaying statistics\n", rte_lcore_id());
+
+		/* Longer initial pause so above printf is seen */
+		sleep(sleeptime * 3);
+
+		/* Loop forever: sleep always returns 0 or <= param */
+		while (sleep(sleeptime) <= sleeptime)
+			do_stats_display();
+	}
+	return 0;
+}
+
+/*
+ * Function to set all the node statistic values to zero.
+ * Called at program startup.
+ */
+static void
+clear_stats(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_nodes; i++)
+		nodes[i].stats.rx = nodes[i].stats.rx_drop = 0;
+}
+
+/*
+ * send a burst of traffic to a node, assuming there are packets
+ * available to be sent to this node
+ */
+static void
+flush_rx_queue(uint16_t node)
+{
+	uint16_t j;
+	struct node *cl;
+
+	if (cl_rx_buf[node].count == 0)
+		return;
+
+	cl = &nodes[node];
+	if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
+			cl_rx_buf[node].count) != 0){
+		for (j = 0; j < cl_rx_buf[node].count; j++)
+			rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+		cl->stats.rx_drop += cl_rx_buf[node].count;
+	} else
+		cl->stats.rx += cl_rx_buf[node].count;
+
+	cl_rx_buf[node].count = 0;
+}
+
+/*
+ * marks a packet down to be sent to a particular node process
+ */
+static inline void
+enqueue_rx_packet(uint8_t node, struct rte_mbuf *buf)
+{
+	cl_rx_buf[node].buffer[cl_rx_buf[node].count++] = buf;
+}
+
+/*
+ * This function takes a group of packets and routes them
+ * individually to the node process. Very simply round-robins the packets
+ * without checking any of the packet contents.
+ */
+static void
+process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
+		uint16_t rx_count, unsigned int socket_id)
+{
+	uint16_t i;
+	uint8_t node;
+	efd_value_t data[RTE_EFD_BURST_MAX];
+	const void *key_ptrs[RTE_EFD_BURST_MAX];
+
+	struct ipv4_hdr *ipv4_hdr;
+	uint32_t ipv4_dst_ip[RTE_EFD_BURST_MAX];
+
+	for (i = 0; i < rx_count; i++) {
+		/* Handle IPv4 header.*/
+		ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
+				sizeof(struct ether_hdr));
+		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+		key_ptrs[i] = (void *)&ipv4_dst_ip[i];
+	}
+
+	rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
+				(const void **) key_ptrs, data);
+	for (i = 0; i < rx_count; i++) {
+		node = (uint8_t) ((uintptr_t)data[i]);
+
+		if (node >= num_nodes) {
+			/*
+			 * Node is out of range, which means that
+			 * flow has not been inserted
+			 */
+			flow_dist_stats.drop++;
+			rte_pktmbuf_free(pkts[i]);
+		} else {
+			flow_dist_stats.distributed++;
+			enqueue_rx_packet(node, pkts[i]);
+		}
+	}
+
+	for (i = 0; i < num_nodes; i++)
+		flush_rx_queue(i);
+}
+
+/*
+ * Function called by the master lcore of the DPDK process.
+ */
+static void
+do_packet_forwarding(void)
+{
+	unsigned int port_num = 0; /* indexes the port[] array */
+	unsigned int socket_id = rte_socket_id();
+
+	for (;;) {
+		struct rte_mbuf *buf[PACKET_READ_SIZE];
+		uint16_t rx_count;
+
+		/* read a port */
+		rx_count = rte_eth_rx_burst(info->id[port_num], 0,
+				buf, PACKET_READ_SIZE);
+		info->rx_stats.rx[port_num] += rx_count;
+
+		/* Now process the NIC packets read */
+		if (likely(rx_count > 0))
+			process_packets(port_num, buf, rx_count, socket_id);
+
+		/* move to next port */
+		if (++port_num == info->num_ports)
+			port_num = 0;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	/* initialise the system */
+	if (init(argc, argv) < 0)
+		return -1;
+	RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+	cl_rx_buf = calloc(num_nodes, sizeof(cl_rx_buf[0]));
+
+	/* clear statistics */
+	clear_stats();
+
+	/* put all other cores to sleep bar master */
+	rte_eal_mp_remote_launch(sleep_lcore, NULL, SKIP_MASTER);
+
+	do_packet_forwarding();
+	return 0;
+}
diff --git a/examples/flow_distributor/node/Makefile b/examples/flow_distributor/node/Makefile
new file mode 100644
index 0000000..8cf7b65
--- /dev/null
+++ b/examples/flow_distributor/node/Makefile
@@ -0,0 +1,48 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = node
+
+# all source are stored in SRCS-y
+SRCS-y := node.c
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/node/node.c b/examples/flow_distributor/node/node.c
new file mode 100644
index 0000000..1f1e7e7
--- /dev/null
+++ b/examples/flow_distributor/node/node.c
@@ -0,0 +1,417 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_log.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_ip.h>
+
+#include "common.h"
+
+/* Number of packets to attempt to read from queue */
+#define PKT_READ_SIZE  ((uint16_t)32)
+
+/*
+ * Our node id number - tells us which rx queue to read, and NIC TX
+ * queue to write to.
+ */
+static uint8_t node_id;
+
+#define MBQ_CAPACITY 32
+
+/* maps input ports to output ports for packets */
+static uint8_t output_ports[RTE_MAX_ETHPORTS];
+
+/* buffers up a set of packet that are ready to send */
+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
+
+/* shared data from distributor. We update statistics here */
+static struct tx_stats *tx_stats;
+
+static struct filter_stats *filter_stats;
+
+/*
+ * print a usage message
+ */
+static void
+usage(const char *progname)
+{
+	printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname);
+}
+
+/*
+ * Convert the node id number from a string to an int.
+ */
+static int
+parse_node_num(const char *node)
+{
+	char *end = NULL;
+	unsigned long temp;
+
+	if (node == NULL || *node == '\0')
+		return -1;
+
+	temp = strtoul(node, &end, 10);
+	if (end == NULL || *end != '\0')
+		return -1;
+
+	node_id = (uint8_t)temp;
+	return 0;
+}
+
+/*
+ * Parse the application arguments to the node app.
+ */
+static int
+parse_app_args(int argc, char *argv[])
+{
+	int option_index, opt;
+	char **argvopt = argv;
+	const char *progname = NULL;
+	static struct option lgopts[] = { /* no long options */
+		{NULL, 0, 0, 0 }
+	};
+	progname = argv[0];
+
+	while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
+		&option_index)) != EOF) {
+		switch (opt) {
+		case 'n':
+			if (parse_node_num(optarg) != 0) {
+				usage(progname);
+				return -1;
+			}
+			break;
+		default:
+			usage(progname);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Tx buffer error callback
+ */
+static void
+flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
+		void *userdata) {
+	int i;
+	uint8_t port_id = (uintptr_t)userdata;
+
+	tx_stats->tx_drop[port_id] += count;
+
+	/* free the mbufs which failed from transmit */
+	for (i = 0; i < count; i++)
+		rte_pktmbuf_free(unsent[i]);
+
+}
+
+static void
+configure_tx_buffer(uint8_t port_id, uint16_t size)
+{
+	int ret;
+
+	/* Initialize TX buffers */
+	tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
+			RTE_ETH_TX_BUFFER_SIZE(size), 0,
+			rte_eth_dev_socket_id(port_id));
+	if (tx_buffer[port_id] == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx "
+				"on port %u\n", (unsigned int) port_id);
+
+	rte_eth_tx_buffer_init(tx_buffer[port_id], size);
+
+	ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
+			flush_tx_error_callback, (void *)(intptr_t)port_id);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Cannot set error callback for "
+			"tx buffer on port %u\n", (unsigned int) port_id);
+}
+
+/*
+ * set up output ports so that all traffic on port gets sent out
+ * its paired port. Index using actual port numbers since that is
+ * what comes in the mbuf structure.
+ */
+static void
+configure_output_ports(const struct shared_info *info)
+{
+	int i;
+
+	if (info->num_ports > RTE_MAX_ETHPORTS)
+		rte_exit(EXIT_FAILURE, "Too many ethernet ports. "
+				"RTE_MAX_ETHPORTS = %u\n",
+				(unsigned int)RTE_MAX_ETHPORTS);
+	for (i = 0; i < info->num_ports - 1; i += 2) {
+		uint8_t p1 = info->id[i];
+		uint8_t p2 = info->id[i+1];
+
+		output_ports[p1] = p2;
+		output_ports[p2] = p1;
+
+		configure_tx_buffer(p1, MBQ_CAPACITY);
+		configure_tx_buffer(p2, MBQ_CAPACITY);
+
+	}
+}
+
+/*
+ * Create the hash table that will contain the flows that
+ * the node will handle, which will be used to decide if packet
+ * is transmitted or dropped.
+ */
+static struct rte_hash *
+create_hash_table(const struct shared_info *info)
+{
+	uint32_t num_flows_node = info->num_flows / info->num_nodes;
+	char name[RTE_HASH_NAMESIZE];
+	struct rte_hash *h;
+
+	/* create table */
+	struct rte_hash_parameters hash_params = {
+		.entries = num_flows_node * 2, /* table load = 50% */
+		.key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
+		.socket_id = rte_socket_id(),
+		.hash_func_init_val = 0,
+	};
+
+	snprintf(name, sizeof(name), "hash_table_%d", node_id);
+	hash_params.name = name;
+	h = rte_hash_create(&hash_params);
+
+	if (h == NULL)
+		rte_exit(EXIT_FAILURE,
+				"Problem creating the hash table for node %d\n",
+				node_id);
+	return h;
+}
+
+static void
+populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
+{
+	unsigned int i;
+	int32_t ret;
+	uint32_t ip_dst;
+	uint32_t num_flows_node = 0;
+	uint64_t target_node;
+
+	/* Add flows in table */
+	for (i = 0; i < info->num_flows; i++) {
+		target_node = i % info->num_nodes;
+		if (target_node != node_id)
+			continue;
+
+		ip_dst = rte_cpu_to_be_32(i);
+
+		ret = rte_hash_add_key(h, (void *) &ip_dst);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Unable to add entry %u "
+					"in hash table\n", i);
+		else
+			num_flows_node++;
+
+	}
+
+	printf("Hash table: Adding 0x%x keys\n", num_flows_node);
+}
+
+/*
+ * This function performs routing of packets
+ * Just sends each input packet out an output port based solely on the input
+ * port it arrived on.
+ */
+static inline void
+transmit_packet(struct rte_mbuf *buf)
+{
+	int sent;
+	const uint8_t in_port = buf->port;
+	const uint8_t out_port = output_ports[in_port];
+	struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
+
+	sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf);
+	if (sent)
+		tx_stats->tx[out_port] += sent;
+
+}
+
+static inline void
+handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint32_t ipv4_dst_ip[PKT_READ_SIZE];
+	const void *key_ptrs[PKT_READ_SIZE];
+	unsigned int i;
+	int32_t positions[PKT_READ_SIZE] = {0};
+
+	for (i = 0; i < num_packets; i++) {
+		/* Handle IPv4 header.*/
+		ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
+				sizeof(struct ether_hdr));
+		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+		key_ptrs[i] = &ipv4_dst_ip[i];
+	}
+	/* Check if packets belongs to any flows handled by this node */
+	rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
+
+	for (i = 0; i < num_packets; i++) {
+		if (likely(positions[i] >= 0)) {
+			filter_stats->passed++;
+			transmit_packet(bufs[i]);
+		} else {
+			filter_stats->drop++;
+			/* Drop packet, as flow is not handled by this node */
+			rte_pktmbuf_free(bufs[i]);
+		}
+	}
+}
+
+/*
+ * Application main function - loops through
+ * receiving and processing packets. Never returns
+ */
+int
+main(int argc, char *argv[])
+{
+	const struct rte_memzone *mz;
+	struct rte_ring *rx_ring;
+	struct rte_hash *h;
+	struct rte_mempool *mp;
+	struct shared_info *info;
+	int need_flush = 0; /* indicates whether we have unsent packets */
+	int retval;
+	void *pkts[PKT_READ_SIZE];
+	uint16_t sent;
+
+	retval = rte_eal_init(argc, argv);
+	if (retval  < 0)
+		return -1;
+	argc -= retval;
+	argv += retval;
+
+	if (parse_app_args(argc, argv) < 0)
+		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
+
+	if (rte_eth_dev_count() == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
+	if (rx_ring == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
+				"is distributor process running?\n");
+
+	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+	if (mp == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
+
+	mz = rte_memzone_lookup(MZ_SHARED_INFO);
+	if (mz == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
+	info = mz->addr;
+	tx_stats = &(info->tx_stats[node_id]);
+	filter_stats = &(info->filter_stats[node_id]);
+
+	configure_output_ports(info);
+
+	h = create_hash_table(info);
+
+	populate_hash_table(h, info);
+
+	RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+	printf("\nNode process %d handling packets\n", node_id);
+	printf("[Press Ctrl-C to quit ...]\n");
+
+	for (;;) {
+		uint16_t  rx_pkts = PKT_READ_SIZE;
+		uint8_t port;
+
+		/*
+		 * Try dequeuing max possible packets first, if that fails,
+		 * get the most we can. Loop body should only execute once,
+		 * maximum
+		 */
+		while (rx_pkts > 0 &&
+				unlikely(rte_ring_dequeue_bulk(rx_ring, pkts,
+					rx_pkts) != 0))
+			rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring),
+					PKT_READ_SIZE);
+
+		if (unlikely(rx_pkts == 0)) {
+			if (need_flush)
+				for (port = 0; port < info->num_ports; port++) {
+					sent = rte_eth_tx_buffer_flush(
+							info->id[port],
+							node_id,
+							tx_buffer[port]);
+					if (unlikely(sent))
+						tx_stats->tx[port] += sent;
+				}
+			need_flush = 0;
+			continue;
+		}
+
+		handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts);
+
+		need_flush = 1;
+	}
+}
diff --git a/examples/flow_distributor/shared/common.h b/examples/flow_distributor/shared/common.h
new file mode 100644
index 0000000..5dcffd6
--- /dev/null
+++ b/examples/flow_distributor/shared/common.h
@@ -0,0 +1,99 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <rte_hash_crc.h>
+#include <rte_hash.h>
+
+#define MAX_NODES             16
+/*
+ * Shared port info, including statistics information for display by distributor.
+ * Structure will be put in a memzone.
+ * - All port id values share one cache line as this data will be read-only
+ * during operation.
+ * - All rx statistic values share cache lines, as this data is written only
+ * by the distributor process. (rare reads by stats display)
+ * - The tx statistics have values for all ports per cache line, but the stats
+ * themselves are written by the nodes, so we have a distinct set, on different
+ * cache lines for each node to use.
+ */
+struct rx_stats {
+	uint64_t rx[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct tx_stats {
+	uint64_t tx[RTE_MAX_ETHPORTS];
+	uint64_t tx_drop[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct filter_stats {
+	uint64_t drop;
+	uint64_t passed;
+} __rte_cache_aligned;
+
+struct shared_info {
+	uint8_t num_nodes;
+	uint8_t num_ports;
+	uint32_t num_flows;
+	uint8_t id[RTE_MAX_ETHPORTS];
+	struct rx_stats rx_stats;
+	struct tx_stats tx_stats[MAX_NODES];
+	struct filter_stats filter_stats[MAX_NODES];
+};
+
+/* define common names for structures shared between distributor and node */
+#define MP_NODE_RXQ_NAME "MProc_Node_%u_RX"
+#define PKTMBUF_POOL_NAME "MProc_pktmbuf_pool"
+#define MZ_SHARED_INFO "MProc_shared_info"
+
+/*
+ * Given the rx queue name template above, get the queue name
+ */
+static inline const char *
+get_rx_queue_name(unsigned int id)
+{
+	/*
+	 * Buffer for return value. Size calculated by %u being replaced
+	 * by maximum 3 digits (plus an extra byte for safety)
+	 */
+	static char buffer[sizeof(MP_NODE_RXQ_NAME) + 2];
+
+	snprintf(buffer, sizeof(buffer) - 1, MP_NODE_RXQ_NAME, id);
+	return buffer;
+}
+
+#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 4/5] doc: add EFD library section in Programmers guide
From: Pablo de Lara @ 2017-01-12 22:15 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Sameh Gobriel
In-Reply-To: <1484259360-198276-1-git-send-email-pablo.de.lara.guarch@intel.com>

Signed-off-by: Sameh Gobriel <sameh.gobriel@intel.com>
Acked-by: Christian Maciocco <christian.maciocco@intel.com>
---
 MAINTAINERS                            |    1 +
 doc/guides/prog_guide/efd_lib.rst      |  428 +++++++++++
 doc/guides/prog_guide/img/efd_i1.svg   |  130 ++++
 doc/guides/prog_guide/img/efd_i10.svg  |  384 ++++++++++
 doc/guides/prog_guide/img/efd_i11.svg  |  319 ++++++++
 doc/guides/prog_guide/img/efd_i12.svg  | 1008 +++++++++++++++++++++++++
 doc/guides/prog_guide/img/efd_i2.svg   |  280 +++++++
 doc/guides/prog_guide/img/efd_i3.svg   |  634 ++++++++++++++++
 doc/guides/prog_guide/img/efd_i4.svg   |  203 ++++++
 doc/guides/prog_guide/img/efd_i5.svg   |  183 +++++
 doc/guides/prog_guide/img/efd_i6.svg   | 1254 ++++++++++++++++++++++++++++++++
 doc/guides/prog_guide/img/efd_i7.svg   |  790 ++++++++++++++++++++
 doc/guides/prog_guide/img/efd_i8.svg   |  182 +++++
 doc/guides/prog_guide/img/efd_i9.svg   |  390 ++++++++++
 doc/guides/prog_guide/index.rst        |   23 +
 doc/guides/rel_notes/release_17_02.rst |    3 +
 16 files changed, 6212 insertions(+)
 create mode 100644 doc/guides/prog_guide/efd_lib.rst
 create mode 100644 doc/guides/prog_guide/img/efd_i1.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i10.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i11.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i12.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i2.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i3.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i4.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i5.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i6.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i7.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i8.svg
 create mode 100644 doc/guides/prog_guide/img/efd_i9.svg

diff --git a/MAINTAINERS b/MAINTAINERS
index b124f6e..66e9466 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -532,6 +532,7 @@ EFD
 M: Byron Marohn <byron.marohn@intel.com>
 M: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>
 F: lib/librte_efd/
+F: doc/guides/prog_guide/efd_lib.rst
 F: app/test/test_efd*
 F: examples/flow_distributor/
 
diff --git a/doc/guides/prog_guide/efd_lib.rst b/doc/guides/prog_guide/efd_lib.rst
new file mode 100644
index 0000000..2358661
--- /dev/null
+++ b/doc/guides/prog_guide/efd_lib.rst
@@ -0,0 +1,428 @@
+..  BSD LICENSE
+    Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of Intel Corporation nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.. _Efd_Library:
+
+Elastic Flow Distributor Library
+================================
+
+Introduction
+------------
+
+In Data Centers today, clustering and scheduling of distributed workloads
+is a very common task. Many workloads require a deterministic
+partitioning of a flat key space among a cluster of machines. When a
+packet enters the cluster, the ingress node will direct the packet to
+its handling node. For example, data-centers with disaggregated storage
+use storage metadata tables to forward I/O requests to the correct back end
+storage cluster, stateful packet inspection will use match incoming
+flows to signatures in flow tables to send incoming packets to their
+intended deep packet inspection (DPI) devices, and so on.
+
+EFD is a distributor library that uses perfect hashing to determine a
+target/value for a given incoming flow key. It has the following
+advantages: first, because it uses perfect hashing it does not store the
+key itself and hence lookup performance is not dependent on the key
+size. Second, the target/value can be any arbitrary value hence the
+system designer and/or operator can better optimize service rates and
+inter-cluster network traffic locating. Third, since the storage
+requirement is much smaller than a hash-based flow table (i.e. better
+fit for CPU cache), EFD can scale to millions of flow keys. Finally,
+with the current optimized library implementation, performance is fully
+scalable with any number of CPU cores.
+
+Flow Based Distribution
+-----------------------
+
+Computation Based Schemes
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Flow distribution and/or load balancing can be simply done using a
+stateless computation, for instance using round-robin or a simple
+computation based on the flow key as an input. For example, a hash
+function can be used to direct a certain flow to a target based on
+the flow key (e.g. ``h(key) mod n``) where h(key) is the hash value of the
+flow key and n is the number of possible targets.
+
+.. _figure_efd1:
+
+.. figure:: img/efd_i1.*
+
+  Load Balancing Using Front End Node
+
+In this scheme (:numref:`figure_efd1`), the front end server/distributor/load balancer
+extracts the flow key from the input packet and applies a computation to determine where
+this flow should be directed. Intuitively, this scheme is very simple
+and requires no state to be kept at the front end node, and hence,
+storage requirements are minimum.
+
+.. _figure_efd2:
+
+.. figure:: img/efd_i2.*
+
+  Consistent Hashing
+
+A widely used flow distributor that belongs to the same category of
+computation-based schemes is ``consistent hashing``, shown in :numref:`figure_efd2`.
+Target destinations (shown in red) are hashed into the same space as the flow
+keys (shown in blue), and keys are mapped to the nearest target in a clockwise
+fashion. Dynamically adding and removing targets with consistent hashing
+requires only K/n keys to be remapped on average, where K is the number of
+keys, and n is the number of targets. In contrast, in a traditional hash-based
+scheme, a change in the number of targets causes nearly all keys to be
+remapped.
+
+Although computation-based schemes are simple and need very little
+storage requirement, they suffer from the drawback that the system
+designer/operator can’t fully control the target to assign a specific
+key, as this is dictated by the hash function.
+Deterministically co-locating of keys together (for example, to minimize
+inter-server traffic or to optimize for network traffic conditions,
+target load, etc.) is simply not possible.
+
+Flow-Table Based Schemes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using a Flow-Table based scheme to handle flow distribution/load
+balancing, in contrast with computation-based schemes, the system designer
+has the flexibility of assigning a given flow to any given
+target. The flow table (e.g. DPDK RTE Hash Library) will simply store
+both the flow key and the target value.
+
+.. _figure_efd3:
+
+.. figure:: img/efd_i3.*
+
+  Table Based Flow Distribution
+
+As shown in :numref:`figure_efd3`, when doing a lookup, the flow-table
+is indexed with the hash of the flow key and the keys (more than one is possible,
+because of hash collision) stored in this index and corresponding values
+are retrieved. The retrieved key(s) is matched with the input flow key
+and if there is a match the value (target id) is returned.
+
+The drawback of using a hash table for flow distribution/load balancing
+is the storage requirement, since the flow table need to store keys,
+signatures and target values. This doesn't allow this scheme to scale to
+millions of flow keys. Large tables will usually not fit in
+the CPU cache, and hence, the lookup performance is degraded because of
+the latency to access the main memory.
+
+EFD Based Scheme
+~~~~~~~~~~~~~~~~
+
+EFD combines the advantages of both flow-table based and computation-based
+schemes. It doesn't require the large storage necessary for
+flow-table based schemes (because EFD doesn't store the key as explained
+below), and it supports any arbitrary value for any given key.
+
+.. _figure_efd4:
+
+.. figure:: img/efd_i4.*
+
+  Searching for Perfect Hash Function
+
+The basic idea of EFD is when a given key is to be inserted, a family of
+hash functions is searched until the correct hash function that maps the
+input key to the correct value is found, as shown in :numref:`figure_efd4`.
+However, rather than explicitly storing all keys and their associated values,
+EFD stores only indices of hash functions that map keys to values, and
+thereby consumes much less space than conventional flow-based tables.
+The lookup operation is very simple, similar to a computational-based
+scheme: given an input key the lookup operation is reduced to hashing
+that key with the correct hash function.
+
+.. _figure_efd5:
+
+.. figure:: img/efd_i5.*
+
+  Divide and Conquer for Millions of Keys
+
+Intuitively, finding a hash function that maps each of a large number
+(millions) of input keys to the correct output value is effectively
+impossible, as a result EFD, as shown in :numref:`figure_efd5`,
+breaks the problem into smaller pieces (divide and conquer).
+EFD divides the entire input key set into many small groups.
+Each group consists of approximately 20-28 keys (a configurable parameter
+for the library), then, for each small group, a brute force search to find
+a hash function that produces the correct outputs for each key in the group.
+
+It should be mentioned that, since the online lookup table for EFD
+doesn't store the key itself, the size of the EFD table is independent
+of the key size and hence EFD lookup performance which is almost
+constant irrespective of the length of the key which is a highly
+desirable feature especially for longer keys.
+
+In summary, EFD is a set separation data structure that supports millions of
+keys. It is used to distribute a given key to an intended target. By itself
+EFD is not a FIB data structure with an exact match the input flow key.
+
+.. _Efd_example:
+
+Example of EFD Library Usage
+----------------------------
+
+EFD can be used along the data path of many network functions and middleboxes.
+As previously mentioned, it can used as an index table for
+<key,value> pairs, meta-data for objects, a flow-level load balancer, etc.
+:numref:`figure_efd6` shows an example of using EFD as a flow-level load
+balancer, where flows are received at a front end server before being forwarded
+to the target back end server for processing. The system designer would
+deterministically co-locate flows together in order to minimize cross-server
+interaction.
+(For example, flows requesting certain webpage objects are co-located
+together, to minimize forwarding of common objects across servers).
+
+.. _figure_efd6:
+
+.. figure:: img/efd_i6.*
+
+  EFD as a Flow-Level Load Balancer
+
+As shown in :numref:`figure_efd6`, the front end server will have an EFD table that
+stores for each group what is the perfect hash index that satisfies the
+correct output. Because the table size is small and fits in cache (since
+keys are not stored), it sustains a large number of flows (N*X, where N
+is the maximum number of flows served by each back end server of the X
+possible targets).
+
+With an input flow key, the group id is computed (for example, using
+last few bits of CRC hash) and then the EFD table is indexed with the
+group id to retrieve the corresponding hash index to use. Once the index
+is retrieved the key is hashed using this hash function and the result
+will be the intended correct target where this flow is supposed to be
+processed.
+
+It should be noted that as a result of EFD not matching the exact key but
+rather distributing the flows to a target back end node based on the
+perfect hash index, a key that has not been inserted before
+will be distributed to a valid target. Hence, a local table which stores
+the flows served at each node is used and is
+exact matched with the input key to rule out new never seen before
+flows.
+
+.. _Efd_api:
+
+Library API Overview
+--------------------
+
+The EFD library API is created with a very similar semantics of a
+hash-index or a flow table. The application creates an EFD table for a
+given maximum number of flows, a function is called to insert a flow key
+with a specific target value, and another function is used to retrieve
+target values for a given individual flow key or a bulk of keys.
+
+EFD Table Create
+~~~~~~~~~~~~~~~~
+
+The function ``rte_efd_create()`` is used to create and return a pointer
+to an EFD table that is sized to hold up to num_flows key.
+The online version of the EFD table (the one that does
+not store the keys and is used for lookups) will be allocated and
+created in the last level cache (LLC) of the socket defined by the
+online_socket_bitmask, while the offline EFD table (the one that
+stores the keys and is used for key inserts and for computing the
+perfect hashing) is allocated and created in the LLC of the socket
+defined by offline_socket_bitmask. It should be noted, that for
+highest performance the socket id should match that where the thread is
+running, i.e. the online EFD lookup table should be created on the same
+socket as where the lookup thread is running.
+
+EFD Insert and Update
+~~~~~~~~~~~~~~~~~~~~~
+
+The EFD function to insert a key or update a key to a new value is
+``rte_efd_update()``. This function will update an existing key to
+a new value (target) if the key has already been inserted
+before, or will insert the <key,value> pair if this key has not been inserted
+before. It will return 0 upon success. It will return
+``EFD_UPDATE_WARN_GROUP_FULL (1)`` if the operation is insert, and the
+last available space in the key's group was just used. It will return
+``EFD_UPDATE_FAILED (2)`` when the insertion or update has failed (either it
+failed to find a suitable perfect hash or the group was full). The function
+will return ``EFD_UPDATE_NO_CHANGE (3)`` if there is no change to the EFD
+table (i.e, same value already exists).
+
+EFD Lookup
+~~~~~~~~~~
+
+To lookup a certain key in an EFD table, the function ``rte_efd_lookup()``
+is used to return the value associated with single key.
+As previously mentioned, if the key has been inserted, the correct value
+inserted is returned, if the key has not been inserted before,
+a ‘random’ value (based on hashing of the key) is returned.
+For better performance and to decrease the overhead of
+function calls per key, it is always recommended to use a bulk lookup
+function (simultaneous lookup of multiple keys) instead of a single key
+lookup function. ``rte_efd_lookup_bulk()`` is the bulk lookup function,
+that looks up num_keys simultaneously stored in the key_list and the
+corresponding return values will be returned in the value_list.
+
+EFD Delete
+~~~~~~~~~~
+
+To delete a certain key in an EFD table, the function
+``rte_efd_delete()`` can be used. The function returns zero upon success 
+when the key has been found and deleted. Socket_id is the parameter to
+use to lookup the existing value, which is ideally the caller's socket id.
+The previous value associated with this key will be returned
+in the prev_value argument.
+
+.. _Efd_internals:
+
+Library Internals
+-----------------
+
+This section provides the brief high-level idea and an overview
+of the library internals to accompany the RFC. The intent of this
+section is to explain to readers the high-level implementation of
+insert, lookup and group rebalancing in the EFD library.
+
+Insert Function Internals
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As previously mentioned the EFD divides the whole set of keys into
+groups of a manageable size (e.g. 28 keys) and then searches for the
+perfect hash that satisfies the intended target value for each key. EFD
+stores two version of the <key,value> table:
+
+-  Offline Version (in memory): Only used for the insertion/update
+   operation, which is less frequent than the lookup operation. In the
+   offline version the exact keys for each group is stored. When a new
+   key is added, the hash function is updated that will satisfy the
+   value for the new key together with the all old keys already inserted
+   in this group.
+
+-  Online Version (in cache): Used for the frequent lookup operation. In
+   the online version, as previously mentioned, the keys are not stored
+   but rather only the hash index for each group.
+
+.. _figure_efd7:
+
+.. figure:: img/efd_i7.*
+
+  Group Assignment
+
+:numref:`figure_efd7` depicts the group assignment for 7 flow keys as an example.
+Given a flow key, a hash function (in our implementation CRC hash) is
+used to get the group id. As shown in the figure, the groups can be
+unbalanced. (We highlight group rebalancing further below).
+
+.. _figure_efd8:
+
+.. figure:: img/efd_i8.*
+
+  Perfect Hash Search - Assigned Keys & Target Value
+
+Focusing on one group that has four keys, :numref:`figure_efd8` depicts the search
+algorithm to find the perfect hash function. Assuming that the target
+value bit for the keys is as shown in the figure, then the online EFD
+table will store a 16 bit hash index and 16 bit lookup table per group
+per value bit.
+
+.. _figure_efd9:
+
+.. figure:: img/efd_i9.*
+
+  Perfect Hash Search - Satisfy Target Values
+
+For a given keyX, a hash function ``(h(keyX, seed1) + index * h(keyX, seed2))``
+is used to point to certain bit index in the 16bit lookup_table value,
+as shown in :numref:`figure_efd9`.
+The insert function will brute force search for all possible values for the
+hash index until a non conflicting lookup_table is found.
+
+.. _figure_efd10:
+
+.. figure:: img/efd_i10.*
+
+  Finding Hash Index for Conflict Free lookup_table
+
+For example, since both key3 and key7 have a target bit value of 1, it
+is okay if the hash function of both keys point to the same bit in the
+lookup table. A conflict will occur if a hash index is used that maps
+both Key4 and Key7 to the same index in the lookup_table,
+as shown in :numref:`figure_efd10`, since their target value bit are not the same.
+Once a hash index is found that produces a lookup_table with no
+contradictions, this index is stored for this group. This procedure is
+repeated for each bit of target value.
+
+Lookup Function Internals
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The design principle of EFD is that lookups are much more frequent than
+inserts, and hence, EFD's design optimizes for the lookups which are
+faster and much simpler than the slower insert procedure (inserts are
+slow, because of perfect hash search as previously discussed).
+
+.. _figure_efd11:
+
+.. figure:: img/efd_i11.*
+
+  EFD Lookup Operation
+
+:numref:`figure_efd11` depicts the lookup operation for EFD. Given an input key,
+the group id is computed (using CRC hash) and then the hash index for this
+group is retrieved from the EFD table. Using the retrieved hash index,
+the hash function ``h(key, seed1) + index *h(key, seed2)`` is used which will
+result in an index in the lookup_table, the bit corresponding to this
+index will be the target value bit. This procedure is repeated for each
+bit of the target value.
+
+Group Rebalancing Function Internals
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When discussing EFD inserts and lookups, the discussion is simplified by
+assuming that a group id is simply a result of hash function. However,
+since hashing in general is not perfect and will not always produce a
+uniform output, this simplified assumption will lead to unbalanced
+groups, i.e., some group will have more keys than other groups.
+Typically, and to minimize insert time with an increasing number of keys,
+it is preferable that all groups will have a balanced number of keys, so
+the brute force search for the perfect hash terminates with a valid hash
+index. In order to achieve this target, groups are rebalanced during
+runtime inserts, and keys are moved around from a busy group to a less
+crowded group as the more keys are inserted.
+
+.. _figure_efd12:
+
+.. figure:: img/efd_i12.*
+
+  Runtime Group Rebalancing
+
+:numref:`figure_efd12` depicts the high level idea of group rebalancing, given an
+input key the hash result is split into two parts a chunk id and 8-bit
+bin id. A chunk contains 64 different groups and 256 bins (i.e. for any
+given bin it can map to 4 distinct groups). When a key is inserted, the
+bin id is computed, for example in :numref:`figure_efd12` bin_id=2,
+and since each bin can be mapped to one of four different groups (2 bit storage),
+the four possible mappings are evaluated and the one that will result in a
+balanced key distribution across these four is selected the mapping result
+is stored in these two bits.
diff --git a/doc/guides/prog_guide/img/efd_i1.svg b/doc/guides/prog_guide/img/efd_i1.svg
new file mode 100644
index 0000000..7f8fcb3
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i1.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i1.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="3.25609in" height="3.375in"
+		viewBox="0 0 234.439 243" xml:space="preserve" color-interpolation-filters="sRGB" class="st10">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+		.st5 {marker-end:url(#mrkr5-12);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:6}
+		.st6 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.70422535211268}
+		.st7 {stroke:#5b9bd5;stroke-dasharray:2.25,4.5;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.25}
+		.st8 {marker-end:url(#mrkr5-39);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st9 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st10 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-12" class="st6" v:arrowType="5" v:arrowSize="2" v:setback="2.485" refX="-2.485" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-1.42,-1.42) "/>
+		</marker>
+		<marker id="mrkr5-39" class="st9" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(77.718,-113.348)">
+			<title>Square</title>
+			<desc>LB</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="18" cy="225" width="36" height="36"/>
+			<g id="shadow2-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="207" width="36" height="36" class="st2"/>
+			</g>
+			<rect x="0" y="207" width="36" height="36" class="st3"/>
+			<text x="13.18" y="228" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>LB</text>		</g>
+		<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(37.0513,-131.348)">
+			<title>Sheet.3</title>
+			<path d="M0 243 L25.76 243" class="st5"/>
+		</g>
+		<g id="shape4-13" v:mID="4" v:groupContext="shape" transform="translate(167.718,-178.598)">
+			<title>Square.4</title>
+			<desc>Target 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="220.5" width="45" height="45"/>
+			<g id="shadow4-14" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="198" width="45" height="45" class="st2"/>
+			</g>
+			<rect x="0" y="198" width="45" height="45" class="st3"/>
+			<text x="5.74" y="223.5" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Target 1</text>		</g>
+		<g id="shape5-19" v:mID="5" v:groupContext="shape" transform="translate(167.718,-121.005)">
+			<title>Square.5</title>
+			<desc>Target 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="220.5" width="45" height="45"/>
+			<g id="shadow5-20" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="198" width="45" height="45" class="st2"/>
+			</g>
+			<rect x="0" y="198" width="45" height="45" class="st3"/>
+			<text x="5.74" y="223.5" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Target 2</text>		</g>
+		<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(167.718,-23.3478)">
+			<title>Square.7</title>
+			<desc>Target N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="220.5" width="45" height="45"/>
+			<g id="shadow7-26" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="198" width="45" height="45" class="st2"/>
+			</g>
+			<rect x="0" y="198" width="45" height="45" class="st3"/>
+			<text x="5.05" y="223.5" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Target N</text>		</g>
+		<g id="shape8-31" v:mID="8" v:groupContext="shape" transform="translate(433.218,132.402) rotate(90)">
+			<title>Sheet.8</title>
+			<path d="M0 243 L34.59 243" class="st7"/>
+		</g>
+		<g id="shape9-34" v:mID="9" v:groupContext="shape" transform="translate(-78.4279,-37.1059) rotate(-52.2532)">
+			<title>Sheet.9</title>
+			<path d="M0 243 L81.18 243" class="st8"/>
+		</g>
+		<g id="shape11-40" v:mID="11" v:groupContext="shape" transform="translate(60.3469,-125.414) rotate(-12.6875)">
+			<title>Sheet.11</title>
+			<path d="M0 243 L48.32 243" class="st8"/>
+		</g>
+		<g id="shape12-45" v:mID="12" v:groupContext="shape" transform="translate(319.172,-18.1081) rotate(57.7244)">
+			<title>Sheet.12</title>
+			<path d="M0 243 L94.09 243" class="st8"/>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i10.svg b/doc/guides/prog_guide/img/efd_i10.svg
new file mode 100644
index 0000000..d26ec61
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i10.svg
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i11.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="9.76715in" height="2.82917in"
+		viewBox="0 0 703.234 203.701" xml:space="preserve" color-interpolation-filters="sRGB" class="st15">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st2 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st3 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st4 {fill:#000000;font-family:Arial;font-size:0.998566em}
+		.st5 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st6 {fill:#000000;font-family:Arial;font-size:0.918686em;font-style:italic}
+		.st7 {fill:#000000;font-family:Arial;font-size:0.918686em}
+		.st8 {fill:#7e8d96;font-family:Arial;font-size:0.998566em;font-weight:bold}
+		.st9 {fill:#00b050;font-family:Arial;font-size:0.998566em;font-weight:bold}
+		.st10 {fill:#ff0000;font-family:Arial;font-size:0.998566em;font-weight:bold}
+		.st11 {fill:#004280;stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st12 {fill:#ffffff;font-family:Arial;font-size:1.49785em}
+		.st13 {stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st14 {fill:#004280;stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0149927}
+		.st15 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(19.0195,-93.4328)">
+			<title>Sheet.3</title>
+			<path d="M0 182.93 C0 180.64 1.87 178.78 4.16 178.78 L109.18 178.78 C111.47 178.78 113.33 180.64 113.33 182.93 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.16 203.7 C1.87 203.7 0 201.84 0 199.55 L0 182.93 Z"
+					class="st1"/>
+		</g>
+		<g id="shape4-3" v:mID="4" v:groupContext="shape" transform="translate(19.0195,-93.4328)">
+			<title>Sheet.4</title>
+			<path d="M0 182.93 C0 180.64 1.87 178.78 4.16 178.78 L109.18 178.78 C111.47 178.78 113.33 180.64 113.33 182.93 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.16 203.7 C1.87 203.7 0 201.84 0 199.55 L0 182.93 Z"
+					class="st2"/>
+		</g>
+		<g id="shape5-5" v:mID="5" v:groupContext="shape" transform="translate(19.0195,-96.9057)">
+			<title>Sheet.5</title>
+			<desc>Key1: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="58.0575" cy="196.509" width="116.12" height="14.3829"/>
+			<path d="M116.11 189.32 L0 189.32 L0 203.7 L116.11 203.7 L116.11 189.32" class="st3"/>
+			<text x="15.59" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key1: Value = 0</text>		</g>
+		<g id="shape6-9" v:mID="6" v:groupContext="shape" transform="translate(19.0195,-68.6284)">
+			<title>Sheet.6</title>
+			<path d="M0 182.93 C0 180.64 1.87 178.78 4.16 178.78 L109.18 178.78 C111.47 178.78 113.33 180.64 113.33 182.93 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.16 203.7 C1.87 203.7 0 201.84 0 199.55 L0 182.93 Z"
+					class="st1"/>
+		</g>
+		<g id="shape7-11" v:mID="7" v:groupContext="shape" transform="translate(19.0195,-68.6284)">
+			<title>Sheet.7</title>
+			<path d="M0 182.93 C0 180.64 1.87 178.78 4.16 178.78 L109.18 178.78 C111.47 178.78 113.33 180.64 113.33 182.93 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.16 203.7 C1.87 203.7 0 201.84 0 199.55 L0 182.93 Z"
+					class="st2"/>
+		</g>
+		<g id="shape8-13" v:mID="8" v:groupContext="shape" transform="translate(19.0195,-72.0832)">
+			<title>Sheet.8</title>
+			<desc>Key3: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="58.0575" cy="196.509" width="116.12" height="14.3829"/>
+			<path d="M116.11 189.32 L0 189.32 L0 203.7 L116.11 203.7 L116.11 189.32" class="st3"/>
+			<text x="15.59" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key3: Value = 1</text>		</g>
+		<g id="shape9-17" v:mID="9" v:groupContext="shape" transform="translate(19.0195,-43.5843)">
+			<title>Sheet.9</title>
+			<path d="M0 182.84 C-0 180.53 1.88 178.66 4.19 178.66 L109.15 178.66 C111.46 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.53 C113.33 201.84 111.46 203.7 109.15 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.53 L0 182.84 Z"
+					class="st1"/>
+		</g>
+		<g id="shape10-19" v:mID="10" v:groupContext="shape" transform="translate(19.0195,-43.5843)">
+			<title>Sheet.10</title>
+			<path d="M0 182.84 C-0 180.53 1.88 178.66 4.19 178.66 L109.15 178.66 C111.46 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.53 C113.33 201.84 111.46 203.7 109.15 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.53 L0 182.84 Z"
+					class="st2"/>
+		</g>
+		<g id="shape11-21" v:mID="11" v:groupContext="shape" transform="translate(19.0195,-47.1109)">
+			<title>Sheet.11</title>
+			<desc>Key4: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="58.0575" cy="196.509" width="116.12" height="14.3829"/>
+			<path d="M116.11 189.32 L0 189.32 L0 203.7 L116.11 203.7 L116.11 189.32" class="st3"/>
+			<text x="15.59" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key4: Value = 0</text>		</g>
+		<g id="shape12-25" v:mID="12" v:groupContext="shape" transform="translate(19.0195,-19.0195)">
+			<title>Sheet.12</title>
+			<path d="M0 182.84 C-0 180.53 1.88 178.66 4.19 178.66 L109.15 178.66 C111.46 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.53 C113.33 201.84 111.46 203.7 109.15 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.53 L0 182.84 Z"
+					class="st1"/>
+		</g>
+		<g id="shape13-27" v:mID="13" v:groupContext="shape" transform="translate(19.0195,-19.0195)">
+			<title>Sheet.13</title>
+			<path d="M0 182.84 C-0 180.53 1.88 178.66 4.19 178.66 L109.15 178.66 C111.46 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.53 C113.33 201.84 111.46 203.7 109.15 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.53 L0 182.84 Z"
+					class="st2"/>
+		</g>
+		<g id="shape14-29" v:mID="14" v:groupContext="shape" transform="translate(19.0195,-22.5475)">
+			<title>Sheet.14</title>
+			<desc>Key7: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="58.0575" cy="196.509" width="116.12" height="14.3829"/>
+			<path d="M116.11 189.32 L0 189.32 L0 203.7 L116.11 203.7 L116.11 189.32" class="st3"/>
+			<text x="15.59" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key7: Value = 1</text>		</g>
+		<g id="shape15-33" v:mID="15" v:groupContext="shape" transform="translate(141.656,-45.5615)">
+			<title>Sheet.15</title>
+			<path d="M0 169.01 L22.75 169.01 L22.75 157.45 L45.5 180.57 L22.75 203.7 L22.75 192.14 L0 192.14 L0 169.01 Z"
+					class="st5"/>
+		</g>
+		<g id="shape16-35" v:mID="16" v:groupContext="shape" transform="translate(193.22,-56.0464)">
+			<title>Sheet.16</title>
+			<path d="M0 182.84 C0 180.53 1.88 178.66 4.19 178.66 L96.55 178.66 C98.87 178.66 100.73 180.53 100.73 182.84 L100.73
+						 199.54 C100.73 201.84 98.87 203.7 96.55 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.54 L0 182.84 Z"
+					class="st1"/>
+		</g>
+		<g id="shape17-37" v:mID="17" v:groupContext="shape" transform="translate(193.22,-56.0464)">
+			<title>Sheet.17</title>
+			<path d="M0 182.84 C0 180.53 1.88 178.66 4.19 178.66 L96.55 178.66 C98.87 178.66 100.73 180.53 100.73 182.84 L100.73
+						 199.54 C100.73 201.84 98.87 203.7 96.55 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.54 L0 182.84 Z"
+					class="st2"/>
+		</g>
+		<g id="shape18-39" v:mID="18" v:groupContext="shape" transform="translate(228.157,-66.9545)">
+			<title>Sheet.18</title>
+			<desc>F</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.63538" cy="197.084" width="11.28" height="13.2327"/>
+			<path d="M11.27 190.47 L0 190.47 L0 203.7 L11.27 203.7 L11.27 190.47" class="st3"/>
+			<text x="2.27" y="200.39" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>F</text>		</g>
+		<g id="shape19-43" v:mID="19" v:groupContext="shape" transform="translate(234.88,-66.9545)">
+			<title>Sheet.19</title>
+			<desc>(key,</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.261" cy="197.084" width="34.53" height="13.2327"/>
+			<path d="M34.52 190.47 L0 190.47 L0 203.7 L34.52 203.7 L34.52 190.47" class="st3"/>
+			<text x="5.32" y="200.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(key,  </text>		</g>
+		<g id="shape20-47" v:mID="20" v:groupContext="shape" transform="translate(198.215,-53.7734)">
+			<title>Sheet.20</title>
+			<desc>hash_index =</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="41.4128" cy="197.084" width="82.83" height="13.2327"/>
+			<path d="M82.83 190.47 L0 190.47 L0 203.7 L82.83 203.7 L82.83 190.47" class="st3"/>
+			<text x="8.47" y="200.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash_index =  </text>		</g>
+		<g id="shape21-51" v:mID="21" v:groupContext="shape" transform="translate(274.858,-53.7734)">
+			<title>Sheet.21</title>
+			<desc>i)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.28241" cy="197.084" width="10.57" height="13.2327"/>
+			<path d="M10.56 190.47 L0 190.47 L0 203.7 L10.56 203.7 L10.56 190.47" class="st3"/>
+			<text x="2.22" y="200.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>i)</text>		</g>
+		<g id="shape22-55" v:mID="22" v:groupContext="shape" transform="translate(351.453,-93.7923)">
+			<title>Sheet.22</title>
+			<path d="M0 182.84 C0 180.53 1.88 178.66 4.19 178.66 L109.16 178.66 C111.47 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.54 C113.33 201.84 111.47 203.7 109.16 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.54 L0 182.84 Z"
+					class="st1"/>
+		</g>
+		<g id="shape23-57" v:mID="23" v:groupContext="shape" transform="translate(351.453,-93.7923)">
+			<title>Sheet.23</title>
+			<path d="M0 182.84 C0 180.53 1.88 178.66 4.19 178.66 L109.16 178.66 C111.47 178.66 113.33 180.53 113.33 182.84 L113.33
+						 199.54 C113.33 201.84 111.47 203.7 109.16 203.7 L4.19 203.7 C1.88 203.7 0 201.84 0 199.54 L0 182.84 Z"
+					class="st2"/>
+		</g>
+		<g id="shape24-59" v:mID="24" v:groupContext="shape" transform="translate(355.798,-97.3147)">
+			<title>Sheet.24</title>
+			<desc>Key1: Position 4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="51.7083" cy="196.509" width="103.42" height="14.3829"/>
+			<path d="M103.42 189.32 L0 189.32 L0 203.7 L103.42 203.7 L103.42 189.32" class="st3"/>
+			<text x="8.41" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key1: Position 4</text>		</g>
+		<g id="shape25-63" v:mID="25" v:groupContext="shape" transform="translate(351.453,-68.9879)">
+			<title>Sheet.25</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape26-65" v:mID="26" v:groupContext="shape" transform="translate(351.453,-68.9879)">
+			<title>Sheet.26</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape27-67" v:mID="27" v:groupContext="shape" transform="translate(355.798,-72.4921)">
+			<title>Sheet.27</title>
+			<desc>Key3: Position 6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="51.7083" cy="196.509" width="103.42" height="14.3829"/>
+			<path d="M103.42 189.32 L0 189.32 L0 203.7 L103.42 203.7 L103.42 189.32" class="st3"/>
+			<text x="8.41" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key3: Position 6</text>		</g>
+		<g id="shape28-71" v:mID="28" v:groupContext="shape" transform="translate(351.453,-44.0636)">
+			<title>Sheet.28</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape29-73" v:mID="29" v:groupContext="shape" transform="translate(351.453,-44.0636)">
+			<title>Sheet.29</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape30-75" v:mID="30" v:groupContext="shape" transform="translate(351.215,-47.5198)">
+			<title>Sheet.30</title>
+			<desc>Key4: Position 14</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="55.5403" cy="196.509" width="111.09" height="14.3829"/>
+			<path d="M111.08 189.32 L0 189.32 L0 203.7 L111.08 203.7 L111.08 189.32" class="st3"/>
+			<text x="8.91" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key4: Position 14</text>		</g>
+		<g id="shape31-79" v:mID="31" v:groupContext="shape" transform="translate(351.453,-19.4988)">
+			<title>Sheet.31</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape32-81" v:mID="32" v:groupContext="shape" transform="translate(351.453,-19.4988)">
+			<title>Sheet.32</title>
+			<path d="M0 182.94 C0 180.65 1.88 178.78 4.17 178.78 L109.18 178.78 C111.47 178.78 113.33 180.65 113.33 182.94 L113.33
+						 199.55 C113.33 201.84 111.47 203.7 109.18 203.7 L4.17 203.7 C1.88 203.7 0 201.84 0 199.55 L0 182.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape33-83" v:mID="33" v:groupContext="shape" transform="translate(351.215,-22.9565)">
+			<title>Sheet.33</title>
+			<desc>Key7: Position 14</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="55.5403" cy="196.509" width="111.09" height="14.3829"/>
+			<path d="M111.08 189.32 L0 189.32 L0 203.7 L111.08 203.7 L111.08 189.32" class="st3"/>
+			<text x="8.91" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key7: Position 14</text>		</g>
+		<g id="shape34-87" v:mID="34" v:groupContext="shape" transform="translate(299.89,-46.0408)">
+			<title>Sheet.34</title>
+			<path d="M0 169.01 L22.75 169.01 L22.75 157.45 L45.5 180.57 L22.75 203.7 L22.75 192.14 L0 192.14 L0 169.01 Z"
+					class="st5"/>
+		</g>
+		<g id="shape35-89" v:mID="35" v:groupContext="shape" transform="translate(528.896,-117.518)">
+			<title>Sheet.35</title>
+			<path d="M0 182.94 C0 180.66 1.89 178.78 4.17 178.78 L137.64 178.78 C139.92 178.78 141.79 180.66 141.79 182.94 L141.79
+						 199.57 C141.79 201.84 139.92 203.7 137.64 203.7 L4.17 203.7 C1.89 203.7 0 201.84 0 199.57 L0 182.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape36-91" v:mID="36" v:groupContext="shape" transform="translate(528.896,-117.518)">
+			<title>Sheet.36</title>
+			<path d="M0 182.94 C0 180.66 1.89 178.78 4.17 178.78 L137.64 178.78 C139.92 178.78 141.79 180.66 141.79 182.94 L141.79
+						 199.57 C141.79 201.84 139.92 203.7 137.64 203.7 L4.17 203.7 C1.89 203.7 0 201.84 0 199.57 L0 182.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape37-93" v:mID="37" v:groupContext="shape" transform="translate(530.056,-121.017)">
+			<title>Sheet.37</title>
+			<desc>0000</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="19.1585" cy="196.509" width="38.32" height="14.3829"/>
+			<path d="M38.32 189.32 L0 189.32 L0 203.7 L38.32 203.7 L38.32 189.32" class="st3"/>
+			<text x="5.83" y="200.1" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0000  </text>		</g>
+		<g id="shape38-97" v:mID="38" v:groupContext="shape" transform="translate(567.215,-121.017)">
+			<title>Sheet.38</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.7483" cy="196.509" width="11.5" height="14.3829"/>
+			<path d="M11.5 189.32 L0 189.32 L0 203.7 L11.5 203.7 L11.5 189.32" class="st3"/>
+			<text x="2.42" y="200.1" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape39-101" v:mID="39" v:groupContext="shape" transform="translate(576.215,-121.017)">
+			<title>Sheet.39</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.7483" cy="196.509" width="11.5" height="14.3829"/>
+			<path d="M11.5 189.32 L0 189.32 L0 203.7 L11.5 203.7 L11.5 189.32" class="st3"/>
+			<text x="2.42" y="200.1" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape40-105" v:mID="40" v:groupContext="shape" transform="translate(584.486,-121.017)">
+			<title>Sheet.40</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.7483" cy="196.509" width="11.5" height="14.3829"/>
+			<path d="M11.5 189.32 L0 189.32 L0 203.7 L11.5 203.7 L11.5 189.32" class="st3"/>
+			<text x="2.42" y="200.1" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape41-109" v:mID="41" v:groupContext="shape" transform="translate(588.646,-121.017)">
+			<title>Sheet.41</title>
+			<desc>0 0000 00</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="32.5687" cy="196.509" width="65.14" height="14.3829"/>
+			<path d="M65.14 189.32 L0 189.32 L0 203.7 L65.14 203.7 L65.14 189.32" class="st3"/>
+			<text x="5.91" y="200.1" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0 0000 00</text>		</g>
+		<g id="shape42-113" v:mID="42" v:groupContext="shape" transform="translate(644.965,-121.017)">
+			<title>Sheet.42</title>
+			<desc>?</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="6.12511" cy="196.509" width="12.26" height="14.3829"/>
+			<path d="M12.25 189.32 L0 189.32 L0 203.7 L12.25 203.7 L12.25 189.32" class="st3"/>
+			<text x="2.47" y="200.1" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>?</text>		</g>
+		<g id="shape43-117" v:mID="43" v:groupContext="shape" transform="translate(654.718,-121.017)">
+			<title>Sheet.43</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="5.7483" cy="196.509" width="11.5" height="14.3829"/>
+			<path d="M11.5 189.32 L0 189.32 L0 203.7 L11.5 203.7 L11.5 189.32" class="st3"/>
+			<text x="2.42" y="200.1" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape44-121" v:mID="44" v:groupContext="shape" transform="translate(464.786,-105.296)">
+			<title>Sheet.44</title>
+			<path d="M0 203.7 L108.29 203.7 C108.86 203.7 109.31 203.22 109.31 202.68 L109.31 189.5 L107.27 189.5 L107.27 202.68
+						 L108.29 201.66 L0 201.66 L0 203.7 ZM111.35 190.52 L108.29 184.41 L105.23 190.55 L111.35 190.52 Z"
+					class="st11"/>
+		</g>
+		<g id="shape45-123" v:mID="45" v:groupContext="shape" transform="translate(464.786,-80.4315)">
+			<title>Sheet.45</title>
+			<path d="M0 203.7 L123.63 203.7 C124.2 203.7 124.65 203.25 124.65 202.68 L124.65 164.28 L122.61 164.28 L122.61 202.68
+						 L123.63 201.66 L0 201.66 L0 203.7 ZM126.69 165.3 L123.6 159.18 L120.57 165.33 L126.69 165.3 Z"
+					class="st11"/>
+		</g>
+		<g id="shape46-125" v:mID="46" v:groupContext="shape" transform="translate(464.786,-55.4772)">
+			<title>Sheet.46</title>
+			<path d="M0 203.7 L186.48 203.7 C186.75 203.7 186.99 203.61 187.2 203.4 C187.38 203.22 187.5 202.95 187.5 202.68 L187.41
+						 139.32 L185.37 139.32 L185.46 202.68 L186.48 201.66 L0 201.66 L0 203.7 ZM189.51 140.07 L185.94 134.23 L183.41
+						 140.61 L189.51 140.07 Z" class="st11"/>
+		</g>
+		<g id="shape47-127" v:mID="47" v:groupContext="shape" transform="translate(464.786,-30.9125)">
+			<title>Sheet.47</title>
+			<path d="M0 203.7 L186.48 203.7 C186.75 203.7 186.99 203.61 187.2 203.4 C187.38 203.22 187.5 202.95 187.5 202.68 L187.41
+						 114.76 L185.37 114.76 L185.46 202.68 L186.48 201.66 L0 201.66 L0 203.7 ZM189.51 115.51 L185.94 109.67 L183.41
+						 116.05 L189.51 115.51 Z" class="st11"/>
+		</g>
+		<g id="shape48-129" v:mID="48" v:groupContext="shape" transform="translate(442.996,-151.106)">
+			<title>Sheet.48</title>
+			<path d="M0 179.56 C0 176.89 2.19 174.7 4.86 174.7 L70.8 174.7 C73.47 174.7 75.64 176.89 75.64 179.56 L75.64 198.88 C75.64
+						 201.54 73.47 203.7 70.8 203.7 L4.86 203.7 C2.19 203.7 0 201.54 0 198.88 L0 179.56 Z" class="st5"/>
+		</g>
+		<g id="shape49-131" v:mID="49" v:groupContext="shape" transform="translate(443.529,-155.018)">
+			<title>Sheet.49</title>
+			<desc>Values</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="37.8175" cy="192.914" width="75.64" height="21.5726"/>
+			<path d="M75.64 182.13 L0 182.13 L0 203.7 L75.64 203.7 L75.64 182.13" class="st3"/>
+			<text x="10.34" y="198.31" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Values</text>		</g>
+		<g id="shape50-135" v:mID="50" v:groupContext="shape" transform="translate(102.458,-122.192)">
+			<title>Sheet.50</title>
+			<path d="M0 203.7 C-0 199.21 0.62 195.55 1.37 195.55 L11.67 195.55 C12.42 195.55 13.03 191.9 13.03 187.4 C13.03 191.9
+						 13.64 195.55 14.39 195.55 L24.69 195.55 C25.44 195.55 26.05 199.21 26.05 203.7" class="st13"/>
+		</g>
+		<g id="shape51-138" v:mID="51" v:groupContext="shape" transform="translate(115.454,-137.5)">
+			<title>Sheet.51</title>
+			<path d="M0.2 203.7 L322.66 174.12 L322.48 172.1 L0 201.68 L0.2 203.7 L0.2 203.7 ZM321.84 176.24 L327.66 172.64 L321.28
+						 170.16 L321.84 176.24 L321.84 176.24 Z" class="st14"/>
+		</g>
+		<g id="shape52-140" v:mID="52" v:groupContext="shape" transform="translate(518.211,-142.473)">
+			<title>Sheet.52</title>
+			<path d="M0.99 176.74 L44.78 200.38 L43.82 202.17 L0 178.51 L0.99 176.74 L0.99 176.74 ZM44.87 198.1 L48.8 203.7 L41.96
+						 203.46 L44.87 198.1 L44.87 198.1 Z" class="st11"/>
+		</g>
+		<g id="shape53-142" v:mID="53" v:groupContext="shape" transform="translate(518.331,-141.963)">
+			<title>Sheet.53</title>
+			<path d="M0.75 176.17 L60.09 200.32 L59.34 202.2 L0 178.06 L0.75 176.17 L0.75 176.17 ZM59.91 198.04 L64.44 203.19 L57.6
+						 203.7 L59.91 198.04 L59.91 198.04 Z" class="st11"/>
+		</g>
+		<g id="shape54-144" v:mID="54" v:groupContext="shape" transform="translate(576.558,-153.706)">
+			<title>Sheet.54</title>
+			<path d="M0 177.04 C0 174.1 2.4 171.71 5.34 171.71 L101.51 171.71 C104.48 171.71 106.85 174.1 106.85 177.04 L106.85 198.37
+						 C106.85 201.33 104.48 203.7 101.51 203.7 L5.34 203.7 C2.4 203.7 0 201.33 0 198.37 L0 177.04 Z" class="st1"/>
+		</g>
+		<g id="shape55-146" v:mID="55" v:groupContext="shape" transform="translate(577.365,-151.611)">
+			<title>Sheet.55</title>
+			<path d="M0 177.04 C0 174.1 2.4 171.71 5.34 171.71 L101.51 171.71 C104.48 171.71 106.85 174.1 106.85 177.04 L106.85 198.37
+						 C106.85 201.33 104.48 203.7 101.51 203.7 L5.34 203.7 C2.4 203.7 0 201.33 0 198.37 L0 177.04 Z" class="st2"/>
+		</g>
+		<g id="shape56-148" v:mID="56" v:groupContext="shape" transform="translate(593.952,-167.894)">
+			<title>Sheet.56</title>
+			<desc>Lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.2942" cy="196.509" width="86.59" height="14.3829"/>
+			<path d="M86.59 189.32 L0 189.32 L0 203.7 L86.59 203.7 L86.59 189.32" class="st3"/>
+			<text x="7.31" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Lookup_table</text>		</g>
+		<g id="shape57-152" v:mID="57" v:groupContext="shape" transform="translate(608.239,-153.515)">
+			<title>Sheet.57</title>
+			<desc>(16 bits)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="26.8054" cy="196.509" width="53.62" height="14.3829"/>
+			<path d="M53.61 189.32 L0 189.32 L0 203.7 L53.61 203.7 L53.61 189.32" class="st3"/>
+			<text x="5.16" y="200.1" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(16 bits)</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i11.svg b/doc/guides/prog_guide/img/efd_i11.svg
new file mode 100644
index 0000000..f2cc656
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i11.svg
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i12.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="10.2783in" height="4.28958in"
+		viewBox="0 0 740.039 308.85" xml:space="preserve" color-interpolation-filters="sRGB" class="st21">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st2 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st3 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st4 {fill:#000000;font-family:Arial;font-size:0.998566em}
+		.st5 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st6 {stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st7 {stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st8 {fill:#000000;font-family:Arial;font-size:0.918686em;font-weight:bold}
+		.st9 {fill:#00b050;font-size:1em}
+		.st10 {fill:#c00000;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st11 {fill:#004280;stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.00749637}
+		.st12 {fill:#ffffff;font-family:Arial;font-size:1.16833em}
+		.st13 {fill:#2e75b5;stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st14 {fill:#ffffff;font-family:Arial;font-size:1.16666em}
+		.st15 {font-size:1em}
+		.st16 {fill:none;stroke:none;stroke-width:0.25}
+		.st17 {fill:#000000;font-family:Calibri;font-size:1.00001em}
+		.st18 {marker-end:url(#mrkr5-121);stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st19 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st20 {fill:#000000;font-family:Calibri;font-size:1.16666em}
+		.st21 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-121" class="st19" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape5-1" v:mID="5" v:groupContext="shape" transform="translate(36.0674,-256.878)">
+			<title>Sheet.5</title>
+			<path d="M0 291.88 C0 290 1.52 288.48 3.41 288.48 L68.51 288.48 C70.4 288.48 71.91 290 71.91 291.88 L71.91 305.46 C71.91
+						 307.33 70.4 308.85 68.51 308.85 L3.41 308.85 C1.52 308.85 0 307.33 0 305.46 L0 291.88 Z" class="st1"/>
+		</g>
+		<g id="shape6-3" v:mID="6" v:groupContext="shape" transform="translate(36.0674,-256.878)">
+			<title>Sheet.6</title>
+			<path d="M0 291.88 C0 290 1.52 288.48 3.41 288.48 L68.51 288.48 C70.4 288.48 71.91 290 71.91 291.88 L71.91 305.46 C71.91
+						 307.33 70.4 308.85 68.51 308.85 L3.41 308.85 C1.52 308.85 0 307.33 0 305.46 L0 291.88 Z" class="st2"/>
+		</g>
+		<g id="shape7-5" v:mID="7" v:groupContext="shape" transform="translate(61.6502,-258.089)">
+			<title>Sheet.7</title>
+			<desc>Key</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="13.7891" cy="301.658" width="27.58" height="14.3829"/>
+			<path d="M27.58 294.47 L0 294.47 L0 308.85 L27.58 308.85 L27.58 294.47" class="st3"/>
+			<text x="3.46" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key</text>		</g>
+		<g id="shape8-9" v:mID="8" v:groupContext="shape" transform="translate(51.9748,-236.328)">
+			<title>Sheet.8</title>
+			<path d="M0 298.54 L9.81 298.54 L9.81 288.24 L29.44 288.24 L29.44 298.54 L39.26 298.54 L19.63 308.85 L0 298.54 Z"
+					class="st5"/>
+		</g>
+		<g id="shape9-11" v:mID="9" v:groupContext="shape" transform="translate(36.0674,-215.298)">
+			<title>Sheet.9</title>
+			<path d="M0 291.77 C0 289.89 1.54 288.36 3.42 288.36 L68.49 288.36 C70.38 288.36 71.91 289.89 71.91 291.77 L71.91 305.43
+						 C71.91 307.32 70.38 308.85 68.49 308.85 L3.42 308.85 C1.54 308.85 0 307.32 0 305.43 L0 291.77 Z"
+					class="st1"/>
+		</g>
+		<g id="shape10-13" v:mID="10" v:groupContext="shape" transform="translate(36.0674,-215.298)">
+			<title>Sheet.10</title>
+			<path d="M0 291.77 C0 289.89 1.54 288.36 3.42 288.36 L68.49 288.36 C70.38 288.36 71.91 289.89 71.91 291.77 L71.91 305.43
+						 C71.91 307.32 70.38 308.85 68.49 308.85 L3.42 308.85 C1.54 308.85 0 307.32 0 305.43 L0 291.77 Z"
+					class="st2"/>
+		</g>
+		<g id="shape11-15" v:mID="11" v:groupContext="shape" transform="translate(58.8889,-216.57)">
+			<title>Sheet.11</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.8573" cy="301.658" width="33.72" height="14.3829"/>
+			<path d="M33.71 294.47 L0 294.47 L0 308.85 L33.71 308.85 L33.71 294.47" class="st3"/>
+			<text x="3.86" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape12-19" v:mID="12" v:groupContext="shape" transform="translate(27.3033,-174.437)">
+			<title>Sheet.12</title>
+			<path d="M0 292.58 C0 290.78 1.46 289.32 3.26 289.32 L87.15 289.32 C88.95 289.32 90.4 290.78 90.4 292.58 L90.4 305.6
+						 C90.4 307.4 88.95 308.85 87.15 308.85 L3.26 308.85 C1.46 308.85 0 307.4 0 305.6 L0 292.58 Z" class="st1"/>
+		</g>
+		<g id="shape13-21" v:mID="13" v:groupContext="shape" transform="translate(27.3033,-174.437)">
+			<title>Sheet.13</title>
+			<path d="M0 292.58 C0 290.78 1.46 289.32 3.26 289.32 L87.15 289.32 C88.95 289.32 90.4 290.78 90.4 292.58 L90.4 305.6
+						 C90.4 307.4 88.95 308.85 87.15 308.85 L3.26 308.85 C1.46 308.85 0 307.4 0 305.6 L0 292.58 Z" class="st2"/>
+		</g>
+		<g id="shape14-23" v:mID="14" v:groupContext="shape" transform="translate(36.0515,-175.256)">
+			<title>Sheet.14</title>
+			<desc>0x0102ABCD</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.6644" cy="301.658" width="87.33" height="14.3829"/>
+			<path d="M87.33 294.47 L0 294.47 L0 308.85 L87.33 308.85 L87.33 294.47" class="st3"/>
+			<text x="7.36" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102ABCD</text>		</g>
+		<g id="shape15-27" v:mID="15" v:groupContext="shape" transform="translate(51.9748,-194.029)">
+			<title>Sheet.15</title>
+			<path d="M0 298.48 L9.81 298.48 L9.81 288.12 L29.44 288.12 L29.44 298.48 L39.26 298.48 L19.63 308.85 L0 298.48 Z"
+					class="st5"/>
+		</g>
+		<g id="shape16-29" v:mID="16" v:groupContext="shape" transform="translate(48.9133,-159.818)">
+			<title>Sheet.16</title>
+			<path d="M26.41 296.87 C26.41 300.18 25.97 302.86 25.41 302.86 L14.21 302.86 C13.66 302.86 13.21 305.55 13.21 308.85
+						 C13.21 305.55 12.76 302.86 12.21 302.86 L1.01 302.86 C0.45 302.86 0 300.18 0 296.87" class="st6"/>
+		</g>
+		<g id="shape17-32" v:mID="17" v:groupContext="shape" transform="translate(19.0195,-19.0195)">
+			<title>Sheet.17</title>
+			<path d="M0 196.93 L0 308.85 L145.15 308.85 L145.15 196.93 L0 196.93 L0 196.93 Z" class="st1"/>
+		</g>
+		<g id="shape18-34" v:mID="18" v:groupContext="shape" transform="translate(19.0195,-19.0195)">
+			<title>Sheet.18</title>
+			<path d="M0 196.93 L145.15 196.93 L145.15 308.85 L0 308.85 L0 196.93" class="st7"/>
+		</g>
+		<g id="shape19-37" v:mID="19" v:groupContext="shape" transform="translate(28.2638,-70.6655)">
+			<title>Sheet.19</title>
+			<path d="M0 280.69 C0 277.58 2.53 275.06 5.64 275.06 L124.14 275.06 C127.26 275.06 129.78 277.58 129.78 280.69 L129.78
+						 303.22 C129.78 306.33 127.26 308.85 124.14 308.85 L5.64 308.85 C2.53 308.85 0 306.33 0 303.22 L0 280.69
+						 Z" class="st1"/>
+		</g>
+		<g id="shape20-39" v:mID="20" v:groupContext="shape" transform="translate(28.2638,-70.6655)">
+			<title>Sheet.20</title>
+			<path d="M0 280.69 C0 277.58 2.53 275.06 5.64 275.06 L124.14 275.06 C127.26 275.06 129.78 277.58 129.78 280.69 L129.78
+						 303.22 C129.78 306.33 127.26 308.85 124.14 308.85 L5.64 308.85 C2.53 308.85 0 306.33 0 303.22 L0 280.69
+						 Z" class="st2"/>
+		</g>
+		<g id="shape21-41" v:mID="21" v:groupContext="shape" transform="translate(57.4514,-85.7513)">
+			<title>Sheet.21</title>
+			<desc>hash_index =</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="45.0133" cy="301.658" width="90.03" height="14.3829"/>
+			<path d="M90.03 294.47 L0 294.47 L0 308.85 L90.03 308.85 L90.03 294.47" class="st3"/>
+			<text x="9.2" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash_index =  </text>		</g>
+		<g id="shape22-45" v:mID="22" v:groupContext="shape" transform="translate(76.3001,-71.3719)">
+			<title>Sheet.22</title>
+			<desc>38123</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.0762" cy="301.658" width="42.16" height="14.3829"/>
+			<path d="M42.15 294.47 L0 294.47 L0 308.85 L42.15 308.85 L42.15 294.47" class="st3"/>
+			<text x="4.42" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>38123</text>		</g>
+		<g id="shape23-49" v:mID="23" v:groupContext="shape" transform="translate(28.2638,-27.048)">
+			<title>Sheet.23</title>
+			<path d="M0 280.69 C0 277.59 2.54 275.06 5.64 275.06 L124.14 275.06 C127.26 275.06 129.78 277.59 129.78 280.69 L129.78
+						 303.22 C129.78 306.33 127.26 308.85 124.14 308.85 L5.64 308.85 C2.54 308.85 0 306.33 0 303.22 L0 280.69
+						 Z" class="st1"/>
+		</g>
+		<g id="shape24-51" v:mID="24" v:groupContext="shape" transform="translate(28.2638,-27.048)">
+			<title>Sheet.24</title>
+			<path d="M0 280.69 C0 277.59 2.54 275.06 5.64 275.06 L124.14 275.06 C127.26 275.06 129.78 277.59 129.78 280.69 L129.78
+						 303.22 C129.78 306.33 127.26 308.85 124.14 308.85 L5.64 308.85 C2.54 308.85 0 306.33 0 303.22 L0 280.69
+						 Z" class="st2"/>
+		</g>
+		<g id="shape25-53" v:mID="25" v:groupContext="shape" transform="translate(54.0924,-41.564)">
+			<title>Sheet.25</title>
+			<desc>lookup_table =</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="46.931" cy="301.658" width="93.87" height="14.3829"/>
+			<path d="M93.86 294.47 L0 294.47 L0 308.85 L93.86 308.85 L93.86 294.47" class="st3"/>
+			<text x="7.79" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table =</text>		</g>
+		<g id="shape26-57" v:mID="26" v:groupContext="shape" transform="translate(28.0195,-28.5506)">
+			<title>Sheet.26</title>
+			<desc>0110 1100 0101 1101</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="64.89" cy="302.233" width="129.79" height="13.2327"/>
+			<path d="M129.78 295.62 L0 295.62 L0 308.85 L129.78 308.85 L129.78 295.62" class="st3"/>
+			<text x="11.25" y="305.54" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0110 11<tspan
+						class="st9">0</tspan>0 0101 1101</text>		</g>
+		<g id="shape27-62" v:mID="27" v:groupContext="shape" transform="translate(26.2461,-113.863)">
+			<title>Sheet.27</title>
+			<desc>Group ID: 0x0102</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="48.6286" cy="302.881" width="97.26" height="11.9384"/>
+			<path d="M97.26 296.91 L0 296.91 L0 308.85 L97.26 308.85 L97.26 296.91" class="st3"/>
+			<text x="7.73" y="305.86" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group ID: 0x0102</text>		</g>
+		<g id="shape28-66" v:mID="28" v:groupContext="shape" transform="translate(42.3703,-135.313)">
+			<title>Sheet.28</title>
+			<path d="M0 298.48 L9.84 298.48 L9.84 288.12 L29.53 288.12 L29.53 298.48 L39.38 298.48 L19.69 308.85 L0 298.48 Z"
+					class="st5"/>
+		</g>
+		<g id="shape29-68" v:mID="29" v:groupContext="shape" transform="translate(117.645,-244.476)">
+			<title>Sheet.29</title>
+			<path d="M0 274.07 L22.75 274.07 L22.75 262.48 L45.5 285.66 L22.75 308.85 L22.75 297.26 L0 297.26 L0 274.07 Z"
+					class="st5"/>
+		</g>
+		<g id="shape30-70" v:mID="30" v:groupContext="shape" transform="translate(169.209,-251.966)">
+			<title>Sheet.30</title>
+			<path d="M0 283.69 C0 280.91 2.27 278.65 5.04 278.65 L111.77 278.65 C114.56 278.65 116.81 280.91 116.81 283.69 L116.81
+						 303.82 C116.81 306.6 114.56 308.85 111.77 308.85 L5.04 308.85 C2.27 308.85 0 306.6 0 303.82 L0 283.69 Z"
+					class="st1"/>
+		</g>
+		<g id="shape31-72" v:mID="31" v:groupContext="shape" transform="translate(169.209,-251.966)">
+			<title>Sheet.31</title>
+			<path d="M0 283.69 C0 280.91 2.27 278.65 5.04 278.65 L111.77 278.65 C114.56 278.65 116.81 280.91 116.81 283.69 L116.81
+						 303.82 C116.81 306.6 114.56 308.85 111.77 308.85 L5.04 308.85 C2.27 308.85 0 306.6 0 303.82 L0 283.69 Z"
+					class="st2"/>
+		</g>
+		<g id="shape35-74" v:mID="35" v:groupContext="shape" transform="translate(291.966,-244.476)">
+			<title>Sheet.35</title>
+			<path d="M0 274.07 L22.69 274.07 L22.69 262.48 L45.38 285.66 L22.69 308.85 L22.69 297.26 L0 297.26 L0 274.07 Z"
+					class="st5"/>
+		</g>
+		<g id="shape36-76" v:mID="36" v:groupContext="shape" transform="translate(343.17,-254.482)">
+			<title>Sheet.36</title>
+			<path d="M0 288.09 C0 285.8 1.88 283.93 4.17 283.93 L109.18 283.93 C111.47 283.93 113.33 285.8 113.33 288.09 L113.33
+						 304.7 C113.33 306.99 111.47 308.85 109.18 308.85 L4.17 308.85 C1.88 308.85 0 306.99 0 304.7 L0 288.09 Z"
+					class="st1"/>
+		</g>
+		<g id="shape37-78" v:mID="37" v:groupContext="shape" transform="translate(343.17,-254.482)">
+			<title>Sheet.37</title>
+			<path d="M0 288.09 C0 285.8 1.88 283.93 4.17 283.93 L109.18 283.93 C111.47 283.93 113.33 285.8 113.33 288.09 L113.33
+						 304.7 C113.33 306.99 111.47 308.85 109.18 308.85 L4.17 308.85 C1.88 308.85 0 306.99 0 304.7 L0 288.09 Z"
+					class="st2"/>
+		</g>
+		<g id="shape38-80" v:mID="38" v:groupContext="shape" transform="translate(368.337,-257.958)">
+			<title>Sheet.38</title>
+			<desc>Position = 6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="38.1131" cy="301.658" width="76.23" height="14.3829"/>
+			<path d="M76.23 294.47 L0 294.47 L0 308.85 L76.23 308.85 L76.23 294.47" class="st3"/>
+			<text x="6.64" y="305.25" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Position = 6</text>		</g>
+		<g id="shape39-84" v:mID="39" v:groupContext="shape" transform="translate(158.044,-86.5202)">
+			<title>Sheet.39</title>
+			<path d="M0 308.85 L69.59 308.85 C70.16 308.85 70.62 308.39 70.62 307.83 L70.62 148.5 L68.57 148.5 L68.57 307.83 L69.59
+						 306.81 L0 306.81 L0 308.85 ZM72.66 149.52 L69.59 143.4 L66.53 149.52 L72.66 149.52 Z" class="st11"/>
+		</g>
+		<g id="shape41-86" v:mID="41" v:groupContext="shape" transform="translate(335.112,-199.647)">
+			<title>Sheet.41</title>
+			<desc>Apply the equation</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="71.2648" cy="300.436" width="142.53" height="16.8275"/>
+			<path d="M142.53 292.02 L0 292.02 L0 308.85 L142.53 308.85 L142.53 292.02" class="st3"/>
+			<text x="13.19" y="304.64" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Apply the equation  </text>		</g>
+		<g id="shape42-90" v:mID="42" v:groupContext="shape" transform="translate(341.115,-182.871)">
+			<title>Sheet.42</title>
+			<desc>to retrieve the bit</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="64.5256" cy="300.436" width="129.06" height="16.8275"/>
+			<path d="M129.05 292.02 L0 292.02 L0 308.85 L129.05 308.85 L129.05 292.02" class="st3"/>
+			<text x="12.31" y="304.64" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>to retrieve the bit  </text>		</g>
+		<g id="shape43-94" v:mID="43" v:groupContext="shape" transform="translate(349.999,-166.095)">
+			<title>Sheet.43</title>
+			<desc>position in the</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="54.2285" cy="300.436" width="108.46" height="16.8275"/>
+			<path d="M108.46 292.02 L0 292.02 L0 308.85 L108.46 308.85 L108.46 292.02" class="st3"/>
+			<text x="10.97" y="304.64" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>position in the  </text>		</g>
+		<g id="shape44-98" v:mID="44" v:groupContext="shape" transform="translate(353.361,-149.319)">
+			<title>Sheet.44</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="47.9619" cy="300.436" width="95.93" height="16.8275"/>
+			<path d="M95.92 292.02 L0 292.02 L0 308.85 L95.92 308.85 L95.92 292.02" class="st3"/>
+			<text x="8.21" y="304.64" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape47-102" v:mID="47" v:groupContext="shape" transform="translate(115.17,255.2) rotate(-90)">
+			<title>1-D word balloon</title>
+			<desc>Retrieve the value “0&#39; from the specified location in the loo...</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+				<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
+				<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="29.2016" cy="218.85" width="180" height="58.4032" transform="rotate(90)"/>
+			<path d="M0 308.85 L58.4 308.85 L58.4 128.85 L0 128.85 L0 204.67 L-11.87 38.85 L-7.09 233.03 L0 233.03 L0 308.85 Z"
+					class="st13"/>
+			<text x="136.98" y="-41.8" transform="rotate(90)" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Retrieve the value “0&#39; from <tspan
+						x="134.41" dy="1.2em" class="st15">the specified location in the </tspan><tspan x="181.1" dy="1.2em"
+						class="st15">lookup table</tspan></text>		</g>
+		<g id="shape48-107" v:mID="48" v:groupContext="shape" transform="translate(169.209,-251.966)">
+			<title>Sheet.48</title>
+			<desc>F(Key, hash_index = 38123</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54.2285" cy="295.35" width="108.46" height="27"/>
+			<rect x="0" y="281.85" width="108.457" height="27" class="st16"/>
+			<text x="5.86" y="291.75" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>F(Key, hash_index = <tspan
+						x="39.02" dy="1.2em" class="st15">38123</tspan></text>		</g>
+		<g id="shape49-111" v:mID="49" v:groupContext="shape" transform="translate(553.962,99) rotate(90)">
+			<title>1-D word balloon.49</title>
+			<desc>Apply the equation to retrieve the bit position in the lookup...</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+				<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
+				<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="29.2016" cy="218.85" width="180" height="58.4032" transform="rotate(-90)"/>
+			<path d="M0 308.85 L58.4 308.85 L58.4 128.85 L0 128.85 L0 204.67 L-51.13 299.85 L0 233.03 L0 308.85 Z" class="st13"/>
+			<text x="-284.62" y="16.6" transform="rotate(-90)" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Apply the equation to <tspan
+						x="-296.67" dy="1.2em" class="st15">retrieve the bit position in </tspan><tspan x="-270.22" dy="1.2em"
+						class="st15">the lookup</tspan>_table</text>		</g>
+		<g id="shape50-116" v:mID="50" v:groupContext="shape" transform="translate(640.132,-104.709) rotate(44.1224)">
+			<title>Sheet.50</title>
+			<path d="M0 308.85 L54.13 308.85" class="st18"/>
+		</g>
+		<g id="shape51-122" v:mID="51" v:groupContext="shape" transform="translate(433.02,-122.267)">
+			<title>Sheet.51</title>
+			<desc>(Hash(key,seed1)+38123*hash(key,seed2))%16</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="144" cy="295.35" width="288" height="27"/>
+			<rect x="0" y="281.85" width="288" height="27" class="st2"/>
+			<text x="9.86" y="299.55" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(Hash(key,seed1)+38123*hash(key,seed2))%16</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i12.svg b/doc/guides/prog_guide/img/efd_i12.svg
new file mode 100644
index 0000000..a309d58
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i12.svg
@@ -0,0 +1,1008 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i13.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="10.2932in" height="5.27505in"
+		viewBox="0 0 741.108 379.804" xml:space="preserve" color-interpolation-filters="sRGB" class="st30">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st2 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st3 {fill:#004280;font-family:Arial;font-size:0.828804em}
+		.st4 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st5 {stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st6 {fill:#7030a0;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st7 {fill:#d0d6d9;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st8 {fill:#006fc5;stroke:#006fc5;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.00749637}
+		.st9 {fill:#006fc5;stroke:#006fc5;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0149927}
+		.st10 {fill:#d0d6d9;stroke:#d0d6d9;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st11 {fill:#d0d6d9;stroke:#d0d6d9;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0149927}
+		.st12 {fill:#004280;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st13 {fill:#00b050;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st14 {fill:#ff0000;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st15 {fill:#00b050;stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st16 {fill:#c00000;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st17 {fill:#000000;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st18 {fill:#7f6d00;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st19 {fill:#ff0000;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st20 {fill:#7e8d96;font-family:Arial;font-size:0.828804em;font-weight:bold}
+		.st21 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st22 {fill:#000000;font-family:Arial;font-size:0.998566em}
+		.st23 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st24 {stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st25 {fill:#ffffff;font-family:Arial;font-size:0.998566em}
+		.st26 {fill:#ff6600;stroke:#ff6600;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.00749637}
+		.st27 {fill:#004280;stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st28 {fill:#ff0000;stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st29 {fill:#ffffff;font-family:Arial;font-size:1.49785em}
+		.st30 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(304.703,-329.32)">
+			<title>Sheet.3</title>
+			<path d="M0 379.8 C-0 375.37 0.6 371.78 1.35 371.78 L205.05 371.78 C205.78 371.78 206.38 368.18 206.38 363.75 C206.38
+						 368.18 206.98 371.78 207.73 371.78 L411.43 371.78 C412.15 371.78 412.75 375.37 412.75 379.8" class="st1"/>
+		</g>
+		<g id="shape4-4" v:mID="4" v:groupContext="shape" transform="translate(219.943,-329.32)">
+			<title>Sheet.4</title>
+			<path d="M0 379.8 C0 375.64 0.57 372.25 1.26 372.25 L29.77 372.25 C30.48 372.25 31.03 368.88 31.03 364.71 C31.03 368.88
+						 31.6 372.25 32.29 372.25 L60.81 372.25 C61.51 372.25 62.07 375.64 62.07 379.8" class="st1"/>
+		</g>
+		<g id="shape5-7" v:mID="5" v:groupContext="shape" transform="translate(241.175,-343.9)">
+			<title>Sheet.5</title>
+			<desc>Bins</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="12.7158" cy="373.835" width="25.44" height="11.9384"/>
+			<path d="M25.43 367.87 L0 367.87 L0 379.8 L25.43 379.8 L25.43 367.87" class="st2"/>
+			<text x="3.04" y="376.82" class="st3" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Bins</text>		</g>
+		<g id="shape6-11" v:mID="6" v:groupContext="shape" transform="translate(496.212,-344.504)">
+			<title>Sheet.6</title>
+			<desc>Groups</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="20.3447" cy="373.835" width="40.69" height="11.9384"/>
+			<path d="M40.69 367.87 L0 367.87 L0 379.8 L40.69 379.8 L40.69 367.87" class="st2"/>
+			<text x="4.04" y="376.82" class="st3" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Groups</text>		</g>
+		<g id="shape7-15" v:mID="7" v:groupContext="shape" transform="translate(131.823,-260.299)">
+			<title>Sheet.7</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape8-17" v:mID="8" v:groupContext="shape" transform="translate(131.823,-260.299)">
+			<title>Sheet.8</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape9-20" v:mID="9" v:groupContext="shape" transform="translate(134.706,-310.738)">
+			<title>Sheet.9</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape10-24" v:mID="10" v:groupContext="shape" transform="translate(122.218,-329.32)">
+			<title>Sheet.10</title>
+			<path d="M0 379.8 C-0 375.64 0.57 372.25 1.26 372.25 L29.77 372.25 C30.47 372.25 31.03 368.88 31.03 364.71 C31.03 368.88
+						 31.6 372.25 32.29 372.25 L60.81 372.25 C61.51 372.25 62.07 375.64 62.07 379.8" class="st1"/>
+		</g>
+		<g id="shape11-27" v:mID="11" v:groupContext="shape" transform="translate(137.598,-343.9)">
+			<title>Sheet.11</title>
+			<desc>Chunks</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="20.9813" cy="373.835" width="41.97" height="11.9384"/>
+			<path d="M41.96 367.87 L0 367.87 L0 379.8 L41.96 379.8 L41.96 367.87" class="st2"/>
+			<text x="4.12" y="376.82" class="st3" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Chunks</text>		</g>
+		<g id="shape12-31" v:mID="12" v:groupContext="shape" transform="translate(131.823,-195.232)">
+			<title>Sheet.12</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape13-33" v:mID="13" v:groupContext="shape" transform="translate(131.823,-195.232)">
+			<title>Sheet.13</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape14-36" v:mID="14" v:groupContext="shape" transform="translate(134.706,-245.682)">
+			<title>Sheet.14</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape15-40" v:mID="15" v:groupContext="shape" transform="translate(131.823,-130.525)">
+			<title>Sheet.15</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st7"/>
+		</g>
+		<g id="shape16-42" v:mID="16" v:groupContext="shape" transform="translate(131.823,-130.525)">
+			<title>Sheet.16</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape17-45" v:mID="17" v:groupContext="shape" transform="translate(134.706,-180.952)">
+			<title>Sheet.17</title>
+			<desc>…</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.30974" cy="373.835" width="14.62" height="11.9384"/>
+			<path d="M14.62 367.87 L0 367.87 L0 379.8 L14.62 379.8 L14.62 367.87" class="st2"/>
+			<text x="2.34" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>…</text>		</g>
+		<g id="shape18-49" v:mID="18" v:groupContext="shape" transform="translate(131.823,-65.4584)">
+			<title>Sheet.18</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape19-51" v:mID="19" v:groupContext="shape" transform="translate(131.823,-65.4584)">
+			<title>Sheet.19</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape20-54" v:mID="20" v:groupContext="shape" transform="translate(130.403,-115.896)">
+			<title>Sheet.20</title>
+			<desc>variable</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="24.7986" cy="373.835" width="49.6" height="11.9384"/>
+			<path d="M49.6 367.87 L0 367.87 L0 379.8 L49.6 379.8 L49.6 367.87" class="st2"/>
+			<text x="6" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>variable  </text>		</g>
+		<g id="shape21-58" v:mID="21" v:groupContext="shape" transform="translate(130.403,-103.913)">
+			<title>Sheet.21</title>
+			<desc># of</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="13.347" cy="373.835" width="26.7" height="11.9384"/>
+			<path d="M26.69 367.87 L0 367.87 L0 379.8 L26.69 379.8 L26.69 367.87" class="st2"/>
+			<text x="4.51" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/># of  </text>		</g>
+		<g id="shape22-62" v:mID="22" v:groupContext="shape" transform="translate(130.403,-91.93)">
+			<title>Sheet.22</title>
+			<desc>chunks</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.6122" cy="373.835" width="43.23" height="11.9384"/>
+			<path d="M43.22 367.87 L0 367.87 L0 379.8 L43.22 379.8 L43.22 367.87" class="st2"/>
+			<text x="4.2" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>chunks</text>		</g>
+		<g id="shape23-66" v:mID="23" v:groupContext="shape" transform="translate(130.403,-79.9472)">
+			<title>Sheet.23</title>
+			<desc>(power</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.9251" cy="373.835" width="43.86" height="11.9384"/>
+			<path d="M43.85 367.87 L0 367.87 L0 379.8 L43.85 379.8 L43.85 367.87" class="st2"/>
+			<text x="5.62" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(power  </text>		</g>
+		<g id="shape24-70" v:mID="24" v:groupContext="shape" transform="translate(130.403,-67.9643)">
+			<title>Sheet.24</title>
+			<desc>of 2)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="13.6626" cy="373.835" width="27.33" height="11.9384"/>
+			<path d="M27.33 367.87 L0 367.87 L0 379.8 L27.33 379.8 L27.33 367.87" class="st2"/>
+			<text x="3.17" y="376.82" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>of 2)</text>		</g>
+		<g id="shape25-74" v:mID="25" v:groupContext="shape" transform="translate(172.289,-260.838)">
+			<title>Sheet.25</title>
+			<path d="M1.43 379.8 L3.29 375.51 L1.85 374.9 L0 379.19 L1.43 379.8 L1.43 379.8 ZM3.9 374.08 L5.76 369.79 L4.32 369.18
+						 L2.47 373.47 L3.9 374.08 L3.9 374.08 ZM6.37 368.36 L8.22 364.07 L6.79 363.45 L4.94 367.75 L6.37 368.36 L6.37
+						 368.36 ZM8.84 362.64 L10.69 358.35 L9.26 357.73 L7.41 362.02 L8.84 362.64 L8.84 362.64 ZM11.31 356.92 L13.16
+						 352.62 L11.73 352 L9.87 356.3 L11.31 356.92 L11.31 356.92 ZM13.78 351.19 L15.63 346.9 L14.2 346.28 L12.34
+						 350.57 L13.78 351.19 L13.78 351.19 ZM16.25 345.47 L18.1 341.17 L16.67 340.56 L14.81 344.85 L16.25 345.47
+						 L16.25 345.47 ZM18.71 339.74 L20.57 335.45 L19.13 334.84 L17.28 339.13 L18.71 339.74 L18.71 339.74 ZM21.18
+						 334.02 L23.04 329.73 L21.6 329.12 L19.75 333.41 L21.18 334.02 L21.18 334.02 ZM23.65 328.3 L25.5 324.01 L24.07
+						 323.39 L22.22 327.68 L23.65 328.3 L23.65 328.3 ZM26.12 322.58 L27.97 318.28 L26.54 317.67 L24.69 321.96
+						 L26.12 322.58 L26.12 322.58 ZM28.59 316.85 L29.44 314.87 L28.01 314.25 L27.16 316.24 L28.59 316.85 L28.59
+						 316.85 Z" class="st8"/>
+		</g>
+		<g id="shape26-76" v:mID="26" v:groupContext="shape" transform="translate(172.476,-20.463)">
+			<title>Sheet.26</title>
+			<path d="M1.55 203.84 L2.28 208.45 L0.74 208.7 L0 204.09 L1.55 203.84 L1.55 203.84 ZM2.52 209.99 L3.27 214.61 L1.73 214.86
+						 L0.99 210.23 L2.52 209.99 L2.52 209.99 ZM3.51 216.15 L4.25 220.76 L2.7 221 L1.97 216.39 L3.51 216.15 L3.51
+						 216.15 ZM4.49 222.3 L5.24 226.92 L3.69 227.16 L2.96 222.54 L4.49 222.3 L4.49 222.3 ZM5.48 228.45 L6.21 233.07
+						 L4.67 233.31 L3.93 228.7 L5.48 228.45 L5.48 228.45 ZM6.47 234.6 L7.2 239.22 L5.66 239.47 L4.92 234.86 L6.47
+						 234.6 L6.47 234.6 ZM7.44 240.76 L8.18 245.37 L6.65 245.63 L5.9 241 L7.44 240.76 L7.44 240.76 ZM8.43 246.91
+						 L9.17 251.53 L7.62 251.77 L6.89 247.15 L8.43 246.91 L8.43 246.91 ZM9.41 253.07 L10.14 257.68 L8.61 257.92
+						 L7.88 253.31 L9.41 253.07 L9.41 253.07 ZM10.4 259.21 L11.14 263.84 L9.59 264.08 L8.85 259.47 L10.4 259.21
+						 L10.4 259.21 ZM11.38 265.37 L12.13 269.98 L10.58 270.24 L9.84 265.62 L11.38 265.37 L11.38 265.37 ZM12.37
+						 271.52 L13.1 276.14 L11.56 276.39 L10.82 271.76 L12.37 271.52 L12.37 271.52 ZM13.34 277.68 L14.09 282.29
+						 L12.55 282.53 L11.81 277.92 L13.34 277.68 L13.34 277.68 ZM14.33 283.84 L15.07 288.45 L13.52 288.69 L12.79
+						 284.08 L14.33 283.84 L14.33 283.84 ZM15.32 289.99 L16.06 294.61 L14.51 294.85 L13.78 290.23 L15.32 289.99
+						 L15.32 289.99 ZM16.3 296.13 L17.03 300.75 L15.5 301 L14.75 296.39 L16.3 296.13 L16.3 296.13 ZM17.29 302.29
+						 L18.02 306.9 L16.48 307.16 L15.74 302.53 L17.29 302.29 L17.29 302.29 ZM18.26 308.45 L19 313.06 L17.47 313.3
+						 L16.73 308.69 L18.26 308.45 L18.26 308.45 ZM19.25 314.6 L19.99 319.22 L18.44 319.46 L17.71 314.84 L19.25
+						 314.6 L19.25 314.6 ZM20.23 320.76 L20.96 325.37 L19.43 325.61 L18.7 321 L20.23 320.76 L20.23 320.76 ZM21.22
+						 326.9 L21.96 331.51 L20.41 331.77 L19.67 327.15 L21.22 326.9 L21.22 326.9 ZM22.2 333.06 L22.95 337.67 L21.4
+						 337.92 L20.66 333.31 L22.2 333.06 L22.2 333.06 ZM23.19 339.21 L23.92 343.83 L22.38 344.07 L21.64 339.45
+						 L23.19 339.21 L23.19 339.21 ZM24.18 345.37 L24.91 349.98 L23.37 350.22 L22.63 345.61 L24.18 345.37 L24.18
+						 345.37 ZM25.15 351.52 L25.89 356.14 L24.36 356.38 L23.61 351.76 L25.15 351.52 L25.15 351.52 ZM26.14 357.67
+						 L26.88 362.28 L25.33 362.53 L24.6 357.92 L26.14 357.67 L26.14 357.67 ZM27.12 363.82 L27.85 368.44 L26.32
+						 368.69 L25.59 364.08 L27.12 363.82 L27.12 363.82 ZM28.11 369.98 L28.84 374.59 L27.3 374.83 L26.56 370.22
+						 L28.11 369.98 L28.11 369.98 ZM29.08 376.13 L29.64 379.55 L28.09 379.8 L27.55 376.37 L29.08 376.13 L29.08
+						 376.13 Z" class="st9"/>
+		</g>
+		<g id="shape27-78" v:mID="27" v:groupContext="shape" transform="translate(276.159,-233.368)">
+			<title>Sheet.27</title>
+			<path d="M0.45 294.85 L354.04 376.06 L353.59 378.04 L0 296.85 L0.45 294.85 L0.45 294.85 ZM353.5 373.84 L358.79 378.19
+						 L352.12 379.8 L353.5 373.84 L353.5 373.84 Z" class="st10"/>
+		</g>
+		<g id="shape28-80" v:mID="28" v:groupContext="shape" transform="translate(275.859,-178.726)">
+			<title>Sheet.28</title>
+			<path d="M1.05 240.32 L231.44 376.33 L230.39 378.1 L0 242.09 L1.05 240.32 L1.05 240.32 ZM231.59 374.05 L235.31 379.8
+						 L228.47 379.32 L231.59 374.05 L231.59 374.05 Z" class="st10"/>
+		</g>
+		<g id="shape29-82" v:mID="29" v:groupContext="shape" transform="translate(275.379,-87.6866)">
+			<title>Sheet.29</title>
+			<path d="M2 149.94 L50.05 374.61 L48.05 375.04 L0 150.38 L2 149.94 L2 149.94 ZM51.83 373.18 L50.12 379.8 L45.85 374.47
+						 L51.83 373.18 L51.83 373.18 Z" class="st11"/>
+		</g>
+		<g id="shape30-84" v:mID="30" v:groupContext="shape" transform="translate(276.279,-177.108)">
+			<title>Sheet.30</title>
+			<path d="M0.21 353.74 L229.55 375.85 L229.34 377.89 L0 355.75 L0.21 353.74 L0.21 353.74 ZM228.71 373.72 L234.53 377.35
+						 L228.14 379.8 L228.71 373.72 L228.71 373.72 Z" class="st10"/>
+		</g>
+		<g id="shape31-86" v:mID="31" v:groupContext="shape" transform="translate(275.919,-213.926)">
+			<title>Sheet.31</title>
+			<path d="M0.45 308.72 L312.65 376.06 L312.2 378.04 L0 310.72 L0.45 308.72 L0.45 308.72 ZM312.08 373.84 L317.43 378.13
+						 L310.79 379.8 L312.08 373.84 L312.08 373.84 Z" class="st10"/>
+		</g>
+		<g id="shape32-88" v:mID="32" v:groupContext="shape" transform="translate(275.439,-143.377)">
+			<title>Sheet.32</title>
+			<path d="M1.4 238.41 L150.34 375.59 L148.96 377.09 L0 239.9 L1.4 238.41 L1.4 238.41 ZM150.98 373.41 L153.4 379.8 L146.83
+						 377.9 L150.98 373.41 L150.98 373.41 Z" class="st11"/>
+		</g>
+		<g id="shape33-90" v:mID="33" v:groupContext="shape" transform="translate(275.274,-108.821)">
+			<title>Sheet.33</title>
+			<path d="M1.73 236.53 L90.79 374.97 L89.08 376.07 L0 237.63 L1.73 236.53 L1.73 236.53 ZM91.96 373 L92.7 379.8 L86.82
+						 376.31 L91.96 373 L91.96 373 Z" class="st11"/>
+		</g>
+		<g id="shape34-92" v:mID="34" v:groupContext="shape" transform="translate(275.364,-124.069)">
+			<title>Sheet.34</title>
+			<path d="M1.55 251.66 L108.22 375.28 L106.67 376.61 L0 253 L1.55 251.66 L1.55 251.66 ZM109.1 373.18 L110.78 379.8 L104.46
+						 377.17 L109.1 373.18 L109.1 373.18 Z" class="st11"/>
+		</g>
+		<g id="shape35-94" v:mID="35" v:groupContext="shape" transform="translate(275.154,-87.7165)">
+			<title>Sheet.35</title>
+			<path d="M1.97 215.68 L49.85 374.64 L47.9 375.22 L0 216.27 L1.97 215.68 L1.97 215.68 ZM51.52 373.08 L50.35 379.8 L45.65
+						 374.83 L51.52 373.08 L51.52 373.08 Z" class="st11"/>
+		</g>
+		<g id="shape36-96" v:mID="36" v:groupContext="shape" transform="translate(276.009,-143.736)">
+			<title>Sheet.36</title>
+			<path d="M0.74 320.41 L147.92 376.36 L147.2 378.26 L0 322.32 L0.74 320.41 L0.74 320.41 ZM147.7 374.08 L152.34 379.11
+						 L145.52 379.8 L147.7 374.08 L147.7 374.08 Z" class="st11"/>
+		</g>
+		<g id="shape37-98" v:mID="37" v:groupContext="shape" transform="translate(275.649,-108.821)">
+			<title>Sheet.37</title>
+			<path d="M1.46 285.74 L89.46 375.45 L88 376.87 L0 287.16 L1.46 285.74 L1.46 285.74 ZM90.21 373.29 L92.29 379.8 L85.82
+						 377.57 L90.21 373.29 L90.21 373.29 Z" class="st11"/>
+		</g>
+		<g id="shape38-100" v:mID="38" v:groupContext="shape" transform="translate(275.934,-108.686)">
+			<title>Sheet.38</title>
+			<path d="M0.89 335.24 L87.85 376.57 L86.97 378.41 L0 337.09 L0.89 335.24 L0.89 335.24 ZM87.81 374.29 L92.01 379.67 L85.16
+						 379.8 L87.81 374.29 L87.81 374.29 Z" class="st11"/>
+		</g>
+		<g id="shape39-102" v:mID="39" v:groupContext="shape" transform="translate(275.574,-89.454)">
+			<title>Sheet.39</title>
+			<path d="M1.61 316.29 L48.49 375.18 L46.88 376.45 L0 317.57 L1.61 316.29 L1.61 316.29 ZM49.45 373.11 L50.86 379.8 L44.65
+						 376.91 L49.45 373.11 L49.45 373.11 Z" class="st11"/>
+		</g>
+		<g id="shape40-104" v:mID="40" v:groupContext="shape" transform="translate(276.324,-141.744)">
+			<title>Sheet.40</title>
+			<path d="M0.11 368.21 L146.74 375.79 L146.62 377.83 L0 370.23 L0.11 368.21 L0.11 368.21 ZM145.82 373.71 L151.78 377.08
+						 L145.51 379.8 L145.82 373.71 L145.82 373.71 Z" class="st11"/>
+		</g>
+		<g id="shape41-106" v:mID="41" v:groupContext="shape" transform="translate(230.508,-309.069)">
+			<title>Sheet.41</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st4"/>
+		</g>
+		<g id="shape42-108" v:mID="42" v:groupContext="shape" transform="translate(230.508,-309.069)">
+			<title>Sheet.42</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape43-111" v:mID="43" v:groupContext="shape" transform="translate(233.39,-309.868)">
+			<title>Sheet.43</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape44-115" v:mID="44" v:groupContext="shape" transform="translate(263.764,-309.869)">
+			<title>Sheet.44</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape45-119" v:mID="45" v:groupContext="shape" transform="translate(230.508,-292.413)">
+			<title>Sheet.45</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape46-121" v:mID="46" v:groupContext="shape" transform="translate(230.508,-292.413)">
+			<title>Sheet.46</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape47-124" v:mID="47" v:groupContext="shape" transform="translate(233.39,-293.221)">
+			<title>Sheet.47</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape48-128" v:mID="48" v:groupContext="shape" transform="translate(230.508,-275.757)">
+			<title>Sheet.48</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st4"/>
+		</g>
+		<g id="shape49-130" v:mID="49" v:groupContext="shape" transform="translate(230.508,-275.757)">
+			<title>Sheet.49</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape50-133" v:mID="50" v:groupContext="shape" transform="translate(233.39,-276.574)">
+			<title>Sheet.50</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape51-137" v:mID="51" v:groupContext="shape" transform="translate(252.478,-276.574)">
+			<title>Sheet.51</title>
+			<desc>3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>3</text>		</g>
+		<g id="shape52-141" v:mID="52" v:groupContext="shape" transform="translate(258.001,-276.574)">
+			<title>Sheet.52</title>
+			<desc>+1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="8.11122" cy="373.835" width="16.23" height="11.9384"/>
+			<path d="M16.22 367.87 L0 367.87 L0 379.8 L16.22 379.8 L16.22 367.87" class="st2"/>
+			<text x="2.44" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>+1</text>		</g>
+		<g id="shape53-145" v:mID="53" v:groupContext="shape" transform="translate(230.508,-259.7)">
+			<title>Sheet.53</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape54-147" v:mID="54" v:groupContext="shape" transform="translate(230.508,-259.7)">
+			<title>Sheet.54</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape55-150" v:mID="55" v:groupContext="shape" transform="translate(233.39,-260.497)">
+			<title>Sheet.55</title>
+			<desc>3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>3</text>		</g>
+		<g id="shape56-154" v:mID="56" v:groupContext="shape" transform="translate(230.508,-243.164)">
+			<title>Sheet.56</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st4"/>
+		</g>
+		<g id="shape57-156" v:mID="57" v:groupContext="shape" transform="translate(230.508,-243.164)">
+			<title>Sheet.57</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape58-159" v:mID="58" v:groupContext="shape" transform="translate(233.39,-244.053)">
+			<title>Sheet.58</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape59-163" v:mID="59" v:groupContext="shape" transform="translate(263.764,-244.053)">
+			<title>Sheet.59</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape60-167" v:mID="60" v:groupContext="shape" transform="translate(230.508,-227.107)">
+			<title>Sheet.60</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape61-169" v:mID="61" v:groupContext="shape" transform="translate(230.508,-227.107)">
+			<title>Sheet.61</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape62-172" v:mID="62" v:groupContext="shape" transform="translate(233.39,-227.976)">
+			<title>Sheet.62</title>
+			<desc>5</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>5</text>		</g>
+		<g id="shape63-176" v:mID="63" v:groupContext="shape" transform="translate(230.508,-210.211)">
+			<title>Sheet.63</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape64-178" v:mID="64" v:groupContext="shape" transform="translate(230.508,-210.211)">
+			<title>Sheet.64</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape65-181" v:mID="65" v:groupContext="shape" transform="translate(233.39,-211.085)">
+			<title>Sheet.65</title>
+			<desc>6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>6</text>		</g>
+		<g id="shape66-185" v:mID="66" v:groupContext="shape" transform="translate(230.508,-193.794)">
+			<title>Sheet.66</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st4"/>
+		</g>
+		<g id="shape67-187" v:mID="67" v:groupContext="shape" transform="translate(230.508,-193.794)">
+			<title>Sheet.67</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape68-190" v:mID="68" v:groupContext="shape" transform="translate(233.39,-194.681)">
+			<title>Sheet.68</title>
+			<desc>7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>7</text>		</g>
+		<g id="shape69-194" v:mID="69" v:groupContext="shape" transform="translate(263.764,-194.681)">
+			<title>Sheet.69</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape70-198" v:mID="70" v:groupContext="shape" transform="translate(230.508,-177.258)">
+			<title>Sheet.70</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape71-200" v:mID="71" v:groupContext="shape" transform="translate(230.508,-177.258)">
+			<title>Sheet.71</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape72-203" v:mID="72" v:groupContext="shape" transform="translate(233.39,-178.117)">
+			<title>Sheet.72</title>
+			<desc>8</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>8</text>		</g>
+		<g id="shape73-207" v:mID="73" v:groupContext="shape" transform="translate(230.508,-160.602)">
+			<title>Sheet.73</title>
+			<path d="M0 363.15 L0 379.8 L41.18 379.8 L41.18 363.15 L0 363.15 L0 363.15 Z" class="st7"/>
+		</g>
+		<g id="shape74-209" v:mID="74" v:groupContext="shape" transform="translate(230.508,-160.602)">
+			<title>Sheet.74</title>
+			<path d="M0 363.15 L41.18 363.15 L41.18 379.8 L0 379.8 L0 363.15" class="st5"/>
+		</g>
+		<g id="shape75-212" v:mID="75" v:groupContext="shape" transform="translate(233.39,-161.505)">
+			<title>Sheet.75</title>
+			<desc>9</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>9</text>		</g>
+		<g id="shape76-216" v:mID="76" v:groupContext="shape" transform="translate(230.508,-143.946)">
+			<title>Sheet.76</title>
+			<path d="M0 363.15 L0 379.8 L41.18 379.8 L41.18 363.15 L0 363.15 L0 363.15 Z" class="st4"/>
+		</g>
+		<g id="shape77-218" v:mID="77" v:groupContext="shape" transform="translate(230.508,-143.946)">
+			<title>Sheet.77</title>
+			<path d="M0 363.15 L41.18 363.15 L41.18 379.8 L0 379.8 L0 363.15" class="st5"/>
+		</g>
+		<g id="shape78-221" v:mID="78" v:groupContext="shape" transform="translate(233.39,-144.841)">
+			<title>Sheet.78</title>
+			<desc>10</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>10</text>		</g>
+		<g id="shape79-225" v:mID="79" v:groupContext="shape" transform="translate(263.764,-144.841)">
+			<title>Sheet.79</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape80-229" v:mID="80" v:groupContext="shape" transform="translate(230.508,-127.529)">
+			<title>Sheet.80</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape81-231" v:mID="81" v:groupContext="shape" transform="translate(230.508,-127.529)">
+			<title>Sheet.81</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape82-234" v:mID="82" v:groupContext="shape" transform="translate(233.39,-128.329)">
+			<title>Sheet.82</title>
+			<desc>11</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>11</text>		</g>
+		<g id="shape83-238" v:mID="83" v:groupContext="shape" transform="translate(230.508,-110.754)">
+			<title>Sheet.83</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape84-240" v:mID="84" v:groupContext="shape" transform="translate(230.508,-110.754)">
+			<title>Sheet.84</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape85-243" v:mID="85" v:groupContext="shape" transform="translate(233.39,-111.64)">
+			<title>Sheet.85</title>
+			<desc>12</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>12</text>		</g>
+		<g id="shape86-247" v:mID="86" v:groupContext="shape" transform="translate(230.508,-94.9362)">
+			<title>Sheet.86</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape87-249" v:mID="87" v:groupContext="shape" transform="translate(230.508,-94.9362)">
+			<title>Sheet.87</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape88-252" v:mID="88" v:groupContext="shape" transform="translate(233.39,-95.7375)">
+			<title>Sheet.88</title>
+			<desc>…</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.30974" cy="373.835" width="14.62" height="11.9384"/>
+			<path d="M14.62 367.87 L0 367.87 L0 379.8 L14.62 379.8 L14.62 367.87" class="st2"/>
+			<text x="2.34" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>…</text>		</g>
+		<g id="shape89-256" v:mID="89" v:groupContext="shape" transform="translate(230.508,-78.999)">
+			<title>Sheet.89</title>
+			<path d="M0 363.27 L0 379.8 L41.18 379.8 L41.18 363.27 L0 363.27 L0 363.27 Z" class="st7"/>
+		</g>
+		<g id="shape90-258" v:mID="90" v:groupContext="shape" transform="translate(230.508,-78.999)">
+			<title>Sheet.90</title>
+			<path d="M0 363.27 L41.18 363.27 L41.18 379.8 L0 379.8 L0 363.27" class="st5"/>
+		</g>
+		<g id="shape91-261" v:mID="91" v:groupContext="shape" transform="translate(233.39,-79.8525)">
+			<title>Sheet.91</title>
+			<desc>255</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="11.1326" cy="373.835" width="22.27" height="11.9384"/>
+			<path d="M22.27 367.87 L0 367.87 L0 379.8 L22.27 379.8 L22.27 367.87" class="st2"/>
+			<text x="2.84" y="376.82" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>255</text>		</g>
+		<g id="shape92-265" v:mID="92" v:groupContext="shape" transform="translate(276.219,-250.503)">
+			<title>Sheet.92</title>
+			<path d="M0.33 311.98 L396.81 375.94 L396.48 377.95 L0 313.99 L0.33 311.98 L0.33 311.98 ZM396.12 373.75 L401.68 377.74
+						 L395.16 379.8 L396.12 373.75 L396.12 373.75 Z" class="st15"/>
+		</g>
+		<g id="shape93-267" v:mID="93" v:groupContext="shape" transform="translate(275.859,-178.426)">
+			<title>Sheet.93</title>
+			<path d="M0.57 305.72 L230.93 376.21 L230.33 378.16 L0 307.67 L0.57 305.72 L0.57 305.72 ZM230.57 373.96 L235.52 378.67
+						 L228.77 379.8 L230.57 373.96 L230.57 373.96 Z" class="st15"/>
+		</g>
+		<g id="shape94-269" v:mID="94" v:groupContext="shape" transform="translate(276.279,-151.285)">
+			<title>Sheet.94</title>
+			<path d="M0.21 379.8 L230.12 353.17 L229.88 351.14 L0 377.8 L0.21 379.8 L0.21 379.8 ZM229.34 355.3 L235.07 351.55 L228.65
+						 349.25 L229.34 355.3 L229.34 355.3 Z" class="st15"/>
+		</g>
+		<g id="shape95-271" v:mID="95" v:groupContext="shape" transform="translate(276.009,-232.679)">
+			<title>Sheet.95</title>
+			<path d="M0.27 327.47 L354.22 375.91 L353.95 377.92 L0 329.48 L0.27 327.47 L0.27 327.47 ZM353.5 373.75 L359.15 377.62
+						 L352.66 379.8 L353.5 373.75 L353.5 373.75 Z" class="st10"/>
+		</g>
+		<g id="shape96-273" v:mID="96" v:groupContext="shape" transform="translate(276.279,-201.134)">
+			<title>Sheet.96</title>
+			<path d="M0.21 379.8 L353.86 348.14 L353.68 346.1 L0 377.77 L0.21 379.8 L0.21 379.8 ZM353.05 350.24 L358.88 346.64 L352.48
+						 344.16 L353.05 350.24 L353.05 350.24 Z" class="st15"/>
+		</g>
+		<g id="shape97-275" v:mID="97" v:groupContext="shape" transform="translate(346.482,-41.2531)">
+			<title>Sheet.97</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st7"/>
+		</g>
+		<g id="shape98-277" v:mID="98" v:groupContext="shape" transform="translate(346.482,-41.2531)">
+			<title>Sheet.98</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape99-280" v:mID="99" v:groupContext="shape" transform="translate(349.371,-91.6514)">
+			<title>Sheet.99</title>
+			<desc>…</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.30974" cy="373.835" width="14.62" height="11.9384"/>
+			<path d="M14.62 367.87 L0 367.87 L0 379.8 L14.62 379.8 L14.62 367.87" class="st2"/>
+			<text x="2.34" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>…</text>		</g>
+		<g id="shape100-284" v:mID="100" v:groupContext="shape" transform="translate(470.019,-94.337)">
+			<title>Sheet.100</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st7"/>
+		</g>
+		<g id="shape101-286" v:mID="101" v:groupContext="shape" transform="translate(470.019,-94.337)">
+			<title>Sheet.101</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape102-289" v:mID="102" v:groupContext="shape" transform="translate(472.925,-144.778)">
+			<title>Sheet.102</title>
+			<desc>5</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>5</text>		</g>
+		<g id="shape103-293" v:mID="103" v:groupContext="shape" transform="translate(511.558,-113.749)">
+			<title>Sheet.103</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape104-295" v:mID="104" v:groupContext="shape" transform="translate(511.558,-113.749)">
+			<title>Sheet.104</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape105-298" v:mID="105" v:groupContext="shape" transform="translate(514.441,-164.138)">
+			<title>Sheet.105</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape106-302" v:mID="106" v:groupContext="shape" transform="translate(542.148,-164.138)">
+			<title>Sheet.106</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape107-306" v:mID="107" v:groupContext="shape" transform="translate(542.148,-152.155)">
+			<title>Sheet.107</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape108-310" v:mID="108" v:groupContext="shape" transform="translate(536.626,-140.172)">
+			<title>Sheet.108</title>
+			<desc>10</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>10</text>		</g>
+		<g id="shape109-314" v:mID="109" v:groupContext="shape" transform="translate(514.201,-114.441)">
+			<title>Sheet.109</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape110-318" v:mID="110" v:groupContext="shape" transform="translate(519.723,-114.441)">
+			<title>Sheet.110</title>
+			<desc>+4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="8.11122" cy="373.835" width="16.23" height="11.9384"/>
+			<path d="M16.22 367.87 L0 367.87 L0 379.8 L16.22 379.8 L16.22 367.87" class="st2"/>
+			<text x="2.44" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>+4</text>		</g>
+		<g id="shape111-322" v:mID="111" v:groupContext="shape" transform="translate(552.257,-130.525)">
+			<title>Sheet.111</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st7"/>
+		</g>
+		<g id="shape112-324" v:mID="112" v:groupContext="shape" transform="translate(552.257,-130.525)">
+			<title>Sheet.112</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape113-327" v:mID="113" v:groupContext="shape" transform="translate(555.203,-180.952)">
+			<title>Sheet.113</title>
+			<desc>3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>3</text>		</g>
+		<g id="shape114-331" v:mID="114" v:groupContext="shape" transform="translate(634.615,-169.11)">
+			<title>Sheet.114</title>
+			<path d="M0 313.9 L0 379.8 L41.18 379.8 L41.18 313.9 L0 313.9 L0 313.9 Z" class="st4"/>
+		</g>
+		<g id="shape115-333" v:mID="115" v:groupContext="shape" transform="translate(634.615,-169.11)">
+			<title>Sheet.115</title>
+			<path d="M0 313.9 L41.18 313.9 L41.18 379.8 L0 379.8 L0 313.9" class="st5"/>
+		</g>
+		<g id="shape116-336" v:mID="116" v:groupContext="shape" transform="translate(637.526,-219.595)">
+			<title>Sheet.116</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape117-340" v:mID="117" v:groupContext="shape" transform="translate(665.234,-219.595)">
+			<title>Sheet.117</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape118-344" v:mID="118" v:groupContext="shape" transform="translate(665.2,-225.489)">
+			<title>Sheet.118</title>
+			<path d="M0 379.32 L0 379.8 L5.52 379.8 L5.52 379.32 L0 379.32 L0 379.32 Z" class="st19"/>
+		</g>
+		<g id="shape119-346" v:mID="119" v:groupContext="shape" transform="translate(665.234,-207.612)">
+			<title>Sheet.119</title>
+			<desc>7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>7</text>		</g>
+		<g id="shape120-350" v:mID="120" v:groupContext="shape" transform="translate(637.286,-169.898)">
+			<title>Sheet.120</title>
+			<desc>5</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>5</text>		</g>
+		<g id="shape121-354" v:mID="121" v:groupContext="shape" transform="translate(642.809,-169.898)">
+			<title>Sheet.121</title>
+			<desc>-</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="3.49545" cy="373.835" width="7" height="11.9384"/>
+			<path d="M6.99 367.87 L0 367.87 L0 379.8 L6.99 379.8 L6.99 367.87" class="st2"/>
+			<text x="1.84" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>-</text>		</g>
+		<g id="shape122-358" v:mID="122" v:groupContext="shape" transform="translate(646.17,-169.898)">
+			<title>Sheet.122</title>
+			<desc>3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>3</text>		</g>
+		<g id="shape123-362" v:mID="123" v:groupContext="shape" transform="translate(676.275,-186.725)">
+			<title>Sheet.123</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape124-364" v:mID="124" v:groupContext="shape" transform="translate(676.275,-186.725)">
+			<title>Sheet.124</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape125-367" v:mID="125" v:groupContext="shape" transform="translate(679.141,-237.17)">
+			<title>Sheet.125</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape126-371" v:mID="126" v:groupContext="shape" transform="translate(706.849,-237.17)">
+			<title>Sheet.126</title>
+			<desc>0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text>		</g>
+		<g id="shape127-375" v:mID="127" v:groupContext="shape" transform="translate(678.901,-187.474)">
+			<title>Sheet.127</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape128-379" v:mID="128" v:groupContext="shape" transform="translate(304.943,-21.841)">
+			<title>Sheet.128</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape129-381" v:mID="129" v:groupContext="shape" transform="translate(304.943,-21.841)">
+			<title>Sheet.129</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape130-384" v:mID="130" v:groupContext="shape" transform="translate(307.855,-72.2917)">
+			<title>Sheet.130</title>
+			<desc>64</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>64</text>		</g>
+		<g id="shape131-388" v:mID="131" v:groupContext="shape" transform="translate(330.041,-72.2917)">
+			<title>Sheet.131</title>
+			<desc>96</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>96</text>		</g>
+		<g id="shape132-392" v:mID="132" v:groupContext="shape" transform="translate(307.616,-22.5952)">
+			<title>Sheet.132</title>
+			<desc>7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>7</text>		</g>
+		<g id="shape133-396" v:mID="133" v:groupContext="shape" transform="translate(428.72,-77.4413)">
+			<title>Sheet.133</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape134-398" v:mID="134" v:groupContext="shape" transform="translate(428.72,-77.4413)">
+			<title>Sheet.134</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape135-401" v:mID="135" v:groupContext="shape" transform="translate(431.648,-127.825)">
+			<title>Sheet.135</title>
+			<desc>6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>6</text>		</g>
+		<g id="shape136-405" v:mID="136" v:groupContext="shape" transform="translate(453.834,-127.825)">
+			<title>Sheet.136</title>
+			<desc>98</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>98</text>		</g>
+		<g id="shape137-409" v:mID="137" v:groupContext="shape" transform="translate(431.409,-78.1289)">
+			<title>Sheet.137</title>
+			<desc>5</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>5</text>		</g>
+		<g id="shape138-413" v:mID="138" v:groupContext="shape" transform="translate(593.796,-149.818)">
+			<title>Sheet.138</title>
+			<path d="M0 313.9 L0 379.8 L41.18 379.8 L41.18 313.9 L0 313.9 L0 313.9 Z" class="st4"/>
+		</g>
+		<g id="shape139-415" v:mID="139" v:groupContext="shape" transform="translate(593.796,-149.818)">
+			<title>Sheet.139</title>
+			<path d="M0 313.9 L41.18 313.9 L41.18 379.8 L0 379.8 L0 313.9" class="st5"/>
+		</g>
+		<g id="shape140-418" v:mID="140" v:groupContext="shape" transform="translate(596.718,-200.312)">
+			<title>Sheet.140</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape141-422" v:mID="141" v:groupContext="shape" transform="translate(618.904,-200.312)">
+			<title>Sheet.141</title>
+			<desc>99</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>99</text>		</g>
+		<g id="shape142-426" v:mID="142" v:groupContext="shape" transform="translate(596.478,-150.615)">
+			<title>Sheet.142</title>
+			<desc>9</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>9</text>		</g>
+		<g id="shape143-430" v:mID="143" v:groupContext="shape" transform="translate(387.181,-58.0291)">
+			<title>Sheet.143</title>
+			<path d="M0 314.02 L0 379.8 L41.18 379.8 L41.18 314.02 L0 314.02 L0 314.02 Z" class="st4"/>
+		</g>
+		<g id="shape144-432" v:mID="144" v:groupContext="shape" transform="translate(387.181,-58.0291)">
+			<title>Sheet.144</title>
+			<path d="M0 314.02 L41.18 314.02 L41.18 379.8 L0 379.8 L0 314.02" class="st5"/>
+		</g>
+		<g id="shape145-435" v:mID="145" v:groupContext="shape" transform="translate(390.133,-108.466)">
+			<title>Sheet.145</title>
+			<desc>7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>7</text>		</g>
+		<g id="shape146-439" v:mID="146" v:groupContext="shape" transform="translate(412.318,-108.466)">
+			<title>Sheet.146</title>
+			<desc>97</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="7.95203" cy="373.835" width="15.91" height="11.9384"/>
+			<path d="M15.9 367.87 L0 367.87 L0 379.8 L15.9 379.8 L15.9 367.87" class="st2"/>
+			<text x="2.42" y="376.82" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>97</text>		</g>
+		<g id="shape147-443" v:mID="147" v:groupContext="shape" transform="translate(389.893,-58.7692)">
+			<title>Sheet.147</title>
+			<desc>6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.77151" cy="373.835" width="9.55" height="11.9384"/>
+			<path d="M9.54 367.87 L0 367.87 L0 379.8 L9.54 379.8 L9.54 367.87" class="st2"/>
+			<text x="2.01" y="376.82" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>6</text>		</g>
+		<g id="shape148-447" v:mID="148" v:groupContext="shape" transform="translate(31.8163,-277.674)">
+			<title>Sheet.148</title>
+			<path d="M0 362.83 C0 360.95 1.52 359.43 3.41 359.43 L68.51 359.43 C70.4 359.43 71.91 360.95 71.91 362.83 L71.91 376.41
+						 C71.91 378.28 70.4 379.8 68.51 379.8 L3.41 379.8 C1.52 379.8 0 378.28 0 376.41 L0 362.83 Z" class="st4"/>
+		</g>
+		<g id="shape149-449" v:mID="149" v:groupContext="shape" transform="translate(31.8163,-277.674)">
+			<title>Sheet.149</title>
+			<path d="M0 362.83 C0 360.95 1.52 359.43 3.41 359.43 L68.51 359.43 C70.4 359.43 71.91 360.95 71.91 362.83 L71.91 376.41
+						 C71.91 378.28 70.4 379.8 68.51 379.8 L3.41 379.8 C1.52 379.8 0 378.28 0 376.41 L0 362.83 Z" class="st21"/>
+		</g>
+		<g id="shape150-451" v:mID="150" v:groupContext="shape" transform="translate(36,-278.851)">
+			<title>Sheet.150</title>
+			<desc>Insert key</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="35.613" cy="372.612" width="71.23" height="14.3829"/>
+			<path d="M71.23 365.42 L0 365.42 L0 379.8 L71.23 379.8 L71.23 365.42" class="st2"/>
+			<text x="9.64" y="376.21" class="st22" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Insert key    </text>		</g>
+		<g id="shape151-455" v:mID="151" v:groupContext="shape" transform="translate(47.7236,-257.004)">
+			<title>Sheet.151</title>
+			<path d="M0 369.44 L9.81 369.44 L9.81 359.07 L29.44 359.07 L29.44 369.44 L39.26 369.44 L19.63 379.8 L0 369.44 Z"
+					class="st23"/>
+		</g>
+		<g id="shape152-457" v:mID="152" v:groupContext="shape" transform="translate(31.8163,-236.094)">
+			<title>Sheet.152</title>
+			<path d="M0 362.73 C0 360.85 1.54 359.31 3.42 359.31 L68.49 359.31 C70.38 359.31 71.91 360.85 71.91 362.73 L71.91 376.39
+						 C71.91 378.28 70.38 379.8 68.49 379.8 L3.42 379.8 C1.54 379.8 0 378.28 0 376.39 L0 362.73 Z" class="st4"/>
+		</g>
+		<g id="shape153-459" v:mID="153" v:groupContext="shape" transform="translate(31.8163,-236.094)">
+			<title>Sheet.153</title>
+			<path d="M0 362.73 C0 360.85 1.54 359.31 3.42 359.31 L68.49 359.31 C70.38 359.31 71.91 360.85 71.91 362.73 L71.91 376.39
+						 C71.91 378.28 70.38 379.8 68.49 379.8 L3.42 379.8 C1.54 379.8 0 378.28 0 376.39 L0 362.73 Z" class="st21"/>
+		</g>
+		<g id="shape154-461" v:mID="154" v:groupContext="shape" transform="translate(54.6845,-237.332)">
+			<title>Sheet.154</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.8573" cy="372.612" width="33.72" height="14.3829"/>
+			<path d="M33.71 365.42 L0 365.42 L0 379.8 L33.71 379.8 L33.71 365.42" class="st2"/>
+			<text x="3.86" y="376.21" class="st22" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape155-465" v:mID="155" v:groupContext="shape" transform="translate(23.0522,-195.232)">
+			<title>Sheet.155</title>
+			<path d="M0 363.53 C0 361.73 1.46 360.27 3.26 360.27 L87.15 360.27 C88.95 360.27 90.4 361.73 90.4 363.53 L90.4 376.55
+						 C90.4 378.35 88.95 379.8 87.15 379.8 L3.26 379.8 C1.46 379.8 0 378.35 0 376.55 L0 363.53 Z" class="st4"/>
+		</g>
+		<g id="shape156-467" v:mID="156" v:groupContext="shape" transform="translate(23.0522,-195.232)">
+			<title>Sheet.156</title>
+			<path d="M0 363.53 C0 361.73 1.46 360.27 3.26 360.27 L87.15 360.27 C88.95 360.27 90.4 361.73 90.4 363.53 L90.4 376.55
+						 C90.4 378.35 88.95 379.8 87.15 379.8 L3.26 379.8 C1.46 379.8 0 378.35 0 376.55 L0 363.53 Z" class="st21"/>
+		</g>
+		<g id="shape157-469" v:mID="157" v:groupContext="shape" transform="translate(27,-196.017)">
+			<title>Sheet.157</title>
+			<desc>0x0102ABCD</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.6644" cy="372.612" width="87.33" height="14.3829"/>
+			<path d="M87.33 365.42 L0 365.42 L0 379.8 L87.33 379.8 L87.33 365.42" class="st2"/>
+			<text x="7.36" y="376.21" class="st22" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102ABCD</text>		</g>
+		<g id="shape158-473" v:mID="158" v:groupContext="shape" transform="translate(47.7236,-214.824)">
+			<title>Sheet.158</title>
+			<path d="M0 369.5 L9.81 369.5 L9.81 359.19 L29.44 359.19 L29.44 369.5 L39.26 369.5 L19.63 379.8 L0 369.5 Z"
+					class="st23"/>
+		</g>
+		<g id="shape159-475" v:mID="159" v:groupContext="shape" transform="translate(49.8539,-181.212)">
+			<title>Sheet.159</title>
+			<path d="M11.89 368.42 C11.89 371.57 11.47 374.11 10.94 374.11 L6.9 374.11 C6.37 374.11 5.94 376.67 5.94 379.8 C5.94
+						 376.67 5.52 374.11 5 374.11 L0.95 374.11 C0.43 374.11 0 371.57 0 368.42" class="st24"/>
+		</g>
+		<g id="shape160-478" v:mID="160" v:groupContext="shape" transform="translate(64.2606,-180.973)">
+			<title>Sheet.160</title>
+			<path d="M9.54 368.54 C9.54 371.66 9.21 374.17 8.79 374.17 L5.53 374.17 C5.11 374.17 4.77 376.7 4.77 379.8 C4.77 376.7
+						 4.43 374.17 4.02 374.17 L0.76 374.17 C0.34 374.17 0 371.66 0 368.54" class="st24"/>
+		</g>
+		<g id="shape161-481" v:mID="161" v:groupContext="shape" transform="translate(18.19,-60.9649)">
+			<title>Sheet.161</title>
+			<path d="M0 354.74 C0 351.97 2.25 349.73 5.03 349.73 L10.77 349.73 L30.27 267.14 L26.92 349.73 L59.58 349.73 C62.35 349.73
+						 64.59 351.97 64.59 354.74 L64.59 354.74 L64.59 362.26 L64.59 374.8 C64.59 377.57 62.35 379.8 59.58 379.8
+						 L26.92 379.8 L10.77 379.8 L10.77 379.8 L5.03 379.8 C2.25 379.8 0 377.57 0 374.8 L0 362.26 L0 354.74 L0 354.74
+						 Z" class="st23"/>
+		</g>
+		<g id="shape162-483" v:mID="162" v:groupContext="shape" transform="translate(28.141,-66.9569)">
+			<title>Sheet.162</title>
+			<desc>chunk id</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="27.5794" cy="372.612" width="55.16" height="14.3829"/>
+			<path d="M55.16 365.42 L0 365.42 L0 379.8 L55.16 379.8 L55.16 365.42" class="st2"/>
+			<text x="5.26" y="376.21" class="st25" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>chunk id</text>		</g>
+		<g id="shape163-487" v:mID="163" v:groupContext="shape" transform="translate(50.8451,-112.132)">
+			<title>Sheet.163</title>
+			<path d="M0 354.64 C0 351.87 2.27 349.61 5.04 349.61 L10.74 349.61 L16.27 313.66 L26.86 349.61 L59.43 349.61 C62.22 349.61
+						 64.47 351.87 64.47 354.64 L64.47 354.64 L64.47 362.19 L64.47 374.77 C64.47 377.56 62.22 379.8 59.43 379.8
+						 L26.86 379.8 L10.74 379.8 L10.74 379.8 L5.04 379.8 C2.27 379.8 0 377.56 0 374.77 L0 362.19 L0 354.64 L0
+						 354.64 Z" class="st23"/>
+		</g>
+		<g id="shape164-489" v:mID="164" v:groupContext="shape" transform="translate(68.8168,-118.181)">
+			<title>Sheet.164</title>
+			<desc>bin id</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="18.3881" cy="372.612" width="36.78" height="14.3829"/>
+			<path d="M36.78 365.42 L0 365.42 L0 379.8 L36.78 379.8 L36.78 365.42" class="st2"/>
+			<text x="4.06" y="376.21" class="st25" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bin id</text>		</g>
+		<g id="shape165-493" v:mID="165" v:groupContext="shape" transform="translate(113.454,-225.085)">
+			<title>Sheet.165</title>
+			<path d="M0.01 375.68 L13.23 375.73 L13.22 377.77 L0 377.72 L0.01 375.68 L0.01 375.68 ZM12.22 373.69 L18.33 376.76 L12.2
+						 379.8 L12.22 373.69 L12.22 373.69 Z" class="st26"/>
+		</g>
+		<g id="shape166-495" v:mID="166" v:groupContext="shape" transform="translate(200.975,-280.969)">
+			<title>Sheet.166</title>
+			<path d="M0 375.73 L20.11 375.73 L20.11 377.77 L0 377.77 L0 375.73 L0 375.73 ZM19.09 373.69 L25.21 376.75 L19.09 379.8
+						 L19.09 373.69 L19.09 373.69 Z" class="st26"/>
+		</g>
+		<g id="shape167-497" v:mID="167" v:groupContext="shape" transform="translate(275.739,-179.745)">
+			<title>Sheet.167</title>
+			<path d="M0.81 274.59 L231.38 376.48 L230.54 378.37 L0 276.48 L0.81 274.59 L0.81 274.59 ZM231.26 374.2 L235.64 379.47
+						 L228.8 379.8 L231.26 374.2 L231.26 374.2 Z" class="st27"/>
+		</g>
+		<g id="shape168-499" v:mID="168" v:groupContext="shape" transform="translate(521.823,-96.8834)">
+			<title>Sheet.168</title>
+			<path d="M127.17 309.02 L127.17 378.79 C127.17 379.35 126.72 379.8 126.15 379.8 L3.06 379.8 C2.52 379.8 2.04 379.35 2.04
+						 378.79 L2.04 369.59 L4.08 369.59 L4.08 378.79 L3.06 377.77 L126.15 377.77 L125.13 378.79 L125.13 309.02
+						 L127.17 309.02 ZM0 370.61 L3.06 364.5 L6.12 370.61 L0 370.61 Z" class="st28"/>
+		</g>
+		<g id="shape169-501" v:mID="169" v:groupContext="shape" transform="translate(478.603,-39.7553)">
+			<title>Sheet.169</title>
+			<path d="M0 347.57 C0 344.01 2.91 341.1 6.48 341.1 L237.86 341.1 C241.43 341.1 244.31 344.01 244.31 347.57 L244.31 373.36
+						 C244.31 376.93 241.43 379.8 237.86 379.8 L6.48 379.8 C2.91 379.8 0 376.93 0 373.36 L0 347.57 Z"
+					class="st23"/>
+		</g>
+		<g id="shape170-503" v:mID="170" v:groupContext="shape" transform="translate(487.717,-45.5378)">
+			<title>Sheet.170</title>
+			<desc>Move bin from group 1 to 4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="126.387" cy="369.018" width="252.78" height="21.5726"/>
+			<path d="M252.77 358.23 L0 358.23 L0 379.8 L252.77 379.8 L252.77 358.23" class="st2"/>
+			<text x="18.98" y="374.41" class="st29" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Move bin from group 1 to 4</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i2.svg b/doc/guides/prog_guide/img/efd_i2.svg
new file mode 100644
index 0000000..a5f43f9
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i2.svg
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i2.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="2.85156in" height="2.98777in"
+		viewBox="0 0 205.313 215.12" xml:space="preserve" color-interpolation-filters="sRGB" class="st18">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st5 {fill:#ff0000;stroke:#c7c8c8;stroke-width:0.25}
+		.st6 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st7 {fill:none;stroke:#0070c0;stroke-width:1.5}
+		.st8 {marker-end:url(#mrkr5-91);stroke:#0070c0;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st9 {fill:#0070c0;fill-opacity:1;stroke:#0070c0;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st10 {fill:none;stroke:none;stroke-width:0.25}
+		.st11 {fill:#ff0000;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st12 {font-size:1em}
+		.st13 {marker-end:url(#mrkr5-101);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st14 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st15 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st16 {marker-end:url(#mrkr5-110);stroke:#41719c;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st17 {fill:#41719c;fill-opacity:1;stroke:#41719c;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st18 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-91" class="st9" v:arrowType="5" v:arrowSize="2" v:setback="4.45" refX="-4.45" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+		<marker id="mrkr5-101" class="st14" v:arrowType="5" v:arrowSize="2" v:setback="6.16" refX="-6.16" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+		</marker>
+		<marker id="mrkr5-110" class="st17" v:arrowType="5" v:arrowSize="2" v:setback="6.16" refX="-6.16" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(24.4044,-42.7174)">
+			<title>Circle</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow2-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 138.62 A76.5 76.5 0 0 1 153 138.62 A76.5 76.5 0 1 1 0 138.62 Z" class="st2"/>
+			</g>
+			<path d="M0 138.62 A76.5 76.5 0 0 1 153 138.62 A76.5 76.5 0 1 1 0 138.62 Z" class="st3"/>
+		</g>
+		<g id="shape3-6" v:mID="3" v:groupContext="shape" transform="translate(24.4044,-144.53)">
+			<title>Circle.3</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow3-7" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape4-11" v:mID="4" v:groupContext="shape" transform="translate(21.0294,-102.342)">
+			<title>Circle.4</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow4-12" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape5-16" v:mID="5" v:groupContext="shape" transform="translate(69.4044,-183.342)">
+			<title>Circle.5</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow5-17" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape6-21" v:mID="6" v:groupContext="shape" transform="translate(117.217,-183.342)">
+			<title>Circle.6</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow6-22" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st5"/>
+		</g>
+		<g id="shape7-26" v:mID="7" v:groupContext="shape" transform="translate(171.217,-104.03)">
+			<title>Circle.7</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow7-27" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st5"/>
+		</g>
+		<g id="shape8-31" v:mID="8" v:groupContext="shape" transform="translate(109.904,-38.2174)">
+			<title>Circle.8</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow8-32" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st5"/>
+		</g>
+		<g id="shape9-36" v:mID="9" v:groupContext="shape" transform="translate(21.0294,-124.842)">
+			<title>Circle.9</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow9-37" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st5"/>
+		</g>
+		<g id="shape10-41" v:mID="10" v:groupContext="shape" transform="translate(147.029,-168.717)">
+			<title>Circle.10</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow10-42" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape11-46" v:mID="11" v:groupContext="shape" transform="translate(138.029,-48.3424)">
+			<title>Circle.11</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow11-47" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape12-51" v:mID="12" v:groupContext="shape" transform="translate(160.529,-74.2174)">
+			<title>Circle.12</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow12-52" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape13-56" v:mID="13" v:groupContext="shape" transform="translate(40.7169,-57.3424)">
+			<title>Circle.13</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow13-57" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape14-61" v:mID="14" v:groupContext="shape" transform="translate(42.4044,-168.717)">
+			<title>Circle.14</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow14-62" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape15-66" v:mID="15" v:groupContext="shape" transform="translate(66.0294,-42.7174)">
+			<title>Circle.15</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow15-67" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(25.5294,-79.8424)">
+			<title>Circle.16</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow16-72" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape17-76" v:mID="17" v:groupContext="shape" transform="translate(165.029,-143.405)">
+			<title>Circle.17</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow17-77" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st2"/>
+			</g>
+			<path d="M0 208.93 A6.1875 6.1875 0 1 1 12.37 208.93 A6.1875 6.1875 0 0 1 0 208.93 Z" class="st4"/>
+		</g>
+		<g id="shape18-81" v:mID="18" v:groupContext="shape" transform="translate(276.618,4.50201) rotate(45)">
+			<title>Ellipse</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow18-82" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,1.63935,1.1506)" class="st1">
+				<path d="M0 187.01 A14.7383 28.1086 0 1 1 29.48 187.01 A14.7383 28.1086 0 1 1 0 187.01 Z" class="st6"/>
+			</g>
+			<path d="M0 187.01 A14.7383 28.1086 0 1 1 29.48 187.01 A14.7383 28.1086 0 1 1 0 187.01 Z" class="st7"/>
+		</g>
+		<g id="shape19-86" v:mID="19" v:groupContext="shape" transform="translate(251.273,355.436) rotate(156.038)">
+			<title>Sheet.19</title>
+			<path d="M-0 215.12 A73.4538 31.2572 85.43 0 1 40.92 208.96 L41.1 209.27" class="st8"/>
+		</g>
+		<g id="shape20-92" v:mID="20" v:groupContext="shape" transform="translate(62.705,-78.7174)">
+			<title>Sheet.20</title>
+			<desc>Target Hashed Value</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="42.6994" cy="203.87" width="85.4" height="22.5"/>
+			<rect x="0" y="192.62" width="85.3987" height="22.5" class="st10"/>
+			<text x="6.73" y="200.27" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Target Hashed <tspan
+						x="28.48" dy="1.2em" class="st12">Value</tspan></text>		</g>
+		<g id="shape21-96" v:mID="21" v:groupContext="shape" transform="translate(314.101,88.728) rotate(75.9638)">
+			<title>Sheet.21</title>
+			<path d="M0 215.12 L16.92 215.12" class="st13"/>
+		</g>
+		<g id="shape23-102" v:mID="23" v:groupContext="shape" transform="translate(60.4044,-138.342)">
+			<title>Sheet.23</title>
+			<desc>Keys</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="24.75" cy="203.87" width="49.5" height="22.5"/>
+			<rect x="0" y="192.62" width="49.5" height="22.5" class="st10"/>
+			<text x="13.21" y="207.47" class="st15" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Keys</text>		</g>
+		<g id="shape24-105" v:mID="24" v:groupContext="shape" transform="translate(-125.293,114.034) rotate(-104.574)">
+			<title>Sheet.24</title>
+			<path d="M0 215.12 L22.9 215.12" class="st16"/>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i3.svg b/doc/guides/prog_guide/img/efd_i3.svg
new file mode 100644
index 0000000..ae22903
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i3.svg
@@ -0,0 +1,634 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i3.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="6.56036in" height="5.44284in"
+		viewBox="0 0 472.346 391.884" xml:space="preserve" color-interpolation-filters="sRGB" class="st22">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+		.st5 {marker-end:url(#mrkr5-24);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st6 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st7 {fill:none;stroke:#2e75b5;stroke-width:1}
+		.st8 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+		.st9 {font-size:1em}
+		.st10 {fill:none;stroke:none;stroke-width:1}
+		.st11 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st12 {fill:#5b9bd5;fill-opacity:0.25;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.25}
+		.st13 {fill:#4f87bb;stroke:#40709c;stroke-width:0.75}
+		.st14 {fill:#feffff;font-family:Calibri;font-size:0.75em}
+		.st15 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st16 {fill:none;stroke:#2e75b5;stroke-width:2.25}
+		.st17 {stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st18 {fill:#305497;stroke:#2e75b5;stroke-width:1}
+		.st19 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:none}
+		.st20 {fill:#92d050;fill-opacity:0.3;stroke:none;stroke-width:0.25}
+		.st21 {fill:#feffff;font-family:Calibri;font-size:1.16666em}
+		.st22 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-24" class="st6" v:arrowType="5" v:arrowSize="2" v:setback="6.16" refX="-6.16" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<v:layer v:name="Connector" v:index="0"/>
+		<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(111.25,-354.482)">
+			<title>Rectangle</title>
+			<desc>Packet Header</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="42.75" cy="382.884" width="85.5" height="18"/>
+			<g id="shadow2-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="85.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="85.5" height="18" class="st3"/>
+			<text x="13.24" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Packet Header</text>		</g>
+		<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(192.25,-354.482)">
+			<title>Rectangle.3</title>
+			<desc>Payload</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="382.884" width="108" height="18"/>
+			<g id="shadow3-8" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="108" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="108" height="18" class="st3"/>
+			<text x="37.95" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Payload</text>		</g>
+		<g id="shape4-13" v:mID="4" v:groupContext="shape" transform="translate(136,-311.232)">
+			<title>Rectangle.4</title>
+			<desc>Flow Key</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="27" cy="382.884" width="54" height="18"/>
+			<g id="shadow4-14" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="54" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="54" height="18" class="st3"/>
+			<text x="8.87" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Flow Key</text>		</g>
+		<g id="shape5-19" v:mID="5" v:groupContext="shape" transform="translate(465.501,-160.057) rotate(59.7436)">
+			<title>Sheet.5</title>
+			<path d="M0 391.88 L25.1 391.88" class="st5"/>
+		</g>
+		<g id="shape8-25" v:mID="8" v:groupContext="shape" transform="translate(219.25,-320.169)">
+			<title>Sheet.8</title>
+			<desc>Fields of the packet are used to form a flow Key</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="377.822" width="135" height="28.125"/>
+			<rect x="0" y="363.759" width="135" height="28.125" class="st7"/>
+			<text x="10.7" y="374.22" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Fields of the packet are <tspan
+						x="9.67" dy="1.2em" class="st9">used to form a flow Key</tspan></text>		</g>
+		<g id="group13-29" transform="translate(120.25,-266.897)" v:mID="13" v:groupContext="group">
+			<title>Sheet.13</title>
+			<g id="shape11-30" v:mID="11" v:groupContext="shape" transform="translate(85.5,751.143) rotate(180)">
+				<title>Trapezoid</title>
+				<v:userDefs>
+					<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				</v:userDefs>
+				<g id="shadow11-31" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,-0.345598,-1.97279)" class="st1">
+					<path d="M0 391.88 L85.5 391.88 L60.19 359.26 L25.31 359.26 L0 391.88 Z" class="st2"/>
+				</g>
+				<path d="M0 391.88 L85.5 391.88 L60.19 359.26 L25.31 359.26 L0 391.88 Z" class="st3"/>
+			</g>
+			<g id="shape12-35" v:mID="12" v:groupContext="shape" transform="translate(13.5,-6.525)">
+				<title>Sheet.12</title>
+				<desc>H(..)</desc>
+				<v:textBlock v:margins="rect(4,4,4,4)"/>
+				<v:textRect cx="27" cy="381.689" width="54" height="20.3906"/>
+				<rect x="0" y="371.494" width="54" height="20.3906" class="st10"/>
+				<text x="16.27" y="385.29" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H(..)</text>			</g>
+		</g>
+		<g id="shape14-38" v:mID="14" v:groupContext="shape" transform="translate(-229.872,96.3648) rotate(-90.0429)">
+			<title>Simple Arrow</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ArrowType" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<g id="shadow14-39" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,-1.97305,0.344122)" class="st1">
+				<path d="M0 391.88 L10.18 387.38 L10.18 389.63 L16.71 389.63 L16.71 391.88 L16.71 394.13 L10.18 394.13 L10.18 396.38
+							 L0 391.88 Z" class="st12"/>
+			</g>
+			<path d="M0 391.88 L10.18 387.38 L10.18 389.63 L16.71 389.63 L16.71 391.88 L16.71 394.13 L10.18 394.13 L10.18 396.38
+						 L0 391.88 Z" class="st13"/>
+		</g>
+		<g id="shape15-43" v:mID="15" v:groupContext="shape" transform="translate(212.5,-271.46)">
+			<title>Sheet.15</title>
+			<desc>Hash function is used to create a flow table index</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="377.822" width="135" height="28.125"/>
+			<rect x="0" y="363.759" width="135" height="28.125" class="st7"/>
+			<text x="9.05" y="374.22" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash function is used to <tspan
+						x="7.39" dy="1.2em" class="st9">create a flow table index</tspan></text>		</g>
+		<g id="shape58-47" v:mID="58" v:groupContext="shape" transform="translate(199,-221.397)">
+			<title>Rectangle.58</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow58-48" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape59-53" v:mID="59" v:groupContext="shape" transform="translate(232.75,-221.397)">
+			<title>Rectangle.59</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow59-54" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape60-59" v:mID="60" v:groupContext="shape" transform="translate(280,-221.397)">
+			<title>Rectangle.60</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow60-60" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape61-65" v:mID="61" v:groupContext="shape" transform="translate(313.75,-221.397)">
+			<title>Rectangle.61</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow61-66" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape62-71" v:mID="62" v:groupContext="shape" transform="translate(361,-221.397)">
+			<title>Rectangle.62</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow62-72" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape63-76" v:mID="63" v:groupContext="shape" transform="translate(394.75,-221.397)">
+			<title>Rectangle.63</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow63-77" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape64-81" v:mID="64" v:groupContext="shape" transform="translate(199,-198.897)">
+			<title>Rectangle.64</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow64-82" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape65-86" v:mID="65" v:groupContext="shape" transform="translate(232.75,-198.897)">
+			<title>Rectangle.65</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow65-87" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape66-91" v:mID="66" v:groupContext="shape" transform="translate(280,-198.897)">
+			<title>Rectangle.66</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow66-92" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape67-96" v:mID="67" v:groupContext="shape" transform="translate(313.75,-198.897)">
+			<title>Rectangle.67</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow67-97" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape68-101" v:mID="68" v:groupContext="shape" transform="translate(361,-198.897)">
+			<title>Rectangle.68</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow68-102" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape69-106" v:mID="69" v:groupContext="shape" transform="translate(394.75,-198.897)">
+			<title>Rectangle.69</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow69-107" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape70-111" v:mID="70" v:groupContext="shape" transform="translate(199,-162.897)">
+			<title>Rectangle.70</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow70-112" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape71-117" v:mID="71" v:groupContext="shape" transform="translate(232.75,-162.897)">
+			<title>Rectangle.71</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow71-118" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape72-123" v:mID="72" v:groupContext="shape" transform="translate(280,-162.897)">
+			<title>Rectangle.72</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow72-124" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape73-129" v:mID="73" v:groupContext="shape" transform="translate(313.75,-162.897)">
+			<title>Rectangle.73</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow73-130" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape74-135" v:mID="74" v:groupContext="shape" transform="translate(361,-162.897)">
+			<title>Rectangle.74</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow74-136" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape75-141" v:mID="75" v:groupContext="shape" transform="translate(394.75,-162.897)">
+			<title>Rectangle.75</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow75-142" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape76-147" v:mID="76" v:groupContext="shape" transform="translate(199,-126.397)">
+			<title>Rectangle.76</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow76-148" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape77-152" v:mID="77" v:groupContext="shape" transform="translate(232.75,-126.397)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow77-153" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape78-157" v:mID="78" v:groupContext="shape" transform="translate(280,-126.397)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow78-158" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape79-162" v:mID="79" v:groupContext="shape" transform="translate(313.75,-126.397)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow79-163" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape80-167" v:mID="80" v:groupContext="shape" transform="translate(361,-126.397)">
+			<title>Rectangle.80</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow80-168" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="385.58" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape81-173" v:mID="81" v:groupContext="shape" transform="translate(394.75,-126.397)">
+			<title>Rectangle.81</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="382.884" width="42.75" height="18"/>
+			<g id="shadow81-174" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="385.58" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape82-179" v:mID="82" v:groupContext="shape" transform="translate(196.75,-117.397)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow82-180" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="256.384" width="245.25" height="135.5" class="st15"/>
+			</g>
+			<rect x="0" y="256.384" width="245.25" height="135.5" class="st16"/>
+		</g>
+		<g id="shape83-184" v:mID="83" v:groupContext="shape" transform="translate(554.884,123.862) rotate(90)">
+			<title>Sheet.83</title>
+			<path d="M0 391.88 L99 391.88" class="st17"/>
+		</g>
+		<g id="shape84-187" v:mID="84" v:groupContext="shape" transform="translate(208,-248.397)">
+			<title>Sheet.84</title>
+			<desc>Load Balancing Flow Table</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="91.75" cy="386.259" width="183.5" height="11.25"/>
+			<rect x="0" y="380.634" width="183.5" height="11.25" class="st18"/>
+			<text x="26.14" y="389.86" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Load Balancing Flow Table</text>		</g>
+		<g id="shape85-190" v:mID="85" v:groupContext="shape" transform="translate(190,-157.835)">
+			<title>Rectangle.85</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow85-191" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="363.759" width="261" height="28.125" class="st19"/>
+			</g>
+			<rect x="0" y="363.759" width="261" height="28.125" class="st20"/>
+		</g>
+		<g id="shape86-195" v:mID="86" v:groupContext="shape" transform="translate(163,-169.022)">
+			<title>Sheet.86</title>
+			<path d="M0 391.88 L18.76 391.88" class="st5"/>
+		</g>
+		<g id="shape87-200" v:mID="87" v:groupContext="shape" transform="translate(19,-198.107)">
+			<title>Sheet.87</title>
+			<desc>Hash value used to index Flow table</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="377.822" width="135" height="28.125"/>
+			<rect x="0" y="363.759" width="135" height="28.125" class="st7"/>
+			<text x="6.79" y="374.22" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash value used to index <tspan
+						x="42.16" dy="1.2em" class="st9">Flow table</tspan></text>		</g>
+		<g id="shape88-204" v:mID="88" v:groupContext="shape" transform="translate(551.381,21.2928) rotate(87.9001)">
+			<title>Sheet.88</title>
+			<path d="M0 391.88 L20.86 391.88" class="st5"/>
+		</g>
+		<g id="shape89-209" v:mID="89" v:groupContext="shape" transform="translate(494.785,297.309) rotate(131.987)">
+			<title>Sheet.89</title>
+			<path d="M0 391.88 L30.84 391.88" class="st5"/>
+		</g>
+		<g id="shape90-214" v:mID="90" v:groupContext="shape" transform="translate(228.25,-92.5847)">
+			<title>Rectangle.90</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow90-215" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape91-220" v:mID="91" v:groupContext="shape" transform="translate(340.75,-92.5847)">
+			<title>Rectangle.91</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow91-221" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="group96-226" transform="translate(253,-51.4597)" v:mID="96" v:groupContext="group">
+			<title>Sheet.96</title>
+			<g id="shape97-227" v:mID="97" v:groupContext="shape" transform="translate(85.5,751.143) rotate(180)">
+				<title>Trapezoid</title>
+				<v:userDefs>
+					<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				</v:userDefs>
+				<g id="shadow97-228" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,-0.345598,-1.97279)" class="st1">
+					<path d="M0 391.88 L85.5 391.88 L60.19 359.26 L25.31 359.26 L0 391.88 Z" class="st2"/>
+				</g>
+				<path d="M0 391.88 L85.5 391.88 L60.19 359.26 L25.31 359.26 L0 391.88 Z" class="st3"/>
+			</g>
+			<g id="shape98-232" v:mID="98" v:groupContext="shape" transform="translate(13.5,-6.525)">
+				<title>Sheet.98</title>
+				<desc>Match</desc>
+				<v:textBlock v:margins="rect(4,4,4,4)"/>
+				<v:textRect cx="27" cy="381.689" width="54" height="20.3906"/>
+				<rect x="0" y="371.494" width="54" height="20.3906" class="st10"/>
+				<text x="10.98" y="385.29" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Match</text>			</g>
+		</g>
+		<g id="shape99-235" v:mID="99" v:groupContext="shape" transform="translate(532.137,0.00916548) rotate(54.6508)">
+			<title>Sheet.99</title>
+			<path d="M0 391.88 L93.23 391.88" class="st5"/>
+		</g>
+		<g id="shape100-240" v:mID="100" v:groupContext="shape" transform="translate(683.134,224.487) rotate(90)">
+			<title>Sheet.100</title>
+			<path d="M0 391.88 L77.15 391.88" class="st5"/>
+		</g>
+		<g id="shape101-245" v:mID="101" v:groupContext="shape" transform="translate(692.213,476.024) rotate(129.078)">
+			<title>Sheet.101</title>
+			<path d="M0 391.88 L95.37 391.88" class="st5"/>
+		</g>
+		<g id="shape102-250" v:mID="102" v:groupContext="shape" transform="translate(293.5,-97.0847)">
+			<title>Rectangle.102</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="382.884" width="31.5" height="18"/>
+			<g id="shadow102-251" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape103-256" v:mID="103" v:groupContext="shape" transform="translate(169.75,-55.9597)">
+			<title>Rectangle.103</title>
+			<desc>Flow Key</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="27" cy="382.884" width="54" height="18"/>
+			<g id="shadow103-257" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="54" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="54" height="18" class="st3"/>
+			<text x="8.87" y="385.88" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Flow Key</text>		</g>
+		<g id="shape104-262" v:mID="104" v:groupContext="shape" transform="translate(226,-64.9597)">
+			<title>Sheet.104</title>
+			<path d="M0 391.88 L34.34 391.88" class="st5"/>
+		</g>
+		<g id="shape105-267" v:mID="105" v:groupContext="shape" transform="translate(54,-82.4597)">
+			<title>Sheet.105</title>
+			<desc>Retrieved keys are matched with input key</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="377.822" width="135" height="28.125"/>
+			<rect x="0" y="363.759" width="135" height="28.125" class="st7"/>
+			<text x="22.51" y="374.22" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Retrieved keys are <tspan
+						x="9.83" dy="1.2em" class="st9">matched with input key</tspan></text>		</g>
+		<g id="shape106-271" v:mID="106" v:groupContext="shape" transform="translate(271,-23.9597)">
+			<title>Rectangle.106</title>
+			<desc>Action</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="27" cy="382.884" width="54" height="18"/>
+			<g id="shadow106-272" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="373.884" width="54" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="373.884" width="54" height="18" class="st3"/>
+			<text x="8.67" y="387.08" class="st21" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action</text>		</g>
+		<g id="shape111-277" v:mID="111" v:groupContext="shape" transform="translate(-94.8716,350.902) rotate(-90.0429)">
+			<title>Simple Arrow.111</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ArrowType" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<g id="shadow111-278" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,-1.97305,0.344122)" class="st1">
+				<path d="M0 391.88 L10.18 387.38 L10.18 389.63 L16.71 389.63 L16.71 391.88 L16.71 394.13 L10.18 394.13 L10.18 396.38
+							 L0 391.88 Z" class="st12"/>
+			</g>
+			<path d="M0 391.88 L10.18 387.38 L10.18 389.63 L16.71 389.63 L16.71 391.88 L16.71 394.13 L10.18 394.13 L10.18 396.38
+						 L0 391.88 Z" class="st13"/>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i4.svg b/doc/guides/prog_guide/img/efd_i4.svg
new file mode 100644
index 0000000..5be5ccd
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i4.svg
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i4.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="2.78993in" height="1.78151in"
+		viewBox="0 0 200.875 128.269" xml:space="preserve" color-interpolation-filters="sRGB" class="st19">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:none;stroke:none;stroke-width:0.25}
+		.st2 {fill:#5b9bd5;font-family:Calibri;font-size:0.75em}
+		.st3 {font-size:1em}
+		.st4 {fill:#5b9bd5;font-family:Calibri;font-size:0.75em;font-weight:bold}
+		.st5 {fill:#deebf6;stroke:none;stroke-width:0.25}
+		.st6 {stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st7 {stroke:#5b9bd5;stroke-dasharray:0.75,1.5;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st8 {fill:#ff0000;font-size:1em}
+		.st9 {baseline-shift:-28.8834%;font-size:0.577667em}
+		.st10 {fill:#ff0000;font-family:Calibri;font-size:0.75em}
+		.st11 {fill:#5b9bd5;font-size:1em}
+		.st12 {visibility:visible}
+		.st13 {fill:#5b9bd5;fill-opacity:0.25;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.25}
+		.st14 {fill:url(#grad0-73);stroke:#40709c;stroke-width:0.75}
+		.st15 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+		.st16 {fill:#00fefe;font-size:1em}
+		.st17 {fill:#00b050}
+		.st18 {stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st19 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Patterns_And_Gradients">
+		<linearGradient id="grad0-73" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(250 0.5 0.5)">
+			<stop offset="0" stop-color="#4f87bb" stop-opacity="1"/>
+			<stop offset="0.48" stop-color="#4f87bb" stop-opacity="1"/>
+			<stop offset="0.82" stop-color="#5b9bd5" stop-opacity="1"/>
+		</linearGradient>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(18.25,-59.3478)">
+			<title>Sheet.2</title>
+			<desc>Key 1 Key 2 ... Key 28</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="18" cy="121.519" width="36" height="13.5"/>
+			<rect x="0" y="114.769" width="36" height="13.5" class="st1"/>
+			<text x="8.09" y="108.02" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1<v:newlineChar/><tspan
+						x="8.09" dy="1.2em" class="st3">Key </tspan>2<v:newlineChar/><tspan x="14.59" dy="1.2em" class="st3">...<v:newlineChar/></tspan><tspan
+						x="5.81" dy="1.2em" class="st3">Key </tspan>28</text>		</g>
+		<g id="shape9-7" v:mID="9" v:groupContext="shape" transform="translate(52,-91.9728)">
+			<title>Sheet.9</title>
+			<desc>Target Value</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="17.4375" cy="122.644" width="34.88" height="11.25"/>
+			<rect x="0" y="117.019" width="34.875" height="11.25" class="st1"/>
+			<text x="5.43" y="119.94" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Target <tspan x="6.77"
+						dy="1.2em" class="st3">Value</tspan></text>		</g>
+		<g id="shape11-11" v:mID="11" v:groupContext="shape" transform="translate(52,-42.4728)">
+			<title>Sheet.11</title>
+			<desc>0 1 0</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="17.4375" cy="105.769" width="34.88" height="45"/>
+			<rect x="0" y="83.2689" width="34.875" height="45" class="st5"/>
+			<text x="15.16" y="92.27" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0<v:newlineChar/><tspan
+						x="15.16" dy="1.2em" class="st3">1<v:newlineChar/><v:newlineChar/></tspan><tspan x="15.16" dy="2.4em"
+						class="st3">0</tspan></text>		</g>
+		<g id="shape8-16" v:mID="8" v:groupContext="shape" transform="translate(180.269,21.6711) rotate(90)">
+			<title>Sheet.8</title>
+			<path d="M0 128.27 L69.75 128.27" class="st6"/>
+		</g>
+		<g id="shape10-19" v:mID="10" v:groupContext="shape" transform="translate(215.144,21.6711) rotate(90)">
+			<title>Sheet.10</title>
+			<path d="M0 128.27 L69.75 128.27" class="st6"/>
+		</g>
+		<g id="shape4-22" v:mID="4" v:groupContext="shape" transform="translate(22.75,-77.3478)">
+			<title>Sheet.4</title>
+			<path d="M0 128.27 L157.5 128.27" class="st7"/>
+		</g>
+		<g id="shape5-25" v:mID="5" v:groupContext="shape" transform="translate(23.875,-66.0978)">
+			<title>Sheet.5</title>
+			<path d="M0 128.27 L158.62 128.27" class="st7"/>
+		</g>
+		<g id="shape6-28" v:mID="6" v:groupContext="shape" transform="translate(22.75,-54.8478)">
+			<title>Sheet.6</title>
+			<path d="M0 128.27 L159.75 128.27" class="st7"/>
+		</g>
+		<g id="shape7-31" v:mID="7" v:groupContext="shape" transform="translate(22.75,-87.4728)">
+			<title>Sheet.7</title>
+			<path d="M0 128.27 L155.25 128.27" class="st6"/>
+		</g>
+		<g id="shape12-34" v:mID="12" v:groupContext="shape" transform="translate(91.9375,-42.4728)">
+			<title>Sheet.12</title>
+			<desc>0 0 0</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="8.4375" cy="105.769" width="16.88" height="45"/>
+			<rect x="0" y="83.2689" width="16.875" height="45" class="st1"/>
+			<text x="6.16" y="92.27" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0<v:newlineChar/><tspan
+						x="6.16" dy="1.2em" class="st8">0<v:newlineChar/><v:newlineChar/></tspan><tspan x="6.16" dy="2.4em"
+						class="st3">0</tspan></text>		</g>
+		<g id="shape26-39" v:mID="26" v:groupContext="shape" transform="translate(86.875,-88.5978)">
+			<title>Sheet.26</title>
+			<desc>H1(x)</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="14.0625" cy="122.644" width="28.13" height="11.25"/>
+			<rect x="0" y="117.019" width="28.125" height="11.25" class="st1"/>
+			<text x="5.03" y="125.34" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan dy="-0.284em"
+						class="st9" v:baseFontSize="8">1</tspan><tspan dy="0.164em" class="st3">(</tspan>x)</text>		</g>
+		<g id="shape27-44" v:mID="27" v:groupContext="shape" transform="translate(115,-42.4728)">
+			<title>Sheet.27</title>
+			<desc>1 1 0</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="8.4375" cy="105.769" width="16.88" height="45"/>
+			<rect x="0" y="83.2689" width="16.875" height="45" class="st1"/>
+			<text x="6.16" y="92.27" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1<v:newlineChar/><tspan
+						x="6.16" dy="1.2em" class="st11">1<v:newlineChar/><v:newlineChar/></tspan><tspan x="6.16" dy="2.4em"
+						class="st11">0</tspan></text>		</g>
+		<g id="shape28-49" v:mID="28" v:groupContext="shape" transform="translate(109.938,-88.5978)">
+			<title>Sheet.28</title>
+			<desc>H2(x)</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="14.0625" cy="122.644" width="28.13" height="11.25"/>
+			<rect x="0" y="117.019" width="28.125" height="11.25" class="st1"/>
+			<text x="5.03" y="125.34" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan dy="-0.284em"
+						class="st9" v:baseFontSize="8">2</tspan><tspan dy="0.164em" class="st3">(</tspan>x)</text>		</g>
+		<g id="shape29-54" v:mID="29" v:groupContext="shape" transform="translate(155.5,-42.4728)">
+			<title>Sheet.29</title>
+			<desc>0 1 0</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="8.4375" cy="105.769" width="16.88" height="45"/>
+			<rect x="0" y="83.2689" width="16.875" height="45" class="st1"/>
+			<text x="6.16" y="92.27" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0<v:newlineChar/><tspan
+						x="6.16" dy="1.2em" class="st3">1<v:newlineChar/><v:newlineChar/></tspan><tspan x="6.16" dy="2.4em"
+						class="st3">0</tspan></text>		</g>
+		<g id="shape30-59" v:mID="30" v:groupContext="shape" transform="translate(150.438,-88.5978)">
+			<title>Sheet.30</title>
+			<desc>Hm(x)</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="14.0625" cy="122.644" width="28.13" height="11.25"/>
+			<rect x="0" y="117.019" width="28.125" height="11.25" class="st1"/>
+			<text x="4.24" y="125.34" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan dy="-0.284em"
+						class="st9" v:baseFontSize="8">m</tspan><tspan dy="0.164em" class="st3">(</tspan>x)</text>		</g>
+		<g id="shape31-64" v:mID="31" v:groupContext="shape" transform="translate(130.188,-89.7228)">
+			<title>Sheet.31</title>
+			<desc>…..</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="14.0625" cy="122.644" width="28.13" height="11.25"/>
+			<rect x="0" y="117.019" width="28.125" height="11.25" class="st1"/>
+			<text x="8.46" y="125.34" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>…..</text>		</g>
+		<g id="shape32-67" v:mID="32" v:groupContext="shape" transform="translate(34,-23.3478)">
+			<title>Sheet.32</title>
+			<desc>Store m for this group of keys</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="66.375" cy="122.644" width="132.75" height="11.25"/>
+			<g id="shadow32-68" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st12">
+				<rect x="0" y="117.019" width="132.75" height="11.25" class="st13"/>
+			</g>
+			<rect x="0" y="117.019" width="132.75" height="11.25" class="st14"/>
+			<text x="6.32" y="125.64" class="st15" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Store <tspan
+						class="st16">m</tspan> for this group of keys</text>		</g>
+		<g id="shape36-76" v:mID="36" v:groupContext="shape" transform="translate(159.381,-100.964)">
+			<title>Sheet.36</title>
+			<path d="M3.45 125.81 L6.87 119.34 L7.99 120.16 L3.87 128.27 L0 124.35 L0.86 123.13 L3.45 125.81 Z" class="st17"/>
+		</g>
+		<g id="group44-79" transform="translate(97.5625,-100.086)" v:mID="44" v:groupContext="group">
+			<title>Sheet.44</title>
+			<g id="shape42-80" v:mID="42" v:groupContext="shape" transform="translate(85.4972,28.6255) rotate(41.8011)">
+				<title>Sheet.42</title>
+				<path d="M0 128.27 L6.04 128.27" class="st18"/>
+			</g>
+			<g id="shape43-83" v:mID="43" v:groupContext="shape" transform="translate(-87.9035,34.8564) rotate(-43.2597)">
+				<title>Sheet.43</title>
+				<path d="M0 128.27 L5.87 128.27" class="st18"/>
+			</g>
+		</g>
+		<g id="group45-86" transform="translate(120.625,-100.086)" v:mID="45" v:groupContext="group">
+			<title>Sheet.45</title>
+			<g id="shape46-87" v:mID="46" v:groupContext="shape" transform="translate(85.4972,28.6255) rotate(41.8011)">
+				<title>Sheet.46</title>
+				<path d="M0 128.27 L6.04 128.27" class="st18"/>
+			</g>
+			<g id="shape47-90" v:mID="47" v:groupContext="shape" transform="translate(-87.9035,34.8564) rotate(-43.2597)">
+				<title>Sheet.47</title>
+				<path d="M0 128.27 L5.87 128.27" class="st18"/>
+			</g>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i5.svg b/doc/guides/prog_guide/img/efd_i5.svg
new file mode 100644
index 0000000..b6540ba
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i5.svg
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i5.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.34375in" height="2.86443in"
+		viewBox="0 0 600.75 206.239" xml:space="preserve" color-interpolation-filters="sRGB" class="st14">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#feffff;font-family:Calibri;font-size:1.5em}
+		.st5 {fill:#feffff;font-family:Calibri;font-size:1.16666em}
+		.st6 {marker-end:url(#mrkr5-36);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st7 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st8 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st9 {fill:none;stroke:none;stroke-width:0.25}
+		.st10 {fill:#5b9bd5;font-family:Calibri;font-size:1.5em;font-weight:bold}
+		.st11 {baseline-shift:-32.4951%;font-size:0.649902em}
+		.st12 {fill:#deebf6;stroke:#0070c0;stroke-width:1}
+		.st13 {fill:#5b9bd5;font-family:Calibri;font-size:1.5em}
+		.st14 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-36" class="st7" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(93.0294,-158.5)">
+			<title>Rectangle</title>
+			<desc>All Keys</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="216" cy="192.739" width="432" height="27"/>
+			<g id="shadow2-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="179.239" width="432" height="27" class="st2"/>
+			</g>
+			<rect x="0" y="179.239" width="432" height="27" class="st3"/>
+			<text x="187.88" y="198.14" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>All Keys</text>		</g>
+		<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(21.0294,-77.5)">
+			<title>Rectangle.3</title>
+			<desc>Group 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="188.239" width="108" height="36"/>
+			<g id="shadow3-8" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="170.239" width="108" height="36" class="st2"/>
+			</g>
+			<rect x="0" y="170.239" width="108" height="36" class="st3"/>
+			<text x="30.97" y="192.44" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group 1</text>		</g>
+		<g id="shape4-13" v:mID="4" v:groupContext="shape" transform="translate(156.029,-77.5)">
+			<title>Rectangle.4</title>
+			<desc>Group 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="188.239" width="108" height="36"/>
+			<g id="shadow4-14" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="170.239" width="108" height="36" class="st2"/>
+			</g>
+			<rect x="0" y="170.239" width="108" height="36" class="st3"/>
+			<text x="30.97" y="192.44" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group 2</text>		</g>
+		<g id="shape5-19" v:mID="5" v:groupContext="shape" transform="translate(291.029,-77.5)">
+			<title>Rectangle.5</title>
+			<desc>Group 3</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="188.239" width="108" height="36"/>
+			<g id="shadow5-20" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="170.239" width="108" height="36" class="st2"/>
+			</g>
+			<rect x="0" y="170.239" width="108" height="36" class="st3"/>
+			<text x="30.97" y="192.44" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group 3</text>		</g>
+		<g id="shape6-25" v:mID="6" v:groupContext="shape" transform="translate(471.029,-77.5)">
+			<title>Rectangle.6</title>
+			<desc>Group X</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="188.239" width="108" height="36"/>
+			<g id="shadow6-26" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="170.239" width="108" height="36" class="st2"/>
+			</g>
+			<rect x="0" y="170.239" width="108" height="36" class="st3"/>
+			<text x="30.88" y="192.44" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group X</text>		</g>
+		<g id="shape7-31" v:mID="7" v:groupContext="shape" transform="translate(359.05,247.819) rotate(165.964)">
+			<title>Sheet.7</title>
+			<path d="M0 206.24 L178.5 206.24" class="st6"/>
+		</g>
+		<g id="shape8-37" v:mID="8" v:groupContext="shape" transform="translate(428.903,215.562) rotate(144.462)">
+			<title>Sheet.8</title>
+			<path d="M0 206.24 L70.39 206.24" class="st6"/>
+		</g>
+		<g id="shape9-42" v:mID="9" v:groupContext="shape" transform="translate(470.075,-81.0976) rotate(51.3402)">
+			<title>Sheet.9</title>
+			<path d="M0 206.24 L50.59 206.24" class="st6"/>
+		</g>
+		<g id="shape10-47" v:mID="10" v:groupContext="shape" transform="translate(364.228,-150.976) rotate(15.5241)">
+			<title>Sheet.10</title>
+			<path d="M0 206.24 L161.1 206.24" class="st6"/>
+		</g>
+		<g id="shape11-52" v:mID="11" v:groupContext="shape" transform="translate(408.029,-95.5)">
+			<title>Sheet.11</title>
+			<path d="M0 206.24 L45 206.24" class="st8"/>
+		</g>
+		<g id="shape12-55" v:mID="12" v:groupContext="shape" transform="translate(48.0294,-50.5)">
+			<title>Sheet.12</title>
+			<desc>H7</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="192.739" width="45" height="27"/>
+			<rect x="0" y="179.239" width="45" height="27" class="st9"/>
+			<text x="13.86" y="198.14" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan
+						dy="-0.284em" class="st11" v:baseFontSize="18">7</tspan></text>		</g>
+		<g id="shape13-59" v:mID="13" v:groupContext="shape" transform="translate(192.029,-50.5)">
+			<title>Sheet.13</title>
+			<desc>H267</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="192.739" width="45" height="27"/>
+			<rect x="0" y="179.239" width="45" height="27" class="st9"/>
+			<text x="7.93" y="198.14" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan dy="-0.284em"
+						class="st11" v:baseFontSize="18">267</tspan></text>		</g>
+		<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(318.029,-50.5)">
+			<title>Sheet.14</title>
+			<desc>H46</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="192.739" width="45" height="27"/>
+			<rect x="0" y="179.239" width="45" height="27" class="st9"/>
+			<text x="10.89" y="198.14" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan
+						dy="-0.284em" class="st11" v:baseFontSize="18">46</tspan></text>		</g>
+		<g id="shape15-67" v:mID="15" v:groupContext="shape" transform="translate(502.529,-50.5)">
+			<title>Sheet.15</title>
+			<desc>H132</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="22.5" cy="192.739" width="45" height="27"/>
+			<rect x="0" y="179.239" width="45" height="27" class="st9"/>
+			<text x="7.93" y="198.14" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>H<tspan dy="-0.284em"
+						class="st11" v:baseFontSize="18">132</tspan></text>		</g>
+		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(111.029,-19)">
+			<title>Sheet.16</title>
+			<desc>Store hash function index for each group of keys</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="189" cy="192.739" width="378" height="27"/>
+			<rect x="0" y="179.239" width="378" height="27" class="st12"/>
+			<text x="12.27" y="198.14" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Store hash function index for each group of keys</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i6.svg b/doc/guides/prog_guide/img/efd_i6.svg
new file mode 100644
index 0000000..9aee30b
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i6.svg
@@ -0,0 +1,1254 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i6.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.2496in" height="5.89673in"
+		viewBox="0 0 593.971 424.565" xml:space="preserve" color-interpolation-filters="sRGB" class="st27">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+		.st5 {fill:#feffff;font-family:Calibri;font-size:0.75em}
+		.st6 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st7 {fill:none;stroke:#2e75b5;stroke-width:2.25}
+		.st8 {fill:#305497;stroke:#2e75b5;stroke-width:1}
+		.st9 {fill:#feffff;font-family:Calibri;font-size:0.833336em;font-weight:bold}
+		.st10 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2)}
+		.st11 {fill:#5b9bd5}
+		.st12 {stroke:#c7c8c8;stroke-width:0.25}
+		.st13 {fill:#acccea;stroke:#c7c8c8;stroke-width:0.25}
+		.st14 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st15 {fill:#ed7d31;stroke:#c7c8c8;stroke-width:0.25}
+		.st16 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+		.st17 {marker-end:url(#mrkr5-212);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st18 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st19 {fill:none;stroke:#2e75b5;stroke-width:1}
+		.st20 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+		.st21 {fill:none;stroke:none;stroke-width:0.25}
+		.st22 {font-size:1em}
+		.st23 {fill:#ffffff}
+		.st24 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st25 {marker-end:url(#mrkr5-444);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st26 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st27 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-212" class="st18" v:arrowType="5" v:arrowSize="2" v:setback="5.8" refX="-5.8" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+		</marker>
+		<marker id="mrkr5-444" class="st26" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(319.501,-335.688)">
+			<title>Rectangle.58</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow3-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape4-7" v:mID="4" v:groupContext="shape" transform="translate(353.251,-335.688)">
+			<title>Rectangle.59</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow4-8" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(400.501,-335.688)">
+			<title>Rectangle.60</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow5-14" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(434.251,-335.688)">
+			<title>Rectangle.61</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow6-20" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(481.501,-335.688)">
+			<title>Rectangle.62</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow7-26" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape8-30" v:mID="8" v:groupContext="shape" transform="translate(515.251,-335.688)">
+			<title>Rectangle.63</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow8-31" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape9-35" v:mID="9" v:groupContext="shape" transform="translate(319.501,-313.188)">
+			<title>Rectangle.64</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow9-36" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape10-40" v:mID="10" v:groupContext="shape" transform="translate(353.251,-313.188)">
+			<title>Rectangle.65</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow10-41" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape11-45" v:mID="11" v:groupContext="shape" transform="translate(400.501,-313.188)">
+			<title>Rectangle.66</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow11-46" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape12-50" v:mID="12" v:groupContext="shape" transform="translate(434.251,-313.188)">
+			<title>Rectangle.67</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow12-51" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape13-55" v:mID="13" v:groupContext="shape" transform="translate(481.501,-313.188)">
+			<title>Rectangle.68</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow13-56" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape14-60" v:mID="14" v:groupContext="shape" transform="translate(515.251,-313.188)">
+			<title>Rectangle.69</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow14-61" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(319.501,-277.188)">
+			<title>Rectangle.70</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow15-66" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(353.251,-277.188)">
+			<title>Rectangle.71</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow16-72" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape17-77" v:mID="17" v:groupContext="shape" transform="translate(400.501,-277.188)">
+			<title>Rectangle.72</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow17-78" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape18-83" v:mID="18" v:groupContext="shape" transform="translate(434.251,-277.188)">
+			<title>Rectangle.73</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow18-84" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape19-89" v:mID="19" v:groupContext="shape" transform="translate(481.501,-277.188)">
+			<title>Rectangle.74</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow19-90" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape20-95" v:mID="20" v:groupContext="shape" transform="translate(515.251,-277.188)">
+			<title>Rectangle.75</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow20-96" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape21-101" v:mID="21" v:groupContext="shape" transform="translate(319.501,-240.687)">
+			<title>Rectangle.76</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow21-102" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape22-106" v:mID="22" v:groupContext="shape" transform="translate(353.251,-240.687)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow22-107" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape23-111" v:mID="23" v:groupContext="shape" transform="translate(400.501,-240.687)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow23-112" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape24-116" v:mID="24" v:groupContext="shape" transform="translate(434.251,-240.687)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow24-117" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape25-121" v:mID="25" v:groupContext="shape" transform="translate(481.501,-240.687)">
+			<title>Rectangle.80</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow25-122" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape26-127" v:mID="26" v:groupContext="shape" transform="translate(515.251,-240.687)">
+			<title>Rectangle.81</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow26-128" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape27-133" v:mID="27" v:groupContext="shape" transform="translate(317.251,-231.687)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow27-134" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape28-138" v:mID="28" v:groupContext="shape" transform="translate(328.501,-362.688)">
+			<title>Sheet.28</title>
+			<desc>Local Table for N Specific Flows Serviced at Node 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.77" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node 1</text>		</g>
+		<g id="group34-141" transform="translate(66.0294,-165.569)" v:mID="34" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Device)"/>
+				<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Load balancer)"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Load balancer</title>
+			<g id="shape35-142" v:mID="35" v:groupContext="shape" transform="translate(0,-7.33146)">
+				<title>Sheet.35</title>
+				<g id="shadow35-143" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st10"/>
+					<path d="M0 377.86 L72 377.86" class="st6"/>
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st6"/>
+				</g>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st11"/>
+				<path d="M0 377.86 L72 377.86" class="st12"/>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st12"/>
+			</g>
+			<g id="shape36-152" v:mID="36" v:groupContext="shape" transform="translate(8.03054,-12.9324)">
+				<title>Sheet.36</title>
+				<g id="shadow36-153" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97
+								 413.34 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83
+								 L51.34 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37
+								 L38.13 400.48 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16
+								 L46.49 392.01 ZM27.71 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42
+								 27.71 415.42 C32.75 415.42 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71
+								 400.04 C31.15 400.04 33.96 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54
+								 21.46 409.74 21.46 406.29 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56
+								 L11.6 407.56 L8.62 410.51 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z"
+							class="st2"/>
+				</g>
+				<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97 413.34
+							 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83 L51.34
+							 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37 L38.13 400.48
+							 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16 L46.49 392.01 ZM27.71
+							 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42 27.71 415.42 C32.75 415.42
+							 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71 400.04 C31.15 400.04 33.96
+							 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54 21.46 409.74 21.46 406.29
+							 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56 L11.6 407.56 L8.62 410.51
+							 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z" class="st13"/>
+			</g>
+		</g>
+		<g id="shape37-157" v:mID="37" v:groupContext="shape" transform="translate(21.0294,-45.4375)">
+			<title>Rectangle</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow37-158" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="336.433" width="135" height="88.1315" class="st2"/>
+			</g>
+			<rect x="0" y="336.433" width="135" height="88.1315" class="st3"/>
+		</g>
+		<g id="shape38-162" v:mID="38" v:groupContext="shape" transform="translate(34.693,-126.438)">
+			<title>Sheet.38</title>
+			<desc>EFD Table</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="49.3364" cy="415.565" width="98.68" height="18"/>
+			<rect x="0" y="406.565" width="98.6728" height="18" class="st8"/>
+			<text x="24.87" y="419.17" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EFD Table</text>		</g>
+		<g id="shape39-165" v:mID="39" v:groupContext="shape" transform="translate(30.0294,-99.4375)">
+			<title>Rectangle.39</title>
+			<desc>Group_id</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow39-166" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="7.87" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group_id</text>		</g>
+		<g id="shape40-171" v:mID="40" v:groupContext="shape" transform="translate(93.193,-99.4375)">
+			<title>Rectangle.40</title>
+			<desc>Hash index</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow40-172" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="4.64" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash index</text>		</g>
+		<g id="shape41-177" v:mID="41" v:groupContext="shape" transform="translate(30.193,-82.4275)">
+			<title>Rectangle.41</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow41-178" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape42-182" v:mID="42" v:groupContext="shape" transform="translate(30.193,-66.8125)">
+			<title>Rectangle.42</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow42-183" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape43-187" v:mID="43" v:groupContext="shape" transform="translate(30.1112,-52.1875)">
+			<title>Rectangle.43</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow43-188" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape44-192" v:mID="44" v:groupContext="shape" transform="translate(93.0294,-81.4375)">
+			<title>Rectangle.44</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow44-193" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape45-197" v:mID="45" v:groupContext="shape" transform="translate(93.193,-66.8125)">
+			<title>Rectangle.45</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow45-198" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape46-202" v:mID="46" v:groupContext="shape" transform="translate(93.193,-52.1875)">
+			<title>Rectangle.46</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow46-203" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape47-207" v:mID="47" v:groupContext="shape" transform="translate(374.924,544.022) rotate(135)">
+			<title>Sheet.47</title>
+			<path d="M-0 417.75 A40.674 18.0151 -156.2 0 0 40.24 422.15 L40.49 421.89" class="st17"/>
+		</g>
+		<g id="shape48-213" v:mID="48" v:groupContext="shape" transform="translate(21.0294,-19)">
+			<title>Sheet.48</title>
+			<desc>Supports X*N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="19.05" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports X*N Flows</text>		</g>
+		<g id="shape49-216" v:mID="49" v:groupContext="shape" transform="translate(48.0294,-229.938)">
+			<title>Sheet.49</title>
+			<desc>Frontend Server or Load Balancer</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="400.94" width="108" height="47.25"/>
+			<rect x="0" y="377.315" width="108" height="47.25" class="st21"/>
+			<text x="14.56" y="397.34" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Frontend Server<v:newlineChar/><tspan
+						x="13.16" dy="1.2em" class="st22">or Load Balancer </tspan> </text>		</g>
+		<g id="group51-220" transform="translate(223.876,-310.938)" v:mID="51" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server</title>
+			<g id="shape52-221" v:mID="52" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.52</title>
+				<g id="shadow52-222" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape53-226" v:mID="53" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.53</title>
+				<g id="shadow53-227" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape54-231" v:mID="54" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.54</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow54-232" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape59-239" v:mID="59" v:groupContext="shape" transform="translate(277.876,-373.938)">
+			<title>Sheet.59</title>
+			<path d="M-0 424.56 A111.108 53.2538 42.31 0 1 93.83 421.21 L94.14 421.41" class="st17"/>
+		</g>
+		<g id="shape60-244" v:mID="60" v:groupContext="shape" transform="translate(205.876,-283.938)">
+			<title>Sheet.60</title>
+			<desc>Backend Server 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 1</text>		</g>
+		<g id="group61-247" transform="translate(223.876,-207.438)" v:mID="61" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.61</title>
+			<g id="shape62-248" v:mID="62" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.62</title>
+				<g id="shadow62-249" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape63-253" v:mID="63" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.63</title>
+				<g id="shadow63-254" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape64-258" v:mID="64" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.64</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow64-259" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape65-266" v:mID="65" v:groupContext="shape" transform="translate(205.876,-180.437)">
+			<title>Sheet.65</title>
+			<desc>Backend Server 2</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 2</text>		</g>
+		<g id="group66-269" transform="translate(219.029,-58.9375)" v:mID="66" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.66</title>
+			<g id="shape67-270" v:mID="67" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.67</title>
+				<g id="shadow67-271" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape68-275" v:mID="68" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.68</title>
+				<g id="shadow68-276" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape69-280" v:mID="69" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.69</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow69-281" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape70-288" v:mID="70" v:groupContext="shape" transform="translate(201.029,-26.056)">
+			<title>Sheet.70</title>
+			<desc>Backend Server X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.86" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server X</text>		</g>
+		<g id="shape71-291" v:mID="71" v:groupContext="shape" transform="translate(684.44,239.627) rotate(90)">
+			<title>Sheet.71</title>
+			<path d="M0 424.56 L45 424.56" class="st24"/>
+		</g>
+		<g id="shape72-294" v:mID="72" v:groupContext="shape" transform="translate(6.85967,-22.443) rotate(-38.1076)">
+			<title>Sheet.72</title>
+			<path d="M-0 424.56 A96.1331 44.4001 55.03 0 1 68.24 420.56 L68.51 420.79" class="st17"/>
+		</g>
+		<g id="shape73-299" v:mID="73" v:groupContext="shape" transform="translate(328.501,-135.937)">
+			<title>Rectangle.73</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow73-300" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape74-305" v:mID="74" v:groupContext="shape" transform="translate(362.251,-135.937)">
+			<title>Rectangle.74</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow74-306" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape75-311" v:mID="75" v:groupContext="shape" transform="translate(409.501,-135.937)">
+			<title>Rectangle.75</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow75-312" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape76-317" v:mID="76" v:groupContext="shape" transform="translate(443.251,-135.937)">
+			<title>Rectangle.76</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow76-318" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape77-323" v:mID="77" v:groupContext="shape" transform="translate(490.501,-135.937)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow77-324" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape78-328" v:mID="78" v:groupContext="shape" transform="translate(524.251,-135.937)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow78-329" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape79-333" v:mID="79" v:groupContext="shape" transform="translate(328.501,-113.437)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow79-334" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape80-338" v:mID="80" v:groupContext="shape" transform="translate(362.251,-113.437)">
+			<title>Rectangle.80</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow80-339" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape81-343" v:mID="81" v:groupContext="shape" transform="translate(409.501,-113.437)">
+			<title>Rectangle.81</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow81-344" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape82-348" v:mID="82" v:groupContext="shape" transform="translate(443.251,-113.437)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow82-349" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape83-353" v:mID="83" v:groupContext="shape" transform="translate(490.501,-113.437)">
+			<title>Rectangle.83</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow83-354" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape84-358" v:mID="84" v:groupContext="shape" transform="translate(524.251,-113.437)">
+			<title>Rectangle.84</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow84-359" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape85-363" v:mID="85" v:groupContext="shape" transform="translate(328.501,-77.4375)">
+			<title>Rectangle.85</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow85-364" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape86-369" v:mID="86" v:groupContext="shape" transform="translate(362.251,-77.4375)">
+			<title>Rectangle.86</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow86-370" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape87-375" v:mID="87" v:groupContext="shape" transform="translate(409.501,-77.4375)">
+			<title>Rectangle.87</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow87-376" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape88-381" v:mID="88" v:groupContext="shape" transform="translate(443.251,-77.4375)">
+			<title>Rectangle.88</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow88-382" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape89-387" v:mID="89" v:groupContext="shape" transform="translate(490.501,-77.4375)">
+			<title>Rectangle.89</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow89-388" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape90-393" v:mID="90" v:groupContext="shape" transform="translate(524.251,-77.4375)">
+			<title>Rectangle.90</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow90-394" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape91-399" v:mID="91" v:groupContext="shape" transform="translate(328.501,-40.9375)">
+			<title>Rectangle.91</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow91-400" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape92-404" v:mID="92" v:groupContext="shape" transform="translate(362.251,-40.9375)">
+			<title>Rectangle.92</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow92-405" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape93-409" v:mID="93" v:groupContext="shape" transform="translate(409.501,-40.9375)">
+			<title>Rectangle.93</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow93-410" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape94-414" v:mID="94" v:groupContext="shape" transform="translate(443.251,-40.9375)">
+			<title>Rectangle.94</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow94-415" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape95-419" v:mID="95" v:groupContext="shape" transform="translate(490.501,-40.9375)">
+			<title>Rectangle.95</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow95-420" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape96-425" v:mID="96" v:groupContext="shape" transform="translate(524.251,-40.9375)">
+			<title>Rectangle.96</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow96-426" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape97-431" v:mID="97" v:groupContext="shape" transform="translate(326.251,-31.9375)">
+			<title>Rectangle.97</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow97-432" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape98-436" v:mID="98" v:groupContext="shape" transform="translate(337.501,-162.938)">
+			<title>Sheet.98</title>
+			<desc>Local Table for N Specific Flows Serviced at Node X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.55" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node X</text>		</g>
+		<g id="shape99-439" v:mID="99" v:groupContext="shape" transform="translate(-204.342,-29.4449) rotate(-53.7462)">
+			<title>Sheet.99</title>
+			<path d="M0 424.56 L160.37 424.56" class="st25"/>
+		</g>
+		<g id="shape100-445" v:mID="100" v:groupContext="shape" transform="translate(-37.6568,-164.882) rotate(-24.444)">
+			<title>Sheet.100</title>
+			<path d="M0 424.56 L101.71 424.56" class="st25"/>
+		</g>
+		<g id="shape101-450" v:mID="101" v:groupContext="shape" transform="translate(464.049,-50.8578) rotate(50.099)">
+			<title>Sheet.101</title>
+			<path d="M0 424.56 L139.8 424.56" class="st25"/>
+		</g>
+		<g id="shape102-455" v:mID="102" v:groupContext="shape" transform="translate(372.376,-207.438)">
+			<title>Sheet.102</title>
+			<desc>Supports N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="25.15" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports N Flows</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i7.svg b/doc/guides/prog_guide/img/efd_i7.svg
new file mode 100644
index 0000000..98f8000
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i7.svg
@@ -0,0 +1,790 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i8.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="10.6168in" height="4.81965in"
+		viewBox="0 0 764.409 347.015" xml:space="preserve" color-interpolation-filters="sRGB" class="st27">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st2 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st3 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st4 {fill:#000000;font-family:Intel Clear;font-size:0.998566em}
+		.st5 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st6 {stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st7 {stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st8 {stroke:#ca8f02;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st9 {stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st10 {fill:#c00000;font-family:Intel Clear;font-size:0.828804em;font-weight:bold}
+		.st11 {fill:#7f6d00;font-family:Intel Clear;font-size:0.828804em;font-weight:bold}
+		.st12 {fill:#00b050;stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0149927}
+		.st13 {fill:#004280;stroke:#004280;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0149927}
+		.st14 {fill:#00b050;stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st15 {fill:#ca8f02;stroke:#ca8f02;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0299855}
+		.st16 {fill:#004280;font-family:Intel Clear;font-size:0.828804em}
+		.st17 {fill:#ffffff;font-family:Intel Clear;font-size:0.998566em}
+		.st18 {fill:#ffffff;font-family:Intel Clear;font-size:1.49785em}
+		.st19 {visibility:visible}
+		.st20 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st21 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st22 {fill:#feffff;font-family:Symbol;font-size:1.16666em}
+		.st23 {font-size:1em}
+		.st24 {font-family:Calibri;font-size:1em}
+		.st25 {fill:none;stroke:none;stroke-width:0.25}
+		.st26 {fill:#ffffff;font-family:Calibri;font-size:1.00001em}
+		.st27 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(27.7836,-307.505)">
+			<title>Sheet.3</title>
+			<path d="M0 329.94 C-0 328.06 1.54 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.06 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.54 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape4-3" v:mID="4" v:groupContext="shape" transform="translate(27.7836,-307.505)">
+			<title>Sheet.4</title>
+			<path d="M0 329.94 C-0 328.06 1.54 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.06 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.54 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape5-5" v:mID="5" v:groupContext="shape" transform="translate(50.1544,-309.121)">
+			<title>Sheet.5</title>
+			<desc>Key1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key1</text>		</g>
+		<g id="shape6-9" v:mID="6" v:groupContext="shape" transform="translate(43.6909,-286.954)">
+			<title>Sheet.6</title>
+			<path d="M0 336.65 L9.81 336.65 L9.81 326.28 L29.44 326.28 L29.44 336.65 L39.26 336.65 L19.63 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape7-11" v:mID="7" v:groupContext="shape" transform="translate(27.7836,-266.044)">
+			<title>Sheet.7</title>
+			<path d="M0 330.04 C0 328.16 1.52 326.64 3.41 326.64 L68.51 326.64 C70.4 326.64 71.91 328.16 71.91 330.04 L71.91 343.62
+						 C71.91 345.49 70.4 347.02 68.51 347.02 L3.41 347.02 C1.52 347.02 0 345.49 0 343.62 L0 330.04 Z"
+					class="st1"/>
+		</g>
+		<g id="shape8-13" v:mID="8" v:groupContext="shape" transform="translate(27.7836,-266.044)">
+			<title>Sheet.8</title>
+			<path d="M0 330.04 C0 328.16 1.52 326.64 3.41 326.64 L68.51 326.64 C70.4 326.64 71.91 328.16 71.91 330.04 L71.91 343.62
+						 C71.91 345.49 70.4 347.02 68.51 347.02 L3.41 347.02 C1.52 347.02 0 345.49 0 343.62 L0 330.04 Z"
+					class="st2"/>
+		</g>
+		<g id="shape9-15" v:mID="9" v:groupContext="shape" transform="translate(50.7572,-267.602)">
+			<title>Sheet.9</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape10-19" v:mID="10" v:groupContext="shape" transform="translate(19.0195,-225.183)">
+			<title>Sheet.10</title>
+			<path d="M0 330.74 C0 328.94 1.46 327.48 3.26 327.48 L87.15 327.48 C88.95 327.48 90.4 328.94 90.4 330.74 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.26 347.02 C1.46 347.02 0 345.56 0 343.76 L0 330.74 Z"
+					class="st1"/>
+		</g>
+		<g id="shape11-21" v:mID="11" v:groupContext="shape" transform="translate(19.0195,-225.183)">
+			<title>Sheet.11</title>
+			<path d="M0 330.74 C0 328.94 1.46 327.48 3.26 327.48 L87.15 327.48 C88.95 327.48 90.4 328.94 90.4 330.74 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.26 347.02 C1.46 347.02 0 345.56 0 343.76 L0 330.74 Z"
+					class="st2"/>
+		</g>
+		<g id="shape12-23" v:mID="12" v:groupContext="shape" transform="translate(28.0373,-226.287)">
+			<title>Sheet.12</title>
+			<desc>0x0102ABCD</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.3615" cy="339.824" width="86.73" height="14.3829"/>
+			<path d="M86.72 332.63 L0 332.63 L0 347.02 L86.72 347.02 L86.72 332.63" class="st3"/>
+			<text x="7.12" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102ABCD</text>		</g>
+		<g id="shape13-27" v:mID="13" v:groupContext="shape" transform="translate(43.6909,-244.775)">
+			<title>Sheet.13</title>
+			<path d="M0 336.71 L9.81 336.71 L9.81 326.4 L29.44 326.4 L29.44 336.71 L39.26 336.71 L19.63 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape14-29" v:mID="14" v:groupContext="shape" transform="translate(40.7496,-210.444)">
+			<title>Sheet.14</title>
+			<path d="M26.29 334.91 C26.29 338.26 25.84 340.96 25.29 340.96 L14.16 340.96 C13.6 340.96 13.15 343.67 13.15 347.02 C13.15
+						 343.67 12.7 340.96 12.14 340.96 L1.01 340.96 C0.46 340.96 0 338.26 0 334.91" class="st6"/>
+		</g>
+		<g id="shape15-32" v:mID="15" v:groupContext="shape" transform="translate(125.629,-307.625)">
+			<title>Sheet.15</title>
+			<path d="M0 330.04 C0 328.16 1.52 326.64 3.41 326.64 L68.63 326.64 C70.51 326.64 72.03 328.16 72.03 330.04 L72.03 343.62
+						 C72.03 345.49 70.51 347.02 68.63 347.02 L3.41 347.02 C1.52 347.02 0 345.49 0 343.62 L0 330.04 Z"
+					class="st1"/>
+		</g>
+		<g id="shape16-34" v:mID="16" v:groupContext="shape" transform="translate(125.629,-307.625)">
+			<title>Sheet.16</title>
+			<path d="M0 330.04 C0 328.16 1.52 326.64 3.41 326.64 L68.63 326.64 C70.51 326.64 72.03 328.16 72.03 330.04 L72.03 343.62
+						 C72.03 345.49 70.51 347.02 68.63 347.02 L3.41 347.02 C1.52 347.02 0 345.49 0 343.62 L0 330.04 Z"
+					class="st2"/>
+		</g>
+		<g id="shape17-36" v:mID="17" v:groupContext="shape" transform="translate(148.034,-309.155)">
+			<title>Sheet.17</title>
+			<desc>Key2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key2</text>		</g>
+		<g id="shape18-40" v:mID="18" v:groupContext="shape" transform="translate(141.536,-286.954)">
+			<title>Sheet.18</title>
+			<path d="M0 336.65 L9.81 336.65 L9.81 326.28 L29.44 326.28 L29.44 336.65 L39.26 336.65 L19.63 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape19-42" v:mID="19" v:groupContext="shape" transform="translate(125.629,-266.044)">
+			<title>Sheet.19</title>
+			<path d="M0 329.94 C0 328.06 1.54 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.06 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.54 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st1"/>
+		</g>
+		<g id="shape20-44" v:mID="20" v:groupContext="shape" transform="translate(125.629,-266.044)">
+			<title>Sheet.20</title>
+			<path d="M0 329.94 C0 328.06 1.54 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.06 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.54 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st2"/>
+		</g>
+		<g id="shape21-46" v:mID="21" v:groupContext="shape" transform="translate(148.636,-267.636)">
+			<title>Sheet.21</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape22-50" v:mID="22" v:groupContext="shape" transform="translate(116.865,-225.183)">
+			<title>Sheet.22</title>
+			<path d="M0 330.74 C0 328.94 1.46 327.48 3.26 327.48 L87.15 327.48 C88.95 327.48 90.4 328.94 90.4 330.74 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.26 347.02 C1.46 347.02 0 345.56 0 343.76 L0 330.74 Z"
+					class="st1"/>
+		</g>
+		<g id="shape23-52" v:mID="23" v:groupContext="shape" transform="translate(116.865,-225.183)">
+			<title>Sheet.23</title>
+			<path d="M0 330.74 C0 328.94 1.46 327.48 3.26 327.48 L87.15 327.48 C88.95 327.48 90.4 328.94 90.4 330.74 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.26 347.02 C1.46 347.02 0 345.56 0 343.76 L0 330.74 Z"
+					class="st2"/>
+		</g>
+		<g id="shape24-54" v:mID="24" v:groupContext="shape" transform="translate(125.917,-226.322)">
+			<title>Sheet.24</title>
+			<desc>0x0103CDAB</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.3615" cy="339.824" width="86.73" height="14.3829"/>
+			<path d="M86.72 332.63 L0 332.63 L0 347.02 L86.72 347.02 L86.72 332.63" class="st3"/>
+			<text x="7.12" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0103CDAB</text>		</g>
+		<g id="shape25-58" v:mID="25" v:groupContext="shape" transform="translate(141.536,-244.775)">
+			<title>Sheet.25</title>
+			<path d="M0 336.71 L9.81 336.71 L9.81 326.4 L29.44 326.4 L29.44 336.71 L39.26 336.71 L19.63 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape26-60" v:mID="26" v:groupContext="shape" transform="translate(138.595,-210.444)">
+			<title>Sheet.26</title>
+			<path d="M26.29 334.91 C26.29 338.26 25.84 340.96 25.29 340.96 L14.16 340.96 C13.6 340.96 13.15 343.67 13.15 347.02 C13.15
+						 343.67 12.7 340.96 12.14 340.96 L1.01 340.96 C0.46 340.96 0 338.26 0 334.91" class="st7"/>
+		</g>
+		<g id="shape27-63" v:mID="27" v:groupContext="shape" transform="translate(221.793,-307.625)">
+			<title>Sheet.27</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.64 326.64 C70.52 326.64 72.03 328.17 72.03 330.04 L72.03 343.63
+						 C72.03 345.5 70.52 347.02 68.64 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st1"/>
+		</g>
+		<g id="shape28-65" v:mID="28" v:groupContext="shape" transform="translate(221.793,-307.625)">
+			<title>Sheet.28</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.64 326.64 C70.52 326.64 72.03 328.17 72.03 330.04 L72.03 343.63
+						 C72.03 345.5 70.52 347.02 68.64 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st2"/>
+		</g>
+		<g id="shape29-67" v:mID="29" v:groupContext="shape" transform="translate(244.237,-309.155)">
+			<title>Sheet.29</title>
+			<desc>Key3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key3</text>		</g>
+		<g id="shape30-71" v:mID="30" v:groupContext="shape" transform="translate(237.701,-286.954)">
+			<title>Sheet.30</title>
+			<path d="M0 336.65 L9.84 336.65 L9.84 326.28 L29.53 326.28 L29.53 336.65 L39.38 336.65 L19.69 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape31-73" v:mID="31" v:groupContext="shape" transform="translate(221.793,-266.044)">
+			<title>Sheet.31</title>
+			<path d="M0 329.94 C-0 328.07 1.55 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.07 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st1"/>
+		</g>
+		<g id="shape32-75" v:mID="32" v:groupContext="shape" transform="translate(221.793,-266.044)">
+			<title>Sheet.32</title>
+			<path d="M0 329.94 C-0 328.07 1.55 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.07 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st2"/>
+		</g>
+		<g id="shape33-77" v:mID="33" v:groupContext="shape" transform="translate(244.84,-267.636)">
+			<title>Sheet.33</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape34-81" v:mID="34" v:groupContext="shape" transform="translate(213.029,-225.183)">
+			<title>Sheet.34</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.27 327.48 C89.07 327.48 90.52 328.95 90.52 330.75 L90.52 343.76
+						 C90.52 345.56 89.07 347.02 87.27 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st1"/>
+		</g>
+		<g id="shape35-83" v:mID="35" v:groupContext="shape" transform="translate(213.029,-225.183)">
+			<title>Sheet.35</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.27 327.48 C89.07 327.48 90.52 328.95 90.52 330.75 L90.52 343.76
+						 C90.52 345.56 89.07 347.02 87.27 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st2"/>
+		</g>
+		<g id="shape36-85" v:mID="36" v:groupContext="shape" transform="translate(222.002,-226.322)">
+			<title>Sheet.36</title>
+			<desc>0x0102BAAD</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.4787" cy="339.824" width="86.96" height="14.3829"/>
+			<path d="M86.96 332.63 L0 332.63 L0 347.02 L86.96 347.02 L86.96 332.63" class="st3"/>
+			<text x="7.13" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102BAAD</text>		</g>
+		<g id="shape37-89" v:mID="37" v:groupContext="shape" transform="translate(237.701,-244.775)">
+			<title>Sheet.37</title>
+			<path d="M0 336.71 L9.84 336.71 L9.84 326.4 L29.53 326.4 L29.53 336.71 L39.38 336.71 L19.69 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape38-91" v:mID="38" v:groupContext="shape" transform="translate(234.759,-210.444)">
+			<title>Sheet.38</title>
+			<path d="M26.41 334.91 C26.41 338.26 25.96 340.96 25.41 340.96 L14.22 340.96 C13.66 340.96 13.21 343.67 13.21 347.02
+						 C13.21 343.67 12.76 340.96 12.2 340.96 L1.01 340.96 C0.46 340.96 0 338.26 0 334.91" class="st6"/>
+		</g>
+		<g id="shape39-94" v:mID="39" v:groupContext="shape" transform="translate(319.759,-307.625)">
+			<title>Sheet.39</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.52 326.64 C70.4 326.64 71.91 328.17 71.91 330.04 L71.91 343.63
+						 C71.91 345.5 70.4 347.02 68.52 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st1"/>
+		</g>
+		<g id="shape40-96" v:mID="40" v:groupContext="shape" transform="translate(319.759,-307.625)">
+			<title>Sheet.40</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.52 326.64 C70.4 326.64 71.91 328.17 71.91 330.04 L71.91 343.63
+						 C71.91 345.5 70.4 347.02 68.52 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st2"/>
+		</g>
+		<g id="shape41-98" v:mID="41" v:groupContext="shape" transform="translate(342.125,-309.155)">
+			<title>Sheet.41</title>
+			<desc>Key4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key4</text>		</g>
+		<g id="shape42-102" v:mID="42" v:groupContext="shape" transform="translate(335.666,-286.954)">
+			<title>Sheet.42</title>
+			<path d="M0 336.65 L9.81 336.65 L9.81 326.28 L29.44 326.28 L29.44 336.65 L39.26 336.65 L19.63 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape43-104" v:mID="43" v:groupContext="shape" transform="translate(319.759,-266.044)">
+			<title>Sheet.43</title>
+			<path d="M0 329.94 C0 328.07 1.55 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.07 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape44-106" v:mID="44" v:groupContext="shape" transform="translate(319.759,-266.044)">
+			<title>Sheet.44</title>
+			<path d="M0 329.94 C0 328.07 1.55 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.07 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape45-108" v:mID="45" v:groupContext="shape" transform="translate(342.728,-267.636)">
+			<title>Sheet.45</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape46-112" v:mID="46" v:groupContext="shape" transform="translate(310.995,-225.183)">
+			<title>Sheet.46</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.15 327.48 C88.95 327.48 90.4 328.95 90.4 330.75 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st1"/>
+		</g>
+		<g id="shape47-114" v:mID="47" v:groupContext="shape" transform="translate(310.995,-225.183)">
+			<title>Sheet.47</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.15 327.48 C88.95 327.48 90.4 328.95 90.4 330.75 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st2"/>
+		</g>
+		<g id="shape48-116" v:mID="48" v:groupContext="shape" transform="translate(321.689,-226.322)">
+			<title>Sheet.48</title>
+			<desc>0x0104BEEF</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="41.4183" cy="339.824" width="82.84" height="14.3829"/>
+			<path d="M82.84 332.63 L0 332.63 L0 347.02 L82.84 347.02 L82.84 332.63" class="st3"/>
+			<text x="6.87" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0104BEEF</text>		</g>
+		<g id="shape49-120" v:mID="49" v:groupContext="shape" transform="translate(335.666,-244.775)">
+			<title>Sheet.49</title>
+			<path d="M0 336.71 L9.81 336.71 L9.81 326.4 L29.44 326.4 L29.44 336.71 L39.26 336.71 L19.63 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape50-122" v:mID="50" v:groupContext="shape" transform="translate(332.725,-210.444)">
+			<title>Sheet.50</title>
+			<path d="M26.29 334.91 C26.29 338.27 25.84 340.96 25.29 340.96 L14.17 340.96 C13.61 340.96 13.15 343.67 13.15 347.02
+						 C13.15 343.67 12.7 340.96 12.14 340.96 L1.02 340.96 C0.47 340.96 0 338.27 0 334.91" class="st6"/>
+		</g>
+		<g id="shape51-125" v:mID="51" v:groupContext="shape" transform="translate(416.884,-307.625)">
+			<title>Sheet.51</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.52 326.64 C70.4 326.64 71.91 328.17 71.91 330.04 L71.91 343.63
+						 C71.91 345.5 70.4 347.02 68.52 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st1"/>
+		</g>
+		<g id="shape52-127" v:mID="52" v:groupContext="shape" transform="translate(416.884,-307.625)">
+			<title>Sheet.52</title>
+			<path d="M0 330.04 C0 328.17 1.53 326.64 3.41 326.64 L68.52 326.64 C70.4 326.64 71.91 328.17 71.91 330.04 L71.91 343.63
+						 C71.91 345.5 70.4 347.02 68.52 347.02 L3.41 347.02 C1.53 347.02 0 345.5 0 343.63 L0 330.04 Z" class="st2"/>
+		</g>
+		<g id="shape53-129" v:mID="53" v:groupContext="shape" transform="translate(439.255,-309.155)">
+			<title>Sheet.53</title>
+			<desc>Key5</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key5</text>		</g>
+		<g id="shape54-133" v:mID="54" v:groupContext="shape" transform="translate(432.791,-286.954)">
+			<title>Sheet.54</title>
+			<path d="M0 336.65 L9.81 336.65 L9.81 326.28 L29.44 326.28 L29.44 336.65 L39.26 336.65 L19.63 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape55-135" v:mID="55" v:groupContext="shape" transform="translate(416.884,-266.044)">
+			<title>Sheet.55</title>
+			<path d="M0 329.94 C0 328.07 1.55 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.07 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st1"/>
+		</g>
+		<g id="shape56-137" v:mID="56" v:groupContext="shape" transform="translate(416.884,-266.044)">
+			<title>Sheet.56</title>
+			<path d="M0 329.94 C0 328.07 1.55 326.52 3.42 326.52 L68.49 326.52 C70.38 326.52 71.91 328.07 71.91 329.94 L71.91 343.6
+						 C71.91 345.49 70.38 347.02 68.49 347.02 L3.42 347.02 C1.55 347.02 0 345.49 0 343.6 L0 329.94 Z"
+					class="st2"/>
+		</g>
+		<g id="shape57-139" v:mID="57" v:groupContext="shape" transform="translate(439.858,-267.636)">
+			<title>Sheet.57</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape58-143" v:mID="58" v:groupContext="shape" transform="translate(408.12,-225.183)">
+			<title>Sheet.58</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.15 327.48 C88.95 327.48 90.4 328.95 90.4 330.75 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st1"/>
+		</g>
+		<g id="shape59-145" v:mID="59" v:groupContext="shape" transform="translate(408.12,-225.183)">
+			<title>Sheet.59</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.15 327.48 C88.95 327.48 90.4 328.95 90.4 330.75 L90.4 343.76
+						 C90.4 345.56 88.95 347.02 87.15 347.02 L3.27 347.02 C1.47 347.02 0 345.56 0 343.76 L0 330.75 Z"
+					class="st2"/>
+		</g>
+		<g id="shape60-147" v:mID="60" v:groupContext="shape" transform="translate(416.778,-226.322)">
+			<title>Sheet.60</title>
+			<desc>0x0103DABD</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.7817" cy="339.824" width="87.57" height="14.3829"/>
+			<path d="M87.56 332.63 L0 332.63 L0 347.02 L87.56 347.02 L87.56 332.63" class="st3"/>
+			<text x="7.17" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0103DABD</text>		</g>
+		<g id="shape61-151" v:mID="61" v:groupContext="shape" transform="translate(432.791,-244.775)">
+			<title>Sheet.61</title>
+			<path d="M0 336.71 L9.81 336.71 L9.81 326.4 L29.44 326.4 L29.44 336.71 L39.26 336.71 L19.63 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape62-153" v:mID="62" v:groupContext="shape" transform="translate(429.85,-210.444)">
+			<title>Sheet.62</title>
+			<path d="M26.29 334.91 C26.29 338.27 25.84 340.96 25.29 340.96 L14.17 340.96 C13.61 340.96 13.15 343.67 13.15 347.02
+						 C13.15 343.67 12.7 340.96 12.14 340.96 L1.02 340.96 C0.47 340.96 0 338.27 0 334.91" class="st7"/>
+		</g>
+		<g id="shape63-156" v:mID="63" v:groupContext="shape" transform="translate(514.489,-307.625)">
+			<title>Sheet.63</title>
+			<path d="M0 330.06 C-0 328.17 1.53 326.64 3.42 326.64 L68.64 326.64 C70.53 326.64 72.03 328.17 72.03 330.06 L72.03 343.63
+						 C72.03 345.52 70.53 347.02 68.64 347.02 L3.42 347.02 C1.53 347.02 0 345.52 0 343.63 L0 330.06 Z"
+					class="st1"/>
+		</g>
+		<g id="shape64-158" v:mID="64" v:groupContext="shape" transform="translate(514.489,-307.625)">
+			<title>Sheet.64</title>
+			<path d="M0 330.06 C-0 328.17 1.53 326.64 3.42 326.64 L68.64 326.64 C70.53 326.64 72.03 328.17 72.03 330.06 L72.03 343.63
+						 C72.03 345.52 70.53 347.02 68.64 347.02 L3.42 347.02 C1.53 347.02 0 345.52 0 343.63 L0 330.06 Z"
+					class="st2"/>
+		</g>
+		<g id="shape65-160" v:mID="65" v:groupContext="shape" transform="translate(536.883,-309.19)">
+			<title>Sheet.65</title>
+			<desc>Key6</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key6</text>		</g>
+		<g id="shape66-164" v:mID="66" v:groupContext="shape" transform="translate(530.396,-287.074)">
+			<title>Sheet.66</title>
+			<path d="M0 336.71 L9.81 336.71 L9.81 326.4 L29.44 326.4 L29.44 336.71 L39.26 336.71 L19.63 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape67-166" v:mID="67" v:groupContext="shape" transform="translate(514.489,-266.044)">
+			<title>Sheet.67</title>
+			<path d="M0 329.94 C0 328.08 1.56 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.08 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.56 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st1"/>
+		</g>
+		<g id="shape68-168" v:mID="68" v:groupContext="shape" transform="translate(514.489,-266.044)">
+			<title>Sheet.68</title>
+			<path d="M0 329.94 C0 328.08 1.56 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.08 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.56 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st2"/>
+		</g>
+		<g id="shape69-170" v:mID="69" v:groupContext="shape" transform="translate(537.486,-267.671)">
+			<title>Sheet.69</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape70-174" v:mID="70" v:groupContext="shape" transform="translate(505.725,-225.183)">
+			<title>Sheet.70</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.16 327.48 C88.96 327.48 90.4 328.95 90.4 330.75 L90.4 343.78
+						 C90.4 345.58 88.96 347.02 87.16 347.02 L3.27 347.02 C1.47 347.02 0 345.58 0 343.78 L0 330.75 Z"
+					class="st1"/>
+		</g>
+		<g id="shape71-176" v:mID="71" v:groupContext="shape" transform="translate(505.725,-225.183)">
+			<title>Sheet.71</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.16 327.48 C88.96 327.48 90.4 328.95 90.4 330.75 L90.4 343.78
+						 C90.4 345.58 88.96 347.02 87.16 347.02 L3.27 347.02 C1.47 347.02 0 345.58 0 343.78 L0 330.75 Z"
+					class="st2"/>
+		</g>
+		<g id="shape72-178" v:mID="72" v:groupContext="shape" transform="translate(514.766,-226.356)">
+			<title>Sheet.72</title>
+			<desc>0x0102ADCB</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.3615" cy="339.824" width="86.73" height="14.3829"/>
+			<path d="M86.72 332.63 L0 332.63 L0 347.02 L86.72 347.02 L86.72 332.63" class="st3"/>
+			<text x="7.12" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102ADCB</text>		</g>
+		<g id="shape73-182" v:mID="73" v:groupContext="shape" transform="translate(530.396,-244.775)">
+			<title>Sheet.73</title>
+			<path d="M0 336.65 L9.81 336.65 L9.81 326.28 L29.44 326.28 L29.44 336.65 L39.26 336.65 L19.63 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape74-184" v:mID="74" v:groupContext="shape" transform="translate(527.455,-210.564)">
+			<title>Sheet.74</title>
+			<path d="M26.29 335.03 C26.29 338.36 25.87 341.02 25.3 341.02 L14.17 341.02 C13.6 341.02 13.15 343.72 13.15 347.02 C13.15
+						 343.72 12.73 341.02 12.16 341.02 L1.02 341.02 C0.45 341.02 0 338.36 0 335.03" class="st6"/>
+		</g>
+		<g id="shape75-187" v:mID="75" v:groupContext="shape" transform="translate(610.653,-307.505)">
+			<title>Sheet.75</title>
+			<path d="M0 329.94 C0 328.08 1.56 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.08 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.56 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st1"/>
+		</g>
+		<g id="shape76-189" v:mID="76" v:groupContext="shape" transform="translate(610.653,-307.505)">
+			<title>Sheet.76</title>
+			<path d="M0 329.94 C0 328.08 1.56 326.52 3.42 326.52 L68.61 326.52 C70.5 326.52 72.03 328.08 72.03 329.94 L72.03 343.6
+						 C72.03 345.49 70.5 347.02 68.61 347.02 L3.42 347.02 C1.56 347.02 0 345.49 0 343.6 L0 329.94 Z" class="st2"/>
+		</g>
+		<g id="shape77-191" v:mID="77" v:groupContext="shape" transform="translate(633.086,-309.121)">
+			<title>Sheet.77</title>
+			<desc>Key7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="17.3237" cy="339.824" width="34.65" height="14.3829"/>
+			<path d="M34.65 332.63 L0 332.63 L0 347.02 L34.65 347.02 L34.65 332.63" class="st3"/>
+			<text x="3.72" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key7</text>		</g>
+		<g id="shape78-195" v:mID="78" v:groupContext="shape" transform="translate(626.561,-286.954)">
+			<title>Sheet.78</title>
+			<path d="M0 336.65 L9.84 336.65 L9.84 326.28 L29.53 326.28 L29.53 336.65 L39.38 336.65 L19.69 347.02 L0 336.65 Z"
+					class="st5"/>
+		</g>
+		<g id="shape79-197" v:mID="79" v:groupContext="shape" transform="translate(610.653,-266.044)">
+			<title>Sheet.79</title>
+			<path d="M0 330.06 C-0 328.17 1.53 326.64 3.42 326.64 L68.64 326.64 C70.53 326.64 72.03 328.17 72.03 330.06 L72.03 343.63
+						 C72.03 345.52 70.53 347.02 68.64 347.02 L3.42 347.02 C1.53 347.02 0 345.52 0 343.63 L0 330.06 Z"
+					class="st1"/>
+		</g>
+		<g id="shape80-199" v:mID="80" v:groupContext="shape" transform="translate(610.653,-266.044)">
+			<title>Sheet.80</title>
+			<path d="M0 330.06 C-0 328.17 1.53 326.64 3.42 326.64 L68.64 326.64 C70.53 326.64 72.03 328.17 72.03 330.06 L72.03 343.63
+						 C72.03 345.52 70.53 347.02 68.64 347.02 L3.42 347.02 C1.53 347.02 0 345.52 0 343.63 L0 330.06 Z"
+					class="st2"/>
+		</g>
+		<g id="shape81-201" v:mID="81" v:groupContext="shape" transform="translate(633.689,-267.602)">
+			<title>Sheet.81</title>
+			<desc>hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="16.5866" cy="339.824" width="33.18" height="14.3829"/>
+			<path d="M33.17 332.63 L0 332.63 L0 347.02 L33.17 347.02 L33.17 332.63" class="st3"/>
+			<text x="3.63" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash</text>		</g>
+		<g id="shape82-205" v:mID="82" v:groupContext="shape" transform="translate(601.889,-225.183)">
+			<title>Sheet.82</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.28 327.48 C89.08 327.48 90.52 328.95 90.52 330.75 L90.52 343.78
+						 C90.52 345.58 89.08 347.02 87.28 347.02 L3.27 347.02 C1.47 347.02 0 345.58 0 343.78 L0 330.75 Z"
+					class="st1"/>
+		</g>
+		<g id="shape83-207" v:mID="83" v:groupContext="shape" transform="translate(601.889,-225.183)">
+			<title>Sheet.83</title>
+			<path d="M0 330.75 C0 328.95 1.47 327.48 3.27 327.48 L87.28 327.48 C89.08 327.48 90.52 328.95 90.52 330.75 L90.52 343.78
+						 C90.52 345.58 89.08 347.02 87.28 347.02 L3.27 347.02 C1.47 347.02 0 345.58 0 343.78 L0 330.75 Z"
+					class="st2"/>
+		</g>
+		<g id="shape84-209" v:mID="84" v:groupContext="shape" transform="translate(610.969,-226.287)">
+			<title>Sheet.84</title>
+			<desc>0x0104DBCA</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="43.3615" cy="339.824" width="86.73" height="14.3829"/>
+			<path d="M86.72 332.63 L0 332.63 L0 347.02 L86.72 347.02 L86.72 332.63" class="st3"/>
+			<text x="7.12" y="343.42" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0104DBCA</text>		</g>
+		<g id="shape85-213" v:mID="85" v:groupContext="shape" transform="translate(626.561,-244.775)">
+			<title>Sheet.85</title>
+			<path d="M0 336.71 L9.84 336.71 L9.84 326.4 L29.53 326.4 L29.53 336.71 L39.38 336.71 L19.69 347.02 L0 336.71 Z"
+					class="st5"/>
+		</g>
+		<g id="shape86-215" v:mID="86" v:groupContext="shape" transform="translate(623.619,-210.444)">
+			<title>Sheet.86</title>
+			<path d="M26.41 334.91 C26.41 338.27 25.96 340.96 25.42 340.96 L14.23 340.96 C13.69 340.96 13.21 343.69 13.21 347.02
+						 C13.21 343.69 12.76 340.96 12.22 340.96 L1.02 340.96 C0.48 340.96 0 338.27 0 334.91" class="st8"/>
+		</g>
+		<g id="shape87-218" v:mID="87" v:groupContext="shape" transform="translate(242.323,-81.6288)">
+			<title>Sheet.87</title>
+			<path d="M0 281.23 L0 347.02 L41.18 347.02 L41.18 281.23 L0 281.23 L0 281.23 Z" class="st1"/>
+		</g>
+		<g id="shape88-220" v:mID="88" v:groupContext="shape" transform="translate(247.009,-81.6288)">
+			<title>Sheet.88</title>
+			<path d="M0 281.23 L41.18 281.23 L41.18 347.02 L0 347.02 L0 281.23" class="st9"/>
+		</g>
+		<g id="shape89-223" v:mID="89" v:groupContext="shape" transform="translate(245.254,-132.398)">
+			<title>Sheet.89</title>
+			<desc>0x0102</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.3211" cy="341.046" width="42.65" height="11.9384"/>
+			<path d="M42.64 335.08 L0 335.08 L0 347.02 L42.64 347.02 L42.64 335.08" class="st3"/>
+			<text x="4" y="344.03" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0102</text>		</g>
+		<g id="shape90-227" v:mID="90" v:groupContext="shape" transform="translate(245.015,-82.7016)">
+			<title>Sheet.90</title>
+			<desc>4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.79425" cy="341.046" width="9.59" height="11.9384"/>
+			<path d="M9.59 335.08 L0 335.08 L0 347.02 L9.59 347.02 L9.59 335.08" class="st3"/>
+			<text x="1.84" y="344.03" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text>		</g>
+		<g id="shape91-231" v:mID="91" v:groupContext="shape" transform="translate(336.326,-81.6288)">
+			<title>Sheet.91</title>
+			<path d="M0 281.23 L0 347.02 L41.18 347.02 L41.18 281.23 L0 281.23 L0 281.23 Z" class="st1"/>
+		</g>
+		<g id="shape92-233" v:mID="92" v:groupContext="shape" transform="translate(339.598,-81.6288)">
+			<title>Sheet.92</title>
+			<path d="M0 281.23 L41.18 281.23 L41.18 347.02 L0 347.02 L0 281.23" class="st9"/>
+		</g>
+		<g id="shape93-236" v:mID="93" v:groupContext="shape" transform="translate(339.264,-132.398)">
+			<title>Sheet.93</title>
+			<desc>0x0103</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.3211" cy="341.046" width="42.65" height="11.9384"/>
+			<path d="M42.64 335.08 L0 335.08 L0 347.02 L42.64 347.02 L42.64 335.08" class="st3"/>
+			<text x="4" y="344.03" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0103</text>		</g>
+		<g id="shape94-240" v:mID="94" v:groupContext="shape" transform="translate(339.024,-82.7016)">
+			<title>Sheet.94</title>
+			<desc>2</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.79425" cy="341.046" width="9.59" height="11.9384"/>
+			<path d="M9.59 335.08 L0 335.08 L0 347.02 L9.59 347.02 L9.59 335.08" class="st3"/>
+			<text x="1.84" y="344.03" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text>		</g>
+		<g id="shape95-244" v:mID="95" v:groupContext="shape" transform="translate(438.598,-81.5089)">
+			<title>Sheet.95</title>
+			<path d="M0 281.23 L0 347.02 L41.18 347.02 L41.18 281.23 L0 281.23 L0 281.23 Z" class="st1"/>
+		</g>
+		<g id="shape96-246" v:mID="96" v:groupContext="shape" transform="translate(438.598,-81.5089)">
+			<title>Sheet.96</title>
+			<path d="M0 281.23 L41.18 281.23 L41.18 347.02 L0 347.02 L0 281.23" class="st9"/>
+		</g>
+		<g id="shape97-249" v:mID="97" v:groupContext="shape" transform="translate(437.81,-132.27)">
+			<title>Sheet.97</title>
+			<desc>0x0104</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="21.3211" cy="341.046" width="42.65" height="11.9384"/>
+			<path d="M42.64 335.08 L0 335.08 L0 347.02 L42.64 347.02 L42.64 335.08" class="st3"/>
+			<text x="4" y="344.03" class="st10" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>0x0104</text>		</g>
+		<g id="shape98-253" v:mID="98" v:groupContext="shape" transform="translate(437.57,-82.5735)">
+			<title>Sheet.98</title>
+			<desc>1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="4.79425" cy="341.046" width="9.59" height="11.9384"/>
+			<path d="M9.59 335.08 L0 335.08 L0 347.02 L9.59 347.02 L9.59 335.08" class="st3"/>
+			<text x="1.84" y="344.03" class="st11" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text>		</g>
+		<g id="shape99-257" v:mID="99" v:groupContext="shape" transform="translate(53.5505,-147.924)">
+			<title>Sheet.99</title>
+			<path d="M0.59 283.52 L206.27 343.39 L205.7 345.34 L0 285.48 L0.59 283.52 L0.59 283.52 ZM205.85 341.14 L210.88 345.79
+						 L204.14 347.02 L205.85 341.14 L205.85 341.14 Z" class="st12"/>
+		</g>
+		<g id="shape100-259" v:mID="100" v:groupContext="shape" transform="translate(151.516,-147.924)">
+			<title>Sheet.100</title>
+			<path d="M0.59 283.52 L202.41 343.41 L201.83 345.35 L0 285.48 L0.59 283.52 L0.59 283.52 ZM202.01 341.16 L207.01 345.83
+						 L200.27 347.02 L202.01 341.16 L202.01 341.16 Z" class="st13"/>
+		</g>
+		<g id="shape101-261" v:mID="101" v:groupContext="shape" transform="translate(246.975,-147.37)">
+			<title>Sheet.101</title>
+			<path d="M2 283.72 L15.77 341.83 L13.79 342.3 L0 284.18 L2 283.72 L2 283.72 ZM17.53 340.36 L15.97 347.02 L11.57 341.77
+						 L17.53 340.36 L17.53 340.36 Z" class="st12"/>
+		</g>
+		<g id="shape102-263" v:mID="102" v:groupContext="shape" transform="translate(262.972,-147.37)">
+			<title>Sheet.102</title>
+			<path d="M82.31 283.13 L3.45 343.12 L4.68 344.74 L83.54 284.76 L82.31 283.13 L82.31 283.13 ZM3.02 340.89 L0 347.02 L6.74
+						 345.74 L3.02 340.89 L3.02 340.89 Z" class="st12"/>
+		</g>
+		<g id="shape103-265" v:mID="103" v:groupContext="shape" transform="translate(358.537,-149.107)">
+			<title>Sheet.103</title>
+			<path d="M83.92 284.85 L3.53 343.2 L4.73 344.84 L85.12 286.5 L83.92 284.85 L83.92 284.85 ZM3.15 340.95 L0 347.02 L6.75
+						 345.89 L3.15 340.95 L3.15 340.95 Z" class="st13"/>
+		</g>
+		<g id="shape104-267" v:mID="104" v:groupContext="shape" transform="translate(264.413,-147.534)">
+			<title>Sheet.104</title>
+			<path d="M275.95 283 L4.77 343.27 L5.22 345.25 L276.37 285 L275.95 283 L275.95 283 ZM5.31 341.05 L0 345.37 L6.66 347.02
+						 L5.31 341.05 L5.31 341.05 Z" class="st14"/>
+		</g>
+		<g id="shape105-269" v:mID="105" v:groupContext="shape" transform="translate(456.982,-148.103)">
+			<title>Sheet.105</title>
+			<path d="M179.48 283.72 L4.5 343.48 L5.16 345.43 L180.14 285.66 L179.48 283.72 L179.48 283.72 ZM4.8 341.23 L0 346.12
+						 L6.81 347.02 L4.8 341.23 L4.8 341.23 Z" class="st15"/>
+		</g>
+		<g id="shape106-271" v:mID="106" v:groupContext="shape" transform="translate(335.628,-18)">
+			<title>Sheet.106</title>
+			<path d="M0 309.64 C0 305.52 2.99 302.16 6.65 302.16 L14.2 302.16 L8.01 284.85 L35.48 302.16 L78.47 302.16 C82.15 302.16
+						 85.12 305.52 85.12 309.64 L85.12 309.64 L85.12 320.85 L85.12 339.54 C85.12 343.68 82.15 347.02 78.47 347.02
+						 L35.48 347.02 L14.2 347.02 L14.2 347.02 L6.65 347.02 C2.99 347.02 0 343.68 0 339.54 L0 320.85 L0 309.64
+						 L0 309.64 Z" class="st5"/>
+		</g>
+		<g id="shape109-273" v:mID="109" v:groupContext="shape" transform="translate(157.564,-62.4234)">
+			<title>Sheet.109</title>
+			<path d="M16.21 347.02 C11.74 347.02 8.1 346.42 8.1 345.67 L8.1 303.49 C8.1 302.75 4.49 302.14 0 302.14 C4.49 302.14
+						 8.1 301.54 8.1 300.79 L8.1 258.61 C8.1 257.88 11.74 257.26 16.21 257.26" class="st7"/>
+		</g>
+		<g id="shape110-276" v:mID="110" v:groupContext="shape" transform="translate(113.844,-100.157)">
+			<title>Sheet.110</title>
+			<desc>Groups</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="20.2175" cy="341.046" width="40.44" height="11.9384"/>
+			<path d="M40.44 335.08 L0 335.08 L0 347.02 L40.44 347.02 L40.44 335.08" class="st3"/>
+			<text x="3.85" y="344.03" class="st16" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Groups</text>		</g>
+		<g id="shape111-280" v:mID="111" v:groupContext="shape" transform="translate(196.718,-76.2186)">
+			<title>Sheet.111</title>
+			<path d="M0 331.97 C0 330.32 2.27 328.96 5.04 328.96 L37.61 328.96 L60.43 284.85 L53.72 328.96 L59.43 328.96 C62.22 328.96
+						 64.47 330.32 64.47 331.97 L64.47 331.97 L64.47 336.48 L64.47 344.01 C64.47 345.67 62.22 347.02 59.43 347.02
+						 L53.72 347.02 L37.61 347.02 L37.61 347.02 L5.04 347.02 C2.27 347.02 0 345.67 0 344.01 L0 336.48 L0 331.97
+						 L0 331.97 Z" class="st5"/>
+		</g>
+		<g id="shape112-282" v:mID="112" v:groupContext="shape" transform="translate(196.65,-80.2991)">
+			<title>Sheet.112</title>
+			<desc>group id</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="27.7691" cy="339.824" width="55.54" height="14.3829"/>
+			<path d="M55.54 332.63 L0 332.63 L0 347.02 L55.54 347.02 L55.54 332.63" class="st3"/>
+			<text x="5.09" y="343.42" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>group id</text>		</g>
+		<g id="shape114-286" v:mID="114" v:groupContext="shape" transform="translate(506.433,-128.007)">
+			<title>Sheet.114</title>
+			<desc>-</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="6.63728" cy="336.229" width="13.28" height="21.5726"/>
+			<path d="M13.27 325.44 L0 325.44 L0 347.02 L13.27 347.02 L13.27 325.44" class="st3"/>
+			<text x="3.06" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>-</text>		</g>
+		<g id="shape115-290" v:mID="115" v:groupContext="shape" transform="translate(529.004,-128.007)">
+			<title>Sheet.115</title>
+			<desc>Keys separated into</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="97.1729" cy="336.229" width="194.35" height="21.5726"/>
+			<path d="M194.35 325.44 L0 325.44 L0 347.02 L194.35 347.02 L194.35 325.44" class="st3"/>
+			<text x="17.06" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Keys separated into  </text>		</g>
+		<g id="shape116-294" v:mID="116" v:groupContext="shape" transform="translate(529.004,-106.438)">
+			<title>Sheet.116</title>
+			<desc>groups based on</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="83.1587" cy="336.229" width="166.32" height="21.5726"/>
+			<path d="M166.32 325.44 L0 325.44 L0 347.02 L166.32 347.02 L166.32 325.44" class="st3"/>
+			<text x="15.23" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>groups based on  </text>		</g>
+		<g id="shape117-298" v:mID="117" v:groupContext="shape" transform="translate(529.004,-84.869)">
+			<title>Sheet.117</title>
+			<desc>some bits from hash</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="97.731" cy="336.229" width="195.47" height="21.5726"/>
+			<path d="M195.46 325.44 L0 325.44 L0 347.02 L195.46 347.02 L195.46 325.44" class="st3"/>
+			<text x="14.94" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>some bits from hash</text>		</g>
+		<g id="shape118-302" v:mID="118" v:groupContext="shape" transform="translate(506.433,-63.2999)">
+			<title>Sheet.118</title>
+			<desc>-</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="6.63728" cy="336.229" width="13.28" height="21.5726"/>
+			<path d="M13.27 325.44 L0 325.44 L0 347.02 L13.27 347.02 L13.27 325.44" class="st3"/>
+			<text x="3.06" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>-</text>		</g>
+		<g id="shape119-306" v:mID="119" v:groupContext="shape" transform="translate(529.004,-63.2999)">
+			<title>Sheet.119</title>
+			<desc>Groups contain a</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="84.2539" cy="336.229" width="168.51" height="21.5726"/>
+			<path d="M168.51 325.44 L0 325.44 L0 347.02 L168.51 347.02 L168.51 325.44" class="st3"/>
+			<text x="15.38" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Groups contain a  </text>		</g>
+		<g id="shape120-310" v:mID="120" v:groupContext="shape" transform="translate(529.004,-41.7308)">
+			<title>Sheet.120</title>
+			<desc>small number of</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="81.4635" cy="336.229" width="162.93" height="21.5726"/>
+			<path d="M162.93 325.44 L0 325.44 L0 347.02 L162.93 347.02 L162.93 325.44" class="st3"/>
+			<text x="15.01" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>small number of  </text>		</g>
+		<g id="shape121-314" v:mID="121" v:groupContext="shape" transform="translate(529.004,-20.1617)">
+			<title>Sheet.121</title>
+			<desc>keys (&#60;28)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="50.4481" cy="336.229" width="100.9" height="21.5726"/>
+			<path d="M100.9 325.44 L0 325.44 L0 347.02 L100.9 347.02 L100.9 325.44" class="st3"/>
+			<text x="8.77" y="341.62" class="st18" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>keys (&#60;28)</text>		</g>
+		<g id="shape122-318" v:mID="122" v:groupContext="shape" transform="translate(19.1996,-146.276)">
+			<title>Sheet.122</title>
+			<path d="M0 310.17 C-0 306.1 3.62 302.8 8.07 302.8 L14.46 302.8 L29.68 282.28 L36.14 302.8 L78.65 302.8 C83.11 302.8
+						 86.72 306.1 86.72 310.17 L86.72 310.17 L86.72 321.22 L86.72 339.65 C86.72 343.72 83.11 347.02 78.65 347.02
+						 L36.14 347.02 L14.46 347.02 L14.46 347.02 L8.07 347.02 C3.62 347.02 0 343.72 0 339.65 L0 321.22 L0 310.17
+						 L0 310.17 Z" class="st5"/>
+		</g>
+		<g id="shape123-320" v:mID="123" v:groupContext="shape" transform="translate(41.9777,-174.053)">
+			<title>Sheet.123</title>
+			<desc>Group</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="22.8289" cy="339.824" width="45.66" height="14.3829"/>
+			<path d="M45.66 332.63 L0 332.63 L0 347.02 L45.66 347.02 L45.66 332.63" class="st3"/>
+			<text x="5.9" y="343.42" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group  </text>		</g>
+		<g id="shape124-324" v:mID="124" v:groupContext="shape" transform="translate(34.4142,-159.674)">
+			<title>Sheet.124</title>
+			<desc>Identifier</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="31.5173" cy="339.824" width="63.04" height="14.3829"/>
+			<path d="M63.03 332.63 L0 332.63 L0 347.02 L63.03 347.02 L63.03 332.63" class="st3"/>
+			<text x="7.04" y="343.42" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Identifier  </text>		</g>
+		<g id="shape125-328" v:mID="125" v:groupContext="shape" transform="translate(28.7716,-145.295)">
+			<title>Sheet.125</title>
+			<desc>(simplified)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="36.2165" cy="339.824" width="72.44" height="14.3829"/>
+			<path d="M72.43 332.63 L0 332.63 L0 347.02 L72.43 347.02 L72.43 332.63" class="st3"/>
+			<text x="6.19" y="343.42" class="st17" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(simplified)</text>		</g>
+		<g id="shape127-332" v:mID="127" v:groupContext="shape" transform="translate(517.688,-71.2991)">
+			<title>Sheet.127</title>
+			<desc>Keys separated into groups based on some bits from hash. Grou...</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="112.5" cy="302.139" width="225" height="89.7513"/>
+			<g id="shadow127-333" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st19">
+				<rect x="0" y="257.264" width="225" height="89.7513" class="st20"/>
+			</g>
+			<rect x="0" y="257.264" width="225" height="89.7513" class="st21"/>
+			<text x="4" y="281.09" class="st22" v:langID="1033"><v:paragraph v:indentFirst="-18" v:indentLeft="18" v:bullet="1"/><v:tabList/><tspan
+						class="st23" v:isBullet="true">·</tspan> <tspan class="st24">Keys separated into groups based </tspan><tspan
+						x="22" dy="1.204em" class="st24">on some bits from hash</tspan><tspan class="st24">.<v:newlineChar/></tspan><tspan
+						x="4" dy="1.211em" class="st23" v:isBullet="true">·</tspan> <tspan class="st24">Groups contain a small number of </tspan><tspan
+						x="22" dy="1.204em" class="st24">keys </tspan><tspan class="st24">(</tspan><tspan class="st24">&#60;</tspan><tspan
+						class="st24">28</tspan><tspan class="st24">)</tspan></text>		</g>
+		<g id="shape129-349" v:mID="129" v:groupContext="shape" transform="translate(336.326,-26.2991)">
+			<title>Sheet.129</title>
+			<desc>Total # of keys in group so far</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="39.6784" cy="333.515" width="79.36" height="27"/>
+			<rect x="0" y="320.015" width="79.3567" height="27" class="st25"/>
+			<text x="4.5" y="329.92" class="st26" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Total # of keys <tspan
+						x="4.39" dy="1.2em" class="st23">in group so far</tspan></text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i8.svg b/doc/guides/prog_guide/img/efd_i8.svg
new file mode 100644
index 0000000..d0fd463
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i8.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i9.svg Page-2 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.98372in" height="2.08442in"
+		viewBox="0 0 358.828 150.078" xml:space="preserve" color-interpolation-filters="sRGB" class="st8">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st2 {stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st3 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st4 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st5 {fill:#000000;font-family:Intel Clear;font-size:0.998566em}
+		.st6 {fill:#c00000;font-family:Intel Clear;font-size:0.828804em;font-weight:bold}
+		.st7 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st8 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<g v:mID="4" v:index="2" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-2</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape4-1" v:mID="4" v:groupContext="shape" transform="translate(206.306,-19.0195)">
+			<title>Sheet.4</title>
+			<path d="M0 38.04 L0 150.08 L133.5 150.08 L133.5 38.04 L0 38.04 L0 38.04 Z" class="st1"/>
+		</g>
+		<g id="shape5-3" v:mID="5" v:groupContext="shape" transform="translate(206.306,-19.0195)">
+			<title>Sheet.5</title>
+			<path d="M0 38.04 L133.5 38.04 L133.5 150.08 L0 150.08 L0 38.04" class="st2"/>
+		</g>
+		<g id="shape6-6" v:mID="6" v:groupContext="shape" transform="translate(215.55,-70.7853)">
+			<title>Sheet.6</title>
+			<path d="M0 121.92 C0 118.82 2.54 116.29 5.64 116.29 L110.69 116.29 C113.81 116.29 116.33 118.82 116.33 121.92 L116.33
+						 144.45 C116.33 147.56 113.81 150.08 110.69 150.08 L5.64 150.08 C2.54 150.08 0 147.56 0 144.45 L0 121.92
+						 Z" class="st1"/>
+		</g>
+		<g id="shape7-8" v:mID="7" v:groupContext="shape" transform="translate(215.55,-70.7853)">
+			<title>Sheet.7</title>
+			<path d="M0 121.92 C0 118.82 2.54 116.29 5.64 116.29 L110.69 116.29 C113.81 116.29 116.33 118.82 116.33 121.92 L116.33
+						 144.45 C116.33 147.56 113.81 150.08 110.69 150.08 L5.64 150.08 C2.54 150.08 0 147.56 0 144.45 L0 121.92
+						 Z" class="st3"/>
+		</g>
+		<g id="shape8-10" v:mID="8" v:groupContext="shape" transform="translate(242.756,-86.1914)">
+			<title>Sheet.8</title>
+			<desc>hash_index</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="36.9951" cy="142.887" width="74" height="14.3829"/>
+			<path d="M73.99 135.7 L0 135.7 L0 150.08 L73.99 150.08 L73.99 135.7" class="st4"/>
+			<text x="6.29" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash_index</text>		</g>
+		<g id="shape9-14" v:mID="9" v:groupContext="shape" transform="translate(229.67,-71.812)">
+			<title>Sheet.9</title>
+			<desc>(integer, 16 bits)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="52.0635" cy="142.887" width="104.13" height="14.3829"/>
+			<path d="M104.13 135.7 L0 135.7 L0 150.08 L104.13 150.08 L104.13 135.7" class="st4"/>
+			<text x="8.25" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(integer, 16 bits)</text>		</g>
+		<g id="shape10-18" v:mID="10" v:groupContext="shape" transform="translate(215.55,-27.1678)">
+			<title>Sheet.10</title>
+			<path d="M0 121.92 C0 118.82 2.54 116.29 5.64 116.29 L110.69 116.29 C113.81 116.29 116.33 118.82 116.33 121.92 L116.33
+						 144.45 C116.33 147.56 113.81 150.08 110.69 150.08 L5.64 150.08 C2.54 150.08 0 147.56 0 144.45 L0 121.92
+						 Z" class="st1"/>
+		</g>
+		<g id="shape11-20" v:mID="11" v:groupContext="shape" transform="translate(215.55,-27.1678)">
+			<title>Sheet.11</title>
+			<path d="M0 121.92 C0 118.82 2.54 116.29 5.64 116.29 L110.69 116.29 C113.81 116.29 116.33 118.82 116.33 121.92 L116.33
+						 144.45 C116.33 147.56 113.81 150.08 110.69 150.08 L5.64 150.08 C2.54 150.08 0 147.56 0 144.45 L0 121.92
+						 Z" class="st3"/>
+		</g>
+		<g id="shape12-22" v:mID="12" v:groupContext="shape" transform="translate(237.836,-42.6033)">
+			<title>Sheet.12</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="42.693" cy="142.887" width="85.39" height="14.3829"/>
+			<path d="M85.39 135.7 L0 135.7 L0 150.08 L85.39 150.08 L85.39 135.7" class="st4"/>
+			<text x="7.03" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape13-26" v:mID="13" v:groupContext="shape" transform="translate(251.643,-28.2239)">
+			<title>Sheet.13</title>
+			<desc>(16 bits)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="26.9562" cy="142.887" width="53.92" height="14.3829"/>
+			<path d="M53.91 135.7 L0 135.7 L0 150.08 L53.91 150.08 L53.91 135.7" class="st4"/>
+			<text x="4.98" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(16 bits)</text>		</g>
+		<g id="shape14-30" v:mID="14" v:groupContext="shape" transform="translate(213.473,-114.303)">
+			<title>Sheet.14</title>
+			<desc>Group ID: 0x0102</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="47.976" cy="144.109" width="95.96" height="11.9384"/>
+			<path d="M95.95 138.14 L0 138.14 L0 150.08 L95.95 150.08 L95.95 138.14" class="st4"/>
+			<text x="7.47" y="147.09" class="st6" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group ID: 0x0102</text>		</g>
+		<g id="shape15-34" v:mID="15" v:groupContext="shape" transform="translate(19.0195,-99.4242)">
+			<title>Sheet.15</title>
+			<path d="M0 129.31 C0 127.02 1.87 125.15 4.16 125.15 L109.18 125.15 C111.47 125.15 113.33 127.02 113.33 129.31 L113.33
+						 145.93 C113.33 148.22 111.47 150.08 109.18 150.08 L4.16 150.08 C1.87 150.08 0 148.22 0 145.93 L0 129.31
+						 Z" class="st1"/>
+		</g>
+		<g id="shape16-36" v:mID="16" v:groupContext="shape" transform="translate(19.0195,-99.4242)">
+			<title>Sheet.16</title>
+			<path d="M0 129.31 C0 127.02 1.87 125.15 4.16 125.15 L109.18 125.15 C111.47 125.15 113.33 127.02 113.33 129.31 L113.33
+						 145.93 C113.33 148.22 111.47 150.08 109.18 150.08 L4.16 150.08 C1.87 150.08 0 148.22 0 145.93 L0 129.31
+						 Z" class="st3"/>
+		</g>
+		<g id="shape17-38" v:mID="17" v:groupContext="shape" transform="translate(33.9485,-103.285)">
+			<title>Sheet.17</title>
+			<desc>Key1: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="49.6862" cy="142.887" width="99.38" height="14.3829"/>
+			<path d="M99.37 135.7 L0 135.7 L0 150.08 L99.37 150.08 L99.37 135.7" class="st4"/>
+			<text x="7.94" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key1: Value = 0</text>		</g>
+		<g id="shape18-42" v:mID="18" v:groupContext="shape" transform="translate(19.0195,-74.6198)">
+			<title>Sheet.18</title>
+			<path d="M0 129.31 C0 127.02 1.87 125.15 4.16 125.15 L109.18 125.15 C111.47 125.15 113.33 127.02 113.33 129.31 L113.33
+						 145.93 C113.33 148.22 111.47 150.08 109.18 150.08 L4.16 150.08 C1.87 150.08 0 148.22 0 145.93 L0 129.31
+						 Z" class="st1"/>
+		</g>
+		<g id="shape19-44" v:mID="19" v:groupContext="shape" transform="translate(19.0195,-74.6198)">
+			<title>Sheet.19</title>
+			<path d="M0 129.31 C0 127.02 1.87 125.15 4.16 125.15 L109.18 125.15 C111.47 125.15 113.33 127.02 113.33 129.31 L113.33
+						 145.93 C113.33 148.22 111.47 150.08 109.18 150.08 L4.16 150.08 C1.87 150.08 0 148.22 0 145.93 L0 129.31
+						 Z" class="st3"/>
+		</g>
+		<g id="shape20-46" v:mID="20" v:groupContext="shape" transform="translate(33.9485,-78.4626)">
+			<title>Sheet.20</title>
+			<desc>Key3: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="49.6862" cy="142.887" width="99.38" height="14.3829"/>
+			<path d="M99.37 135.7 L0 135.7 L0 150.08 L99.37 150.08 L99.37 135.7" class="st4"/>
+			<text x="7.94" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key3: Value = 1</text>		</g>
+		<g id="shape21-50" v:mID="21" v:groupContext="shape" transform="translate(19.0195,-49.5757)">
+			<title>Sheet.21</title>
+			<path d="M0 129.21 C0 126.91 1.88 125.03 4.19 125.03 L109.15 125.03 C111.46 125.03 113.33 126.91 113.33 129.21 L113.33
+						 145.91 C113.33 148.21 111.46 150.08 109.15 150.08 L4.19 150.08 C1.88 150.08 0 148.21 0 145.91 L0 129.21
+						 Z" class="st1"/>
+		</g>
+		<g id="shape22-52" v:mID="22" v:groupContext="shape" transform="translate(19.0195,-49.5757)">
+			<title>Sheet.22</title>
+			<path d="M0 129.21 C0 126.91 1.88 125.03 4.19 125.03 L109.15 125.03 C111.46 125.03 113.33 126.91 113.33 129.21 L113.33
+						 145.91 C113.33 148.21 111.46 150.08 109.15 150.08 L4.19 150.08 C1.88 150.08 0 148.21 0 145.91 L0 129.21
+						 Z" class="st3"/>
+		</g>
+		<g id="shape23-54" v:mID="23" v:groupContext="shape" transform="translate(33.9485,-53.4903)">
+			<title>Sheet.23</title>
+			<desc>Key4: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="49.6862" cy="142.887" width="99.38" height="14.3829"/>
+			<path d="M99.37 135.7 L0 135.7 L0 150.08 L99.37 150.08 L99.37 135.7" class="st4"/>
+			<text x="7.94" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key4: Value = 0</text>		</g>
+		<g id="shape24-58" v:mID="24" v:groupContext="shape" transform="translate(19.0195,-25.0109)">
+			<title>Sheet.24</title>
+			<path d="M0 129.21 C0 126.91 1.88 125.03 4.19 125.03 L109.15 125.03 C111.46 125.03 113.33 126.91 113.33 129.21 L113.33
+						 145.91 C113.33 148.21 111.46 150.08 109.15 150.08 L4.19 150.08 C1.88 150.08 0 148.21 0 145.91 L0 129.21
+						 Z" class="st1"/>
+		</g>
+		<g id="shape25-60" v:mID="25" v:groupContext="shape" transform="translate(19.0195,-25.0109)">
+			<title>Sheet.25</title>
+			<path d="M0 129.21 C0 126.91 1.88 125.03 4.19 125.03 L109.15 125.03 C111.46 125.03 113.33 126.91 113.33 129.21 L113.33
+						 145.91 C113.33 148.21 111.46 150.08 109.15 150.08 L4.19 150.08 C1.88 150.08 0 148.21 0 145.91 L0 129.21
+						 Z" class="st3"/>
+		</g>
+		<g id="shape26-62" v:mID="26" v:groupContext="shape" transform="translate(33.9485,-28.927)">
+			<title>Sheet.26</title>
+			<desc>Key7: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="49.6862" cy="142.887" width="99.38" height="14.3829"/>
+			<path d="M99.37 135.7 L0 135.7 L0 150.08 L99.37 150.08 L99.37 135.7" class="st4"/>
+			<text x="7.94" y="146.48" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key7: Value = 1</text>		</g>
+		<g id="shape27-66" v:mID="27" v:groupContext="shape" transform="translate(141.536,-51.5529)">
+			<title>Sheet.27</title>
+			<path d="M0 115.39 L22.75 115.39 L22.75 103.82 L45.5 126.95 L22.75 150.08 L22.75 138.51 L0 138.51 L0 115.39 Z"
+					class="st7"/>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/img/efd_i9.svg b/doc/guides/prog_guide/img/efd_i9.svg
new file mode 100644
index 0000000..b2e385d
--- /dev/null
+++ b/doc/guides/prog_guide/img/efd_i9.svg
@@ -0,0 +1,390 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i10.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="9.8125in" height="3.76365in"
+		viewBox="0 0 706.5 270.983" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {fill:#ffffff;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st2 {fill:none;stroke:#00aeef;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.03901}
+		.st3 {stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st4 {fill:#000000;font-family:Arial;font-size:0.998566em}
+		.st5 {fill:#000000;font-family:Arial;font-size:0.918686em}
+		.st6 {fill:#0071c5;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+		.st7 {fill:#ffffff;font-family:Arial;font-size:0.998566em}
+		.st8 {fill:#ffffff;font-family:Arial;font-size:1.49785em}
+		.st9 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape68-1" v:mID="68" v:groupContext="shape" transform="translate(196.523,-158.978)">
+			<title>Sheet.68</title>
+			<path d="M0 250.22 C0 247.95 1.89 246.06 4.17 246.06 L317.25 246.06 C319.53 246.06 321.39 247.95 321.39 250.22 L321.39
+						 266.85 C321.39 269.13 319.53 270.98 317.25 270.98 L4.17 270.98 C1.89 270.98 0 269.13 0 266.85 L0 250.22
+						 Z" class="st1"/>
+		</g>
+		<g id="shape69-3" v:mID="69" v:groupContext="shape" transform="translate(196.523,-158.978)">
+			<title>Sheet.69</title>
+			<path d="M0 250.22 C0 247.95 1.89 246.06 4.17 246.06 L317.25 246.06 C319.53 246.06 321.39 247.95 321.39 250.22 L321.39
+						 266.85 C321.39 269.13 319.53 270.98 317.25 270.98 L4.17 270.98 C1.89 270.98 0 269.13 0 266.85 L0 250.22
+						 Z" class="st2"/>
+		</g>
+		<g id="shape70-5" v:mID="70" v:groupContext="shape" transform="translate(186.139,-162.437)">
+			<title>Sheet.70</title>
+			<desc>(hash(key, seed1) + hash_index *</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="106.671" cy="263.792" width="213.35" height="14.3829"/>
+			<path d="M213.34 256.6 L0 256.6 L0 270.98 L213.34 270.98 L213.34 256.6" class="st3"/>
+			<text x="17.24" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>(hash(key, seed1) + hash_index *  </text>		</g>
+		<g id="shape71-9" v:mID="71" v:groupContext="shape" transform="translate(381.48,-162.845)">
+			<title>Sheet.71</title>
+			<desc>hash(key</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="27.4843" cy="264.367" width="54.97" height="13.2327"/>
+			<path d="M54.97 257.75 L0 257.75 L0 270.98 L54.97 270.98 L54.97 257.75" class="st3"/>
+			<text x="5.12" y="267.67" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash(key</text>		</g>
+		<g id="shape72-13" v:mID="72" v:groupContext="shape" transform="translate(424.755,-162.437)">
+			<title>Sheet.72</title>
+			<desc>, seed2)) % 16</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="46.7254" cy="263.792" width="93.46" height="14.3829"/>
+			<path d="M93.45 256.6 L0 256.6 L0 270.98 L93.45 270.98 L93.45 256.6" class="st3"/>
+			<text x="7.76" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>, seed2)) % 16</text>		</g>
+		<g id="shape73-17" v:mID="73" v:groupContext="shape" transform="translate(524.094,-148.373)">
+			<title>Sheet.73</title>
+			<path d="M0 236.29 L22.75 236.29 L22.75 224.73 L45.5 247.86 L22.75 270.98 L22.75 259.42 L0 259.42 L0 236.29 Z"
+					class="st6"/>
+		</g>
+		<g id="shape74-19" v:mID="74" v:groupContext="shape" transform="translate(574.148,-217.574)">
+			<title>Sheet.74</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st1"/>
+		</g>
+		<g id="shape75-21" v:mID="75" v:groupContext="shape" transform="translate(574.148,-217.574)">
+			<title>Sheet.75</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st2"/>
+		</g>
+		<g id="shape76-23" v:mID="76" v:groupContext="shape" transform="translate(584.296,-231.499)">
+			<title>Sheet.76</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="40.993" cy="263.792" width="81.99" height="14.3829"/>
+			<path d="M81.99 256.6 L0 256.6 L0 270.98 L81.99 270.98 L81.99 256.6" class="st3"/>
+			<text x="7.01" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape77-27" v:mID="77" v:groupContext="shape" transform="translate(655.369,-231.499)">
+			<title>Sheet.77</title>
+			<desc>bit</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="11.1076" cy="263.792" width="22.22" height="14.3829"/>
+			<path d="M22.22 256.6 L0 256.6 L0 270.98 L22.22 270.98 L22.22 256.6" class="st3"/>
+			<text x="4.78" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit  </text>		</g>
+		<g id="shape78-31" v:mID="78" v:groupContext="shape" transform="translate(588.858,-217.12)">
+			<title>Sheet.78</title>
+			<desc>index for key1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="44.8113" cy="263.792" width="89.63" height="14.3829"/>
+			<path d="M89.62 256.6 L0 256.6 L0 270.98 L89.62 270.98 L89.62 256.6" class="st3"/>
+			<text x="7.51" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>index for key1</text>		</g>
+		<g id="shape79-35" v:mID="79" v:groupContext="shape" transform="translate(573.548,-178.869)">
+			<title>Sheet.79</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st1"/>
+		</g>
+		<g id="shape80-37" v:mID="80" v:groupContext="shape" transform="translate(573.548,-178.869)">
+			<title>Sheet.80</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st2"/>
+		</g>
+		<g id="shape81-39" v:mID="81" v:groupContext="shape" transform="translate(584.296,-192.768)">
+			<title>Sheet.81</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="40.993" cy="263.792" width="81.99" height="14.3829"/>
+			<path d="M81.99 256.6 L0 256.6 L0 270.98 L81.99 270.98 L81.99 256.6" class="st3"/>
+			<text x="7.01" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape82-43" v:mID="82" v:groupContext="shape" transform="translate(655.369,-192.768)">
+			<title>Sheet.82</title>
+			<desc>bit</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="11.1076" cy="263.792" width="22.22" height="14.3829"/>
+			<path d="M22.22 256.6 L0 256.6 L0 270.98 L22.22 270.98 L22.22 256.6" class="st3"/>
+			<text x="4.78" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit  </text>		</g>
+		<g id="shape83-47" v:mID="83" v:groupContext="shape" transform="translate(588.858,-178.388)">
+			<title>Sheet.83</title>
+			<desc>index for key3</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="44.8113" cy="263.792" width="89.63" height="14.3829"/>
+			<path d="M89.62 256.6 L0 256.6 L0 270.98 L89.62 270.98 L89.62 256.6" class="st3"/>
+			<text x="7.51" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>index for key3</text>		</g>
+		<g id="shape84-51" v:mID="84" v:groupContext="shape" transform="translate(574.148,-139.326)">
+			<title>Sheet.84</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st1"/>
+		</g>
+		<g id="shape85-53" v:mID="85" v:groupContext="shape" transform="translate(574.148,-139.326)">
+			<title>Sheet.85</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st2"/>
+		</g>
+		<g id="shape86-55" v:mID="86" v:groupContext="shape" transform="translate(584.296,-153.227)">
+			<title>Sheet.86</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="40.993" cy="263.792" width="81.99" height="14.3829"/>
+			<path d="M81.99 256.6 L0 256.6 L0 270.98 L81.99 270.98 L81.99 256.6" class="st3"/>
+			<text x="7.01" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape87-59" v:mID="87" v:groupContext="shape" transform="translate(655.369,-153.227)">
+			<title>Sheet.87</title>
+			<desc>bit</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="11.1076" cy="263.792" width="22.22" height="14.3829"/>
+			<path d="M22.22 256.6 L0 256.6 L0 270.98 L22.22 270.98 L22.22 256.6" class="st3"/>
+			<text x="4.78" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit  </text>		</g>
+		<g id="shape88-63" v:mID="88" v:groupContext="shape" transform="translate(588.858,-138.848)">
+			<title>Sheet.88</title>
+			<desc>index for key4</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="44.8113" cy="263.792" width="89.63" height="14.3829"/>
+			<path d="M89.62 256.6 L0 256.6 L0 270.98 L89.62 270.98 L89.62 256.6" class="st3"/>
+			<text x="7.51" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>index for key4</text>		</g>
+		<g id="shape89-67" v:mID="89" v:groupContext="shape" transform="translate(574.148,-100.622)">
+			<title>Sheet.89</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st1"/>
+		</g>
+		<g id="shape90-69" v:mID="90" v:groupContext="shape" transform="translate(574.148,-100.622)">
+			<title>Sheet.90</title>
+			<path d="M0 244.83 C-0 241.95 2.37 239.59 5.25 239.59 L108.11 239.59 C110.99 239.59 113.33 241.95 113.33 244.83 L113.33
+						 265.77 C113.33 268.65 110.99 270.98 108.11 270.98 L5.25 270.98 C2.37 270.98 0 268.65 0 265.77 L0 244.83
+						 Z" class="st2"/>
+		</g>
+		<g id="shape91-71" v:mID="91" v:groupContext="shape" transform="translate(584.296,-114.496)">
+			<title>Sheet.91</title>
+			<desc>lookup_table</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="40.993" cy="263.792" width="81.99" height="14.3829"/>
+			<path d="M81.99 256.6 L0 256.6 L0 270.98 L81.99 270.98 L81.99 256.6" class="st3"/>
+			<text x="7.01" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>lookup_table</text>		</g>
+		<g id="shape92-75" v:mID="92" v:groupContext="shape" transform="translate(655.369,-114.496)">
+			<title>Sheet.92</title>
+			<desc>bit</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="11.1076" cy="263.792" width="22.22" height="14.3829"/>
+			<path d="M22.22 256.6 L0 256.6 L0 270.98 L22.22 270.98 L22.22 256.6" class="st3"/>
+			<text x="4.78" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit  </text>		</g>
+		<g id="shape93-79" v:mID="93" v:groupContext="shape" transform="translate(588.858,-100.117)">
+			<title>Sheet.93</title>
+			<desc>index for key7</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="44.8113" cy="263.792" width="89.63" height="14.3829"/>
+			<path d="M89.62 256.6 L0 256.6 L0 270.98 L89.62 270.98 L89.62 256.6" class="st3"/>
+			<text x="7.51" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>index for key7</text>		</g>
+		<g id="shape94-83" v:mID="94" v:groupContext="shape" transform="translate(205.227,-191.137)">
+			<title>Sheet.94</title>
+			<path d="M0 217.76 C0 213 3.87 209.14 8.64 209.14 L14.53 209.14 L14.53 209.14 L36.32 209.14 L78.52 209.14 C83.3 209.14
+						 87.16 213 87.16 217.76 L87.16 239.33 L87.16 239.33 L87.16 252.27 L87.16 252.27 C87.16 257.05 83.3 260.9
+						 78.52 260.9 L36.32 260.9 L18.46 270.98 L14.53 260.9 L8.64 260.9 C3.87 260.9 0 257.05 0 252.27 L0 239.33
+						 L0 239.33 L0 217.76 Z" class="st6"/>
+		</g>
+		<g id="shape95-85" v:mID="95" v:groupContext="shape" transform="translate(214.98,-225.215)">
+			<title>Sheet.95</title>
+			<desc>CRC32 (32</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="38.2947" cy="263.792" width="76.59" height="14.3829"/>
+			<path d="M76.59 256.6 L0 256.6 L0 270.98 L76.59 270.98 L76.59 256.6" class="st3"/>
+			<text x="8.33" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>CRC32 (32  </text>		</g>
+		<g id="shape96-89" v:mID="96" v:groupContext="shape" transform="translate(222.123,-210.835)">
+			<title>Sheet.96</title>
+			<desc>bit output)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="32.5584" cy="263.792" width="65.12" height="14.3829"/>
+			<path d="M65.12 256.6 L0 256.6 L0 270.98 L65.12 270.98 L65.12 256.6" class="st3"/>
+			<text x="5.91" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit output)</text>		</g>
+		<g id="shape97-93" v:mID="97" v:groupContext="shape" transform="translate(305.473,-188.366)">
+			<title>Sheet.97</title>
+			<path d="M0 226.84 C0 223.28 2.9 220.39 6.47 220.39 L21.37 220.39 L21.37 220.39 L53.42 220.39 L121.77 220.39 C125.34
+						 220.39 128.22 223.28 128.22 226.84 L128.22 242.97 L128.22 242.97 L128.22 252.65 L128.22 252.65 C128.22 256.21
+						 125.34 259.09 121.77 259.09 L53.42 259.09 L38.73 270.98 L21.37 259.09 L6.47 259.09 C2.9 259.09 0 256.21
+						 0 252.65 L0 242.97 L0 242.97 L0 226.84 Z" class="st6"/>
+		</g>
+		<g id="shape98-95" v:mID="98" v:groupContext="shape" transform="translate(318.48,-217.733)">
+			<title>Sheet.98</title>
+			<desc>Goal: Find a valid</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="57.4478" cy="263.792" width="114.9" height="14.3829"/>
+			<path d="M114.9 256.6 L0 256.6 L0 270.98 L114.9 270.98 L114.9 256.6" class="st3"/>
+			<text x="10.82" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Goal: Find a valid  </text>		</g>
+		<g id="shape99-99" v:mID="99" v:groupContext="shape" transform="translate(339.077,-203.354)">
+			<title>Sheet.99</title>
+			<desc>hash_index</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="37.1611" cy="263.792" width="74.33" height="14.3829"/>
+			<path d="M74.32 256.6 L0 256.6 L0 270.98 L74.32 270.98 L74.32 256.6" class="st3"/>
+			<text x="6.51" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>hash_index</text>		</g>
+		<g id="shape100-103" v:mID="100" v:groupContext="shape" transform="translate(438.135,-185.939)">
+			<title>Sheet.100</title>
+			<path d="M0 217.36 C0 213.8 2.91 210.89 6.48 210.89 L21.37 210.89 L21.37 210.89 L53.42 210.89 L121.77 210.89 C125.34
+						 210.89 128.22 213.8 128.22 217.36 L128.22 233.48 L128.22 233.48 L128.22 243.15 L128.22 243.15 C128.22 246.72
+						 125.34 249.59 121.77 249.59 L53.42 249.59 L54.75 270.98 L21.37 249.59 L6.48 249.59 C2.91 249.59 0 246.72
+						 0 243.15 L0 233.48 L0 233.48 L0 217.36 Z" class="st6"/>
+		</g>
+		<g id="shape101-105" v:mID="101" v:groupContext="shape" transform="translate(448.763,-224.802)">
+			<title>Sheet.101</title>
+			<desc>Lookup Table has</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="58.6085" cy="263.792" width="117.22" height="14.3829"/>
+			<path d="M117.22 256.6 L0 256.6 L0 270.98 L117.22 270.98 L117.22 256.6" class="st3"/>
+			<text x="10.98" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Lookup Table has  </text>		</g>
+		<g id="shape102-109" v:mID="102" v:groupContext="shape" transform="translate(484.549,-210.423)">
+			<title>Sheet.102</title>
+			<desc>16 bits</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="22.2166" cy="263.792" width="44.44" height="14.3829"/>
+			<path d="M44.43 256.6 L0 256.6 L0 270.98 L44.43 270.98 L44.43 256.6" class="st3"/>
+			<text x="4.56" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>16 bits</text>		</g>
+		<g id="shape103-113" v:mID="103" v:groupContext="shape" transform="translate(369.583,-90.8555)">
+			<title>Sheet.103</title>
+			<path d="M0 227.76 C0 222.98 3.89 219.1 8.67 219.1 L14.53 219.1 L34.47 205.09 L36.32 219.1 L78.5 219.1 C83.29 219.1 87.16
+						 222.98 87.16 227.76 L87.16 227.76 L87.16 240.73 L87.16 262.34 C87.16 267.12 83.29 270.98 78.5 270.98 L36.32
+						 270.98 L14.53 270.98 L14.53 270.98 L8.67 270.98 C3.89 270.98 0 267.12 0 262.34 L0 240.73 L0 227.76 L0 227.76
+						 Z" class="st6"/>
+		</g>
+		<g id="shape104-115" v:mID="104" v:groupContext="shape" transform="translate(383.264,-114.932)">
+			<title>Sheet.104</title>
+			<desc>CRC32 (32</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="38.2947" cy="263.792" width="76.59" height="14.3829"/>
+			<path d="M76.59 256.6 L0 256.6 L0 270.98 L76.59 270.98 L76.59 256.6" class="st3"/>
+			<text x="8.33" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>CRC32 (32  </text>		</g>
+		<g id="shape105-119" v:mID="105" v:groupContext="shape" transform="translate(386.505,-100.553)">
+			<title>Sheet.105</title>
+			<desc>bit output)</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="32.5584" cy="263.792" width="65.12" height="14.3829"/>
+			<path d="M65.12 256.6 L0 256.6 L0 270.98 L65.12 270.98 L65.12 256.6" class="st3"/>
+			<text x="5.91" y="267.39" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>bit output)</text>		</g>
+		<g id="shape106-123" v:mID="106" v:groupContext="shape" transform="translate(313.397,-18)">
+			<title>Sheet.106</title>
+			<path d="M0 226.35 C0 221.43 4.02 217.42 8.94 217.42 L347.02 217.42 C351.97 217.42 355.96 221.43 355.96 226.35 L355.96
+						 262.06 C355.96 267 351.97 270.98 347.02 270.98 L8.94 270.98 C4.02 270.98 0 267 0 262.06 L0 226.35 Z"
+					class="st6"/>
+		</g>
+		<g id="shape107-125" v:mID="107" v:groupContext="shape" transform="translate(313.98,-41.963)">
+			<title>Sheet.107</title>
+			<desc>Goal is to find a hash_index that produces</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="177.75" cy="260.197" width="355.5" height="21.5726"/>
+			<path d="M355.5 249.41 L0 249.41 L0 270.98 L355.5 270.98 L355.5 249.41" class="st3"/>
+			<text x="9.88" y="265.59" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Goal is to find a hash_index that produces  </text>		</g>
+		<g id="shape108-129" v:mID="108" v:groupContext="shape" transform="translate(318.48,-20.3939)">
+			<title>Sheet.108</title>
+			<desc>a lookup_table with no contradictions</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="175.5" cy="260.197" width="351" height="21.5726"/>
+			<path d="M351 249.41 L0 249.41 L0 270.98 L351 270.98 L351 249.41" class="st3"/>
+			<text x="28.12" y="265.59" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>a lookup_table with no contradictions</text>		</g>
+		<g id="shape109-133" v:mID="109" v:groupContext="shape" transform="translate(18,-196.244)">
+			<title>Sheet.109</title>
+			<path d="M0 250.22 C0 247.92 1.87 246.06 4.16 246.06 L109.18 246.06 C111.47 246.06 113.33 247.92 113.33 250.22 L113.33
+						 266.83 C113.33 269.13 111.47 270.98 109.18 270.98 L4.16 270.98 C1.87 270.98 0 269.13 0 266.83 L0 250.22
+						 Z" class="st1"/>
+		</g>
+		<g id="shape110-135" v:mID="110" v:groupContext="shape" transform="translate(29.8201,-196.244)">
+			<title>Sheet.110</title>
+			<path d="M0 250.22 C-0 247.92 1.67 246.06 3.73 246.06 L97.79 246.06 C99.85 246.06 101.51 247.92 101.51 250.22 L101.51
+						 266.83 C101.51 269.13 99.85 270.98 97.79 270.98 L3.73 270.98 C1.67 270.98 0 269.13 0 266.83 L0 250.22 Z"
+					class="st2"/>
+		</g>
+		<g id="shape111-137" v:mID="111" v:groupContext="shape" transform="translate(32.5663,-199.746)">
+			<title>Sheet.111</title>
+			<desc>Key1: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="50.7562" cy="263.792" width="101.52" height="14.3829"/>
+			<path d="M101.51 256.6 L0 256.6 L0 270.98 L101.51 270.98 L101.51 256.6" class="st3"/>
+			<text x="8.29" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key1: Value = 0</text>		</g>
+		<g id="shape112-141" v:mID="112" v:groupContext="shape" transform="translate(18,-171.44)">
+			<title>Sheet.112</title>
+			<path d="M0 250.22 C0 247.92 1.87 246.06 4.16 246.06 L109.18 246.06 C111.47 246.06 113.33 247.92 113.33 250.22 L113.33
+						 266.83 C113.33 269.13 111.47 270.98 109.18 270.98 L4.16 270.98 C1.87 270.98 0 269.13 0 266.83 L0 250.22
+						 Z" class="st1"/>
+		</g>
+		<g id="shape113-143" v:mID="113" v:groupContext="shape" transform="translate(29.8201,-171.44)">
+			<title>Sheet.113</title>
+			<path d="M0 250.22 C0 247.92 1.67 246.06 3.73 246.06 L97.79 246.06 C99.85 246.06 101.51 247.92 101.51 250.22 L101.51
+						 266.83 C101.51 269.13 99.85 270.98 97.79 270.98 L3.73 270.98 C1.67 270.98 0 269.13 0 266.83 L0 250.22 Z"
+					class="st2"/>
+		</g>
+		<g id="shape114-145" v:mID="114" v:groupContext="shape" transform="translate(32.5663,-174.923)">
+			<title>Sheet.114</title>
+			<desc>Key3: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="50.7562" cy="263.792" width="101.52" height="14.3829"/>
+			<path d="M101.51 256.6 L0 256.6 L0 270.98 L101.51 270.98 L101.51 256.6" class="st3"/>
+			<text x="8.29" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key3: Value = 1</text>		</g>
+		<g id="shape115-149" v:mID="115" v:groupContext="shape" transform="translate(18,-146.396)">
+			<title>Sheet.115</title>
+			<path d="M0 250.12 C0 247.81 1.88 245.94 4.19 245.94 L109.15 245.94 C111.46 245.94 113.33 247.81 113.33 250.12 L113.33
+						 266.81 C113.33 269.12 111.46 270.98 109.15 270.98 L4.19 270.98 C1.88 270.98 0 269.12 0 266.81 L0 250.12
+						 Z" class="st1"/>
+		</g>
+		<g id="shape116-151" v:mID="116" v:groupContext="shape" transform="translate(29.8201,-146.396)">
+			<title>Sheet.116</title>
+			<path d="M0 250.12 C0 247.81 1.68 245.94 3.75 245.94 L97.77 245.94 C99.84 245.94 101.51 247.81 101.51 250.12 L101.51
+						 266.81 C101.51 269.12 99.84 270.98 97.77 270.98 L3.75 270.98 C1.68 270.98 0 269.12 0 266.81 L0 250.12 Z"
+					class="st2"/>
+		</g>
+		<g id="shape117-153" v:mID="117" v:groupContext="shape" transform="translate(32.5663,-149.951)">
+			<title>Sheet.117</title>
+			<desc>Key4: Value = 0</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="50.7562" cy="263.792" width="101.52" height="14.3829"/>
+			<path d="M101.51 256.6 L0 256.6 L0 270.98 L101.51 270.98 L101.51 256.6" class="st3"/>
+			<text x="8.29" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key4: Value = 0</text>		</g>
+		<g id="shape118-157" v:mID="118" v:groupContext="shape" transform="translate(18,-121.831)">
+			<title>Sheet.118</title>
+			<path d="M0 250.12 C0 247.81 1.88 245.94 4.19 245.94 L109.15 245.94 C111.46 245.94 113.33 247.81 113.33 250.12 L113.33
+						 266.81 C113.33 269.12 111.46 270.98 109.15 270.98 L4.19 270.98 C1.88 270.98 0 269.12 0 266.81 L0 250.12
+						 Z" class="st1"/>
+		</g>
+		<g id="shape119-159" v:mID="119" v:groupContext="shape" transform="translate(29.8201,-121.831)">
+			<title>Sheet.119</title>
+			<path d="M0 250.12 C0 247.81 1.68 245.94 3.75 245.94 L97.77 245.94 C99.84 245.94 101.51 247.81 101.51 250.12 L101.51
+						 266.81 C101.51 269.12 99.84 270.98 97.77 270.98 L3.75 270.98 C1.68 270.98 0 269.12 0 266.81 L0 250.12 Z"
+					class="st2"/>
+		</g>
+		<g id="shape120-161" v:mID="120" v:groupContext="shape" transform="translate(32.5663,-125.388)">
+			<title>Sheet.120</title>
+			<desc>Key7: Value = 1</desc>
+			<v:textBlock v:margins="rect(0,0,0,0)"/>
+			<v:textRect cx="50.7562" cy="263.792" width="101.52" height="14.3829"/>
+			<path d="M101.51 256.6 L0 256.6 L0 270.98 L101.51 270.98 L101.51 256.6" class="st3"/>
+			<text x="8.29" y="267.39" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key7: Value = 1</text>		</g>
+		<g id="shape121-165" v:mID="121" v:groupContext="shape" transform="translate(140.517,-148.373)">
+			<title>Sheet.121</title>
+			<path d="M0 236.29 L22.75 236.29 L22.75 224.73 L45.5 247.86 L22.75 270.98 L22.75 259.42 L0 259.42 L0 236.29 Z"
+					class="st6"/>
+		</g>
+	</g>
+</svg>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index ed7f770..7f825cb 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -47,6 +47,7 @@ Programmer's Guide
     link_bonding_poll_mode_drv_lib
     timer_lib
     hash_lib
+    efd_lib
     lpm_lib
     lpm6_lib
     packet_distrib_lib
@@ -167,6 +168,28 @@ Programmer's Guide
 
 :numref:`figure_figure39` :ref:`figure_figure39`
 
+:numref:`figure_efd1` :ref:`figure_efd1`
+
+:numref:`figure_efd2` :ref:`figure_efd2`
+
+:numref:`figure_efd3` :ref:`figure_efd3`
+
+:numref:`figure_efd4` :ref:`figure_efd4`
+
+:numref:`figure_efd5` :ref:`figure_efd5`
+
+:numref:`figure_efd6` :ref:`figure_efd6`
+
+:numref:`figure_efd7` :ref:`figure_efd7`
+
+:numref:`figure_efd8` :ref:`figure_efd8`
+
+:numref:`figure_efd9` :ref:`figure_efd9`
+
+:numref:`figure_efd10` :ref:`figure_efd10`
+
+:numref:`figure_efd11` :ref:`figure_efd11`
+
 
 **Tables**
 
diff --git a/doc/guides/rel_notes/release_17_02.rst b/doc/guides/rel_notes/release_17_02.rst
index 5023038..4c94513 100644
--- a/doc/guides/rel_notes/release_17_02.rst
+++ b/doc/guides/rel_notes/release_17_02.rst
@@ -64,6 +64,9 @@ New Features
   is much smaller than a hash-based flow table and therefore, it can better fit for
   CPU cache, being able to scale to millions of flow keys.
 
+  See the :ref:`Elastic Flow Distributor Library <Efd_Library>` documentation in
+  the Programmers Guide document, for more information.
+
 
 Resolved Issues
 ---------------
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 5/5] doc: add flow distributor guide
From: Pablo de Lara @ 2017-01-12 22:16 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Sameh Gobriel
In-Reply-To: <1484259360-198276-1-git-send-email-pablo.de.lara.guarch@intel.com>

Signed-off-by: Sameh Gobriel <sameh.gobriel@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Christian Maciocco <christian.maciocco@intel.com>
---
 MAINTAINERS                                       |    1 +
 doc/guides/sample_app_ug/flow_distributor.rst     |  494 ++++++++
 doc/guides/sample_app_ug/img/flow_distributor.svg | 1254 +++++++++++++++++++++
 doc/guides/sample_app_ug/index.rst                |    1 +
 4 files changed, 1750 insertions(+)
 create mode 100644 doc/guides/sample_app_ug/flow_distributor.rst
 create mode 100644 doc/guides/sample_app_ug/img/flow_distributor.svg

diff --git a/MAINTAINERS b/MAINTAINERS
index 66e9466..0d3b247 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -535,6 +535,7 @@ F: lib/librte_efd/
 F: doc/guides/prog_guide/efd_lib.rst
 F: app/test/test_efd*
 F: examples/flow_distributor/
+F: doc/guides/sample_app_ug/flow_distributor.rst
 
 Hashes
 M: Bruce Richardson <bruce.richardson@intel.com>
diff --git a/doc/guides/sample_app_ug/flow_distributor.rst b/doc/guides/sample_app_ug/flow_distributor.rst
new file mode 100644
index 0000000..a8cd5f4
--- /dev/null
+++ b/doc/guides/sample_app_ug/flow_distributor.rst
@@ -0,0 +1,494 @@
+..  BSD LICENSE
+    Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of Intel Corporation nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Flow Distributor Sample Application
+===================================
+
+This sample application demonstrates the use of EFD library as a flow-level
+load balancer, for more information about the EFD Library please refer to the
+DPDK programmer's guide.
+
+This sample application is a variant of the
+:ref:`client-server sample application <multi_process_app>`
+where a specific target node is specified for every and each flow
+(not in a round-robin fashion as the original load balancing sample application).
+
+Overview
+--------
+
+The architecture of the EFD flow-based load balancer sample application is
+presented in the following figure.
+
+.. _figure_efd_sample_app_overview:
+
+.. figure:: img/flow_distributor.*
+
+   Using EFD as a Flow-Level Load Balancer
+
+As shown in :numref:`_figure_efd_sample_app_overview`,
+the sample application consists of a front-end node (distributor)
+using the EFD library to create a load-balancing table for flows,
+for each flow a target backend worker node is specified. The EFD table does not
+store the flow key (unlike a regular hash table), and hence, it can
+individually load-balance millions of flows (number of targets * maximum number
+of flows fit in a flow table per target) while still fitting in CPU cache.
+
+It should be noted that although they are referred to as nodes, the frontend
+distributor and worker nodes are processes running on the same platform.
+
+Front-end Distributor
+~~~~~~~~~~~~~~~~~~~~~
+
+Upon initializing, the frontend distributor node (process) creates a flow
+distributor table (based on the EFD library) which is populated with flow
+information and its intended target node.
+
+The sample application assigns a specific target node_id (process) for each of
+the IP destination addresses as follows:
+
+.. code-block:: c
+
+    node_id = i % num_nodes; /* Target node id is generated */
+    ip_dst = rte_cpu_to_be_32(i); /* Specific ip destination address is
+                                     assigned to this target node */
+
+then the pair of <key,target> is inserted into the flow distribution table.
+
+The main loop of the the distributor node receives a burst of packets, then for
+each packet, a flow key (IP destination address) is extracted. The flow
+distributor table is looked up and the target node id is returned.  Packets are
+then enqueued to the specified target node id.
+
+It should be noted that flow distributor table is not a membership test table.
+I.e. if the key has already been inserted the target node id will be correct,
+but for new keys the flow distributor table will return a value (which can be
+valid).
+
+Backend Worker Nodes
+~~~~~~~~~~~~~~~~~~~~
+
+Upon initializing, the worker node (process) creates a flow table (a regular
+hash table that stores the key default size 1M flows) which is populated with
+only the flow information that is serviced at this node. This flow key is
+essential to point out new keys that have not been inserted before.
+
+The worker node's main loop is simply receiving packets then doing a hash table
+lookup. If a match occurs then statistics are updated for flows serviced by
+this node. If no match is found in the local hash table then this indicates
+that this is a new flow, which is dropped.
+
+
+Compiling the Application
+-------------------------
+
+The sequence of steps used to build the application is:
+
+#.  Export the required environment variables:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+#.  Build the application executable file:
+
+    .. code-block:: console
+
+        cd ${RTE_SDK}/examples/flow_distributor/
+        make
+
+    For more details on how to build the DPDK libraries and sample
+    applications,
+    please refer to the *DPDK Getting Started Guide.*
+
+
+Running the Application
+-----------------------
+
+The application has two binaries to be run: the front-end distributor
+and the back-end node.
+
+The frontend distributor (distributor) has the following command line options::
+
+    ./distributor [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS
+
+Where,
+
+* ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure
+* ``-n NUM_NODES:`` Number of back-end nodes that will be used
+* ``-f NUM_FLOWS:`` Number of flows to be added in the EFD table (1 million, by default)
+
+The back-end node (node) has the following command line options::
+
+    ./node [EAL options] -- -n NODE_ID
+
+Where,
+
+* ``-n NODE_ID:`` Node ID, which cannot be equal or higher than NUM_MODES
+
+
+First, the distributor app must be launched, with the number of nodes that will be run.
+Once it has been started, the node instances can be run, with different NODE_ID.
+These instances have to be run as secondary processes, with ``--proc-type=secondary``
+in the EAL options, which will attach to the primary process memory, and therefore,
+they can access the queues created by the primary process to distribute packets.
+
+To successfully run the application, the command line used to start the
+application has to be in sync with the traffic flows configured on the traffic
+generator side.
+
+For examples of application command lines and traffic generator flows, please
+refer to the DPDK Test Report. For more details on how to set up and run the
+sample applications provided with DPDK package, please refer to the
+:ref:`DPDK Getting Started Guide for Linux <linux_gsg>` and
+:ref:`DPDK Getting Started Guide for FreeBSD <freebsd_gsg>`.
+
+
+Explanation
+-----------
+
+As described in previous sections, there are two processes in this example.
+
+The first process, the front-end distributor, creates and populates the EFD table,
+which is used to distribute packets to nodes, which the number of flows
+specified in the command line (1 million, by default).
+
+
+.. code-block:: c
+
+    static void
+    create_flow_distributor_table(void)
+    {
+        uint8_t socket_id = rte_socket_id();
+
+        /* create table */
+        efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
+                        1 << socket_id, socket_id);
+
+        if (efd_table == NULL)
+            rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
+    }
+
+    static void
+    populate_flow_distributor_table(void)
+    {
+        unsigned int i;
+        int32_t ret;
+        uint32_t ip_dst;
+        uint8_t socket_id = rte_socket_id();
+        uint64_t node_id;
+
+        /* Add flows in table */
+        for (i = 0; i < num_flows; i++) {
+            node_id = i % num_nodes;
+
+            ip_dst = rte_cpu_to_be_32(i);
+            ret = rte_efd_update(efd_table, socket_id,
+                            (void *)&ip_dst, (efd_value_t)node_id);
+            if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
+                                    "flow distributor table\n", i);
+        }
+
+        printf("EFD table: Adding 0x%x keys\n", num_flows);
+    }
+
+After initialization, packets are received from the enabled ports, and the IPv4
+address from the packets is used as a key to look up in the EFD table,
+which tells the node where the packet has to be distributed.
+
+.. code-block:: c
+
+    static void
+    process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
+            uint16_t rx_count, unsigned int socket_id)
+    {
+        uint16_t i;
+        uint8_t node;
+        efd_value_t data[EFD_BURST_MAX];
+        const void *key_ptrs[EFD_BURST_MAX];
+
+        struct ipv4_hdr *ipv4_hdr;
+        uint32_t ipv4_dst_ip[EFD_BURST_MAX];
+
+        for (i = 0; i < rx_count; i++) {
+            /* Handle IPv4 header.*/
+            ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
+                    sizeof(struct ether_hdr));
+            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+            key_ptrs[i] = (void *)&ipv4_dst_ip[i];
+        }
+
+        rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
+                    (const void **) key_ptrs, data);
+        for (i = 0; i < rx_count; i++) {
+            node = (uint8_t) ((uintptr_t)data[i]);
+
+            if (node >= num_nodes) {
+                /*
+                 * Node is out of range, which means that
+                 * flow has not been inserted
+                 */
+                flow_dist_stats.drop++;
+                rte_pktmbuf_free(pkts[i]);
+            } else {
+                flow_dist_stats.distributed++;
+                enqueue_rx_packet(node, pkts[i]);
+            }
+        }
+
+        for (i = 0; i < num_nodes; i++)
+            flush_rx_queue(i);
+    }
+
+The burst of packets received is enqueued in temporary buffers (per node),
+and enqueued in the shared ring between the distributor and the node.
+After this, a new burst of packets is received and this process is
+repeated infinitely.
+
+.. code-block:: c
+
+    static void
+    flush_rx_queue(uint16_t node)
+    {
+        uint16_t j;
+        struct node *cl;
+
+        if (cl_rx_buf[node].count == 0)
+            return;
+
+        cl = &nodes[node];
+        if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
+                cl_rx_buf[node].count) != 0){
+            for (j = 0; j < cl_rx_buf[node].count; j++)
+                rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+            cl->stats.rx_drop += cl_rx_buf[node].count;
+        } else
+            cl->stats.rx += cl_rx_buf[node].count;
+
+        cl_rx_buf[node].count = 0;
+    }
+
+The second process, the back-end node, receives the packets from the shared
+ring with the distributor and send them out, if they belong to the node.
+
+At initialization, it attaches to the distributor process memory, to have
+access to the shared ring, parameters and statistics.
+
+.. code-block:: c
+
+    rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
+    if (rx_ring == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
+                "is distributor process running?\n");
+
+    mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+    if (mp == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
+
+    mz = rte_memzone_lookup(MZ_SHARED_INFO);
+    if (mz == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
+    info = mz->addr;
+    tx_stats = &(info->tx_stats[node_id]);
+    filter_stats = &(info->filter_stats[node_id]);
+
+Then, the hash table that contains the flows that will be handled
+by the node is created and populated.
+
+.. code-block:: c
+
+    static struct rte_hash *
+    create_hash_table(const struct shared_info *info)
+    {
+        uint32_t num_flows_node = info->num_flows / info->num_nodes;
+        char name[RTE_HASH_NAMESIZE];
+        struct rte_hash *h;
+
+        /* create table */
+        struct rte_hash_parameters hash_params = {
+            .entries = num_flows_node * 2, /* table load = 50% */
+            .key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
+            .socket_id = rte_socket_id(),
+            .hash_func_init_val = 0,
+        };
+
+        snprintf(name, sizeof(name), "hash_table_%d", node_id);
+        hash_params.name = name;
+        h = rte_hash_create(&hash_params);
+
+        if (h == NULL)
+            rte_exit(EXIT_FAILURE,
+                    "Problem creating the hash table for node %d\n",
+                    node_id);
+        return h;
+    }
+
+    static void
+    populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
+    {
+        unsigned int i;
+        int32_t ret;
+        uint32_t ip_dst;
+        uint32_t num_flows_node = 0;
+        uint64_t target_node;
+
+        /* Add flows in table */
+        for (i = 0; i < info->num_flows; i++) {
+            target_node = i % info->num_nodes;
+            if (target_node != node_id)
+                continue;
+
+            ip_dst = rte_cpu_to_be_32(i);
+
+            ret = rte_hash_add_key(h, (void *) &ip_dst);
+            if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Unable to add entry %u "
+                        "in hash table\n", i);
+            else
+                num_flows_node++;
+
+        }
+
+        printf("Hash table: Adding 0x%x keys\n", num_flows_node);
+    }
+
+After initialization, packets are dequeued from the shared ring
+(from the distributor) and, like in the distributor process,
+the IPv4 address from the packets is used as a key to look up in the hash table.
+If there is a hit, packet is stored in a buffer, to be eventually transmitted
+in one of the enabled ports. If key is not there, packet is dropped, since the
+flow is not handled by the node.
+
+.. code-block:: c
+
+    static inline void
+    handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
+    {
+        struct ipv4_hdr *ipv4_hdr;
+        uint32_t ipv4_dst_ip[PKT_READ_SIZE];
+        const void *key_ptrs[PKT_READ_SIZE];
+        unsigned int i;
+        int32_t positions[PKT_READ_SIZE] = {0};
+
+        for (i = 0; i < num_packets; i++) {
+            /* Handle IPv4 header.*/
+            ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
+                    sizeof(struct ether_hdr));
+            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+            key_ptrs[i] = &ipv4_dst_ip[i];
+        }
+        /* Check if packets belongs to any flows handled by this node */
+        rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
+
+        for (i = 0; i < num_packets; i++) {
+            if (likely(positions[i] >= 0)) {
+                filter_stats->passed++;
+                transmit_packet(bufs[i]);
+            } else {
+                filter_stats->drop++;
+                /* Drop packet, as flow is not handled by this node */
+                rte_pktmbuf_free(bufs[i]);
+            }
+        }
+    }
+
+Finally, note that both processes updates statistics, such as transmitted, received
+and dropped packets, which are shown and refreshed by the distributor app.
+
+.. code-block:: c
+
+    static void
+    do_stats_display(void)
+    {
+        unsigned int i, j;
+        const char clr[] = {27, '[', '2', 'J', '\0'};
+        const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
+        uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
+        uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
+
+        /* to get TX stats, we need to do some summing calculations */
+        memset(port_tx, 0, sizeof(port_tx));
+        memset(port_tx_drop, 0, sizeof(port_tx_drop));
+        memset(node_tx, 0, sizeof(node_tx));
+        memset(node_tx_drop, 0, sizeof(node_tx_drop));
+
+        for (i = 0; i < num_nodes; i++) {
+            const struct tx_stats *tx = &info->tx_stats[i];
+
+            for (j = 0; j < info->num_ports; j++) {
+                const uint64_t tx_val = tx->tx[info->id[j]];
+                const uint64_t drop_val = tx->tx_drop[info->id[j]];
+
+                port_tx[j] += tx_val;
+                port_tx_drop[j] += drop_val;
+                node_tx[i] += tx_val;
+                node_tx_drop[i] += drop_val;
+            }
+        }
+
+        /* Clear screen and move to top left */
+        printf("%s%s", clr, topLeft);
+
+        printf("PORTS\n");
+        printf("-----\n");
+        for (i = 0; i < info->num_ports; i++)
+            printf("Port %u: '%s'\t", (unsigned int)info->id[i],
+                    get_printable_mac_addr(info->id[i]));
+        printf("\n\n");
+        for (i = 0; i < info->num_ports; i++) {
+            printf("Port %u - rx: %9"PRIu64"\t"
+                    "tx: %9"PRIu64"\n",
+                    (unsigned int)info->id[i], info->rx_stats.rx[i],
+                    port_tx[i]);
+        }
+
+        printf("\nFLOW DISTRIBUTOR\n");
+        printf("-----\n");
+        printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
+                flow_dist_stats.distributed, flow_dist_stats.drop);
+
+        printf("\nNODES\n");
+        printf("-------\n");
+        for (i = 0; i < num_nodes; i++) {
+            const unsigned long long rx = nodes[i].stats.rx;
+            const unsigned long long rx_drop = nodes[i].stats.rx_drop;
+            const struct filter_stats *filter = &info->filter_stats[i];
+
+            printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
+                    "            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
+                    "            filter_passed: %9"PRIu64", "
+                    "filter_drop: %9"PRIu64"\n",
+                    i, rx, rx_drop, node_tx[i], node_tx_drop[i],
+                    filter->passed, filter->drop);
+        }
+
+        printf("\n");
+    }
diff --git a/doc/guides/sample_app_ug/img/flow_distributor.svg b/doc/guides/sample_app_ug/img/flow_distributor.svg
new file mode 100644
index 0000000..9aee30b
--- /dev/null
+++ b/doc/guides/sample_app_ug/img/flow_distributor.svg
@@ -0,0 +1,1254 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export efd_i6.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.2496in" height="5.89673in"
+		viewBox="0 0 593.971 424.565" xml:space="preserve" color-interpolation-filters="sRGB" class="st27">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<style type="text/css">
+	<![CDATA[
+		.st1 {visibility:visible}
+		.st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+		.st4 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+		.st5 {fill:#feffff;font-family:Calibri;font-size:0.75em}
+		.st6 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st7 {fill:none;stroke:#2e75b5;stroke-width:2.25}
+		.st8 {fill:#305497;stroke:#2e75b5;stroke-width:1}
+		.st9 {fill:#feffff;font-family:Calibri;font-size:0.833336em;font-weight:bold}
+		.st10 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2)}
+		.st11 {fill:#5b9bd5}
+		.st12 {stroke:#c7c8c8;stroke-width:0.25}
+		.st13 {fill:#acccea;stroke:#c7c8c8;stroke-width:0.25}
+		.st14 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st15 {fill:#ed7d31;stroke:#c7c8c8;stroke-width:0.25}
+		.st16 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+		.st17 {marker-end:url(#mrkr5-212);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st18 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st19 {fill:none;stroke:#2e75b5;stroke-width:1}
+		.st20 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+		.st21 {fill:none;stroke:none;stroke-width:0.25}
+		.st22 {font-size:1em}
+		.st23 {fill:#ffffff}
+		.st24 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st25 {marker-end:url(#mrkr5-444);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st26 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st27 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+	]]>
+	</style>
+
+	<defs id="Markers">
+		<g id="lend5">
+			<path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+		</g>
+		<marker id="mrkr5-212" class="st18" v:arrowType="5" v:arrowSize="2" v:setback="5.8" refX="-5.8" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+		</marker>
+		<marker id="mrkr5-444" class="st26" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<title>Page-1</title>
+		<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+		<g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(319.501,-335.688)">
+			<title>Rectangle.58</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow3-2" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape4-7" v:mID="4" v:groupContext="shape" transform="translate(353.251,-335.688)">
+			<title>Rectangle.59</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow4-8" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(400.501,-335.688)">
+			<title>Rectangle.60</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow5-14" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(434.251,-335.688)">
+			<title>Rectangle.61</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow6-20" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(481.501,-335.688)">
+			<title>Rectangle.62</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow7-26" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape8-30" v:mID="8" v:groupContext="shape" transform="translate(515.251,-335.688)">
+			<title>Rectangle.63</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow8-31" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape9-35" v:mID="9" v:groupContext="shape" transform="translate(319.501,-313.188)">
+			<title>Rectangle.64</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow9-36" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape10-40" v:mID="10" v:groupContext="shape" transform="translate(353.251,-313.188)">
+			<title>Rectangle.65</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow10-41" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape11-45" v:mID="11" v:groupContext="shape" transform="translate(400.501,-313.188)">
+			<title>Rectangle.66</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow11-46" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape12-50" v:mID="12" v:groupContext="shape" transform="translate(434.251,-313.188)">
+			<title>Rectangle.67</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow12-51" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape13-55" v:mID="13" v:groupContext="shape" transform="translate(481.501,-313.188)">
+			<title>Rectangle.68</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow13-56" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape14-60" v:mID="14" v:groupContext="shape" transform="translate(515.251,-313.188)">
+			<title>Rectangle.69</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow14-61" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(319.501,-277.188)">
+			<title>Rectangle.70</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow15-66" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(353.251,-277.188)">
+			<title>Rectangle.71</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow16-72" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape17-77" v:mID="17" v:groupContext="shape" transform="translate(400.501,-277.188)">
+			<title>Rectangle.72</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow17-78" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape18-83" v:mID="18" v:groupContext="shape" transform="translate(434.251,-277.188)">
+			<title>Rectangle.73</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow18-84" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape19-89" v:mID="19" v:groupContext="shape" transform="translate(481.501,-277.188)">
+			<title>Rectangle.74</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow19-90" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape20-95" v:mID="20" v:groupContext="shape" transform="translate(515.251,-277.188)">
+			<title>Rectangle.75</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow20-96" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape21-101" v:mID="21" v:groupContext="shape" transform="translate(319.501,-240.687)">
+			<title>Rectangle.76</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow21-102" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape22-106" v:mID="22" v:groupContext="shape" transform="translate(353.251,-240.687)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow22-107" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape23-111" v:mID="23" v:groupContext="shape" transform="translate(400.501,-240.687)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow23-112" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape24-116" v:mID="24" v:groupContext="shape" transform="translate(434.251,-240.687)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow24-117" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape25-121" v:mID="25" v:groupContext="shape" transform="translate(481.501,-240.687)">
+			<title>Rectangle.80</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow25-122" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape26-127" v:mID="26" v:groupContext="shape" transform="translate(515.251,-240.687)">
+			<title>Rectangle.81</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow26-128" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape27-133" v:mID="27" v:groupContext="shape" transform="translate(317.251,-231.687)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow27-134" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape28-138" v:mID="28" v:groupContext="shape" transform="translate(328.501,-362.688)">
+			<title>Sheet.28</title>
+			<desc>Local Table for N Specific Flows Serviced at Node 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.77" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node 1</text>		</g>
+		<g id="group34-141" transform="translate(66.0294,-165.569)" v:mID="34" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Device)"/>
+				<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Load balancer)"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Load balancer</title>
+			<g id="shape35-142" v:mID="35" v:groupContext="shape" transform="translate(0,-7.33146)">
+				<title>Sheet.35</title>
+				<g id="shadow35-143" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st10"/>
+					<path d="M0 377.86 L72 377.86" class="st6"/>
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st6"/>
+				</g>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st11"/>
+				<path d="M0 377.86 L72 377.86" class="st12"/>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st12"/>
+			</g>
+			<g id="shape36-152" v:mID="36" v:groupContext="shape" transform="translate(8.03054,-12.9324)">
+				<title>Sheet.36</title>
+				<g id="shadow36-153" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97
+								 413.34 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83
+								 L51.34 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37
+								 L38.13 400.48 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16
+								 L46.49 392.01 ZM27.71 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42
+								 27.71 415.42 C32.75 415.42 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71
+								 400.04 C31.15 400.04 33.96 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54
+								 21.46 409.74 21.46 406.29 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56
+								 L11.6 407.56 L8.62 410.51 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z"
+							class="st2"/>
+				</g>
+				<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97 413.34
+							 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83 L51.34
+							 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37 L38.13 400.48
+							 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16 L46.49 392.01 ZM27.71
+							 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42 27.71 415.42 C32.75 415.42
+							 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71 400.04 C31.15 400.04 33.96
+							 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54 21.46 409.74 21.46 406.29
+							 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56 L11.6 407.56 L8.62 410.51
+							 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z" class="st13"/>
+			</g>
+		</g>
+		<g id="shape37-157" v:mID="37" v:groupContext="shape" transform="translate(21.0294,-45.4375)">
+			<title>Rectangle</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow37-158" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="336.433" width="135" height="88.1315" class="st2"/>
+			</g>
+			<rect x="0" y="336.433" width="135" height="88.1315" class="st3"/>
+		</g>
+		<g id="shape38-162" v:mID="38" v:groupContext="shape" transform="translate(34.693,-126.438)">
+			<title>Sheet.38</title>
+			<desc>EFD Table</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="49.3364" cy="415.565" width="98.68" height="18"/>
+			<rect x="0" y="406.565" width="98.6728" height="18" class="st8"/>
+			<text x="24.87" y="419.17" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EFD Table</text>		</g>
+		<g id="shape39-165" v:mID="39" v:groupContext="shape" transform="translate(30.0294,-99.4375)">
+			<title>Rectangle.39</title>
+			<desc>Group_id</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow39-166" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="7.87" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group_id</text>		</g>
+		<g id="shape40-171" v:mID="40" v:groupContext="shape" transform="translate(93.193,-99.4375)">
+			<title>Rectangle.40</title>
+			<desc>Hash index</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow40-172" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="4.64" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash index</text>		</g>
+		<g id="shape41-177" v:mID="41" v:groupContext="shape" transform="translate(30.193,-82.4275)">
+			<title>Rectangle.41</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow41-178" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape42-182" v:mID="42" v:groupContext="shape" transform="translate(30.193,-66.8125)">
+			<title>Rectangle.42</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow42-183" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape43-187" v:mID="43" v:groupContext="shape" transform="translate(30.1112,-52.1875)">
+			<title>Rectangle.43</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow43-188" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape44-192" v:mID="44" v:groupContext="shape" transform="translate(93.0294,-81.4375)">
+			<title>Rectangle.44</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow44-193" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape45-197" v:mID="45" v:groupContext="shape" transform="translate(93.193,-66.8125)">
+			<title>Rectangle.45</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow45-198" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape46-202" v:mID="46" v:groupContext="shape" transform="translate(93.193,-52.1875)">
+			<title>Rectangle.46</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow46-203" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape47-207" v:mID="47" v:groupContext="shape" transform="translate(374.924,544.022) rotate(135)">
+			<title>Sheet.47</title>
+			<path d="M-0 417.75 A40.674 18.0151 -156.2 0 0 40.24 422.15 L40.49 421.89" class="st17"/>
+		</g>
+		<g id="shape48-213" v:mID="48" v:groupContext="shape" transform="translate(21.0294,-19)">
+			<title>Sheet.48</title>
+			<desc>Supports X*N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="19.05" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports X*N Flows</text>		</g>
+		<g id="shape49-216" v:mID="49" v:groupContext="shape" transform="translate(48.0294,-229.938)">
+			<title>Sheet.49</title>
+			<desc>Frontend Server or Load Balancer</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="400.94" width="108" height="47.25"/>
+			<rect x="0" y="377.315" width="108" height="47.25" class="st21"/>
+			<text x="14.56" y="397.34" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Frontend Server<v:newlineChar/><tspan
+						x="13.16" dy="1.2em" class="st22">or Load Balancer </tspan> </text>		</g>
+		<g id="group51-220" transform="translate(223.876,-310.938)" v:mID="51" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server</title>
+			<g id="shape52-221" v:mID="52" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.52</title>
+				<g id="shadow52-222" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape53-226" v:mID="53" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.53</title>
+				<g id="shadow53-227" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape54-231" v:mID="54" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.54</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow54-232" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape59-239" v:mID="59" v:groupContext="shape" transform="translate(277.876,-373.938)">
+			<title>Sheet.59</title>
+			<path d="M-0 424.56 A111.108 53.2538 42.31 0 1 93.83 421.21 L94.14 421.41" class="st17"/>
+		</g>
+		<g id="shape60-244" v:mID="60" v:groupContext="shape" transform="translate(205.876,-283.938)">
+			<title>Sheet.60</title>
+			<desc>Backend Server 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 1</text>		</g>
+		<g id="group61-247" transform="translate(223.876,-207.438)" v:mID="61" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.61</title>
+			<g id="shape62-248" v:mID="62" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.62</title>
+				<g id="shadow62-249" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape63-253" v:mID="63" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.63</title>
+				<g id="shadow63-254" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape64-258" v:mID="64" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.64</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow64-259" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape65-266" v:mID="65" v:groupContext="shape" transform="translate(205.876,-180.437)">
+			<title>Sheet.65</title>
+			<desc>Backend Server 2</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 2</text>		</g>
+		<g id="group66-269" transform="translate(219.029,-58.9375)" v:mID="66" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.66</title>
+			<g id="shape67-270" v:mID="67" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.67</title>
+				<g id="shadow67-271" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape68-275" v:mID="68" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.68</title>
+				<g id="shadow68-276" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape69-280" v:mID="69" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.69</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow69-281" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+						transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape70-288" v:mID="70" v:groupContext="shape" transform="translate(201.029,-26.056)">
+			<title>Sheet.70</title>
+			<desc>Backend Server X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.86" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server X</text>		</g>
+		<g id="shape71-291" v:mID="71" v:groupContext="shape" transform="translate(684.44,239.627) rotate(90)">
+			<title>Sheet.71</title>
+			<path d="M0 424.56 L45 424.56" class="st24"/>
+		</g>
+		<g id="shape72-294" v:mID="72" v:groupContext="shape" transform="translate(6.85967,-22.443) rotate(-38.1076)">
+			<title>Sheet.72</title>
+			<path d="M-0 424.56 A96.1331 44.4001 55.03 0 1 68.24 420.56 L68.51 420.79" class="st17"/>
+		</g>
+		<g id="shape73-299" v:mID="73" v:groupContext="shape" transform="translate(328.501,-135.937)">
+			<title>Rectangle.73</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow73-300" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape74-305" v:mID="74" v:groupContext="shape" transform="translate(362.251,-135.937)">
+			<title>Rectangle.74</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow74-306" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape75-311" v:mID="75" v:groupContext="shape" transform="translate(409.501,-135.937)">
+			<title>Rectangle.75</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow75-312" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape76-317" v:mID="76" v:groupContext="shape" transform="translate(443.251,-135.937)">
+			<title>Rectangle.76</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow76-318" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape77-323" v:mID="77" v:groupContext="shape" transform="translate(490.501,-135.937)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow77-324" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape78-328" v:mID="78" v:groupContext="shape" transform="translate(524.251,-135.937)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow78-329" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape79-333" v:mID="79" v:groupContext="shape" transform="translate(328.501,-113.437)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow79-334" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape80-338" v:mID="80" v:groupContext="shape" transform="translate(362.251,-113.437)">
+			<title>Rectangle.80</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow80-339" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape81-343" v:mID="81" v:groupContext="shape" transform="translate(409.501,-113.437)">
+			<title>Rectangle.81</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow81-344" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape82-348" v:mID="82" v:groupContext="shape" transform="translate(443.251,-113.437)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow82-349" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape83-353" v:mID="83" v:groupContext="shape" transform="translate(490.501,-113.437)">
+			<title>Rectangle.83</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow83-354" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape84-358" v:mID="84" v:groupContext="shape" transform="translate(524.251,-113.437)">
+			<title>Rectangle.84</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow84-359" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape85-363" v:mID="85" v:groupContext="shape" transform="translate(328.501,-77.4375)">
+			<title>Rectangle.85</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow85-364" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape86-369" v:mID="86" v:groupContext="shape" transform="translate(362.251,-77.4375)">
+			<title>Rectangle.86</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow86-370" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape87-375" v:mID="87" v:groupContext="shape" transform="translate(409.501,-77.4375)">
+			<title>Rectangle.87</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow87-376" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape88-381" v:mID="88" v:groupContext="shape" transform="translate(443.251,-77.4375)">
+			<title>Rectangle.88</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow88-382" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape89-387" v:mID="89" v:groupContext="shape" transform="translate(490.501,-77.4375)">
+			<title>Rectangle.89</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow89-388" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape90-393" v:mID="90" v:groupContext="shape" transform="translate(524.251,-77.4375)">
+			<title>Rectangle.90</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow90-394" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape91-399" v:mID="91" v:groupContext="shape" transform="translate(328.501,-40.9375)">
+			<title>Rectangle.91</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow91-400" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape92-404" v:mID="92" v:groupContext="shape" transform="translate(362.251,-40.9375)">
+			<title>Rectangle.92</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow92-405" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape93-409" v:mID="93" v:groupContext="shape" transform="translate(409.501,-40.9375)">
+			<title>Rectangle.93</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow93-410" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape94-414" v:mID="94" v:groupContext="shape" transform="translate(443.251,-40.9375)">
+			<title>Rectangle.94</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow94-415" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape95-419" v:mID="95" v:groupContext="shape" transform="translate(490.501,-40.9375)">
+			<title>Rectangle.95</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow95-420" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape96-425" v:mID="96" v:groupContext="shape" transform="translate(524.251,-40.9375)">
+			<title>Rectangle.96</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow96-426" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape97-431" v:mID="97" v:groupContext="shape" transform="translate(326.251,-31.9375)">
+			<title>Rectangle.97</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow97-432" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+					transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape98-436" v:mID="98" v:groupContext="shape" transform="translate(337.501,-162.938)">
+			<title>Sheet.98</title>
+			<desc>Local Table for N Specific Flows Serviced at Node X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.55" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node X</text>		</g>
+		<g id="shape99-439" v:mID="99" v:groupContext="shape" transform="translate(-204.342,-29.4449) rotate(-53.7462)">
+			<title>Sheet.99</title>
+			<path d="M0 424.56 L160.37 424.56" class="st25"/>
+		</g>
+		<g id="shape100-445" v:mID="100" v:groupContext="shape" transform="translate(-37.6568,-164.882) rotate(-24.444)">
+			<title>Sheet.100</title>
+			<path d="M0 424.56 L101.71 424.56" class="st25"/>
+		</g>
+		<g id="shape101-450" v:mID="101" v:groupContext="shape" transform="translate(464.049,-50.8578) rotate(50.099)">
+			<title>Sheet.101</title>
+			<path d="M0 424.56 L139.8 424.56" class="st25"/>
+		</g>
+		<g id="shape102-455" v:mID="102" v:groupContext="shape" transform="translate(372.376,-207.438)">
+			<title>Sheet.102</title>
+			<desc>Supports N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="25.15" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports N Flows</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 775e2f7..260f6a5 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -57,6 +57,7 @@ Sample Applications User Guides
     l3_forward_virtual
     link_status_intr
     load_balancer
+    flow_distributor
     multi_process
     qos_metering
     qos_scheduler
-- 
2.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox