dev.dpdk.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/2] net/tap RSS BPF rewrite
@ 2024-01-30  3:46 Stephen Hemminger
  2024-01-30  3:46 ` [RFC 1/2] tap: stop "vendoring" linux bpf headers Stephen Hemminger
                   ` (12 more replies)
  0 siblings, 13 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-01-30  3:46 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

This is a early (alpha) view of my recent work to
to update (gut job) of the RSS handling in the
tap device. The rework was so big that it did not
make sense to do it in incremental stages.

Overall it comes out much simpler and cleaner.
Much more testing is needed, at this point it will
load the program and try and setup filter (but fails).

Stephen Hemminger (2):
  tap: stop "vendoring" linux bpf headers
  tap: rework BPF handling

 .gitignore                            |     3 -
 drivers/net/tap/bpf/.gitignore        |     2 +
 drivers/net/tap/bpf/Makefile          |    21 +-
 drivers/net/tap/bpf/README            |    12 +
 drivers/net/tap/bpf/bpf_api.h         |   276 -
 drivers/net/tap/bpf/bpf_elf.h         |    53 -
 drivers/net/tap/bpf/bpf_extract.py    |    86 -
 drivers/net/tap/bpf/tap_bpf_program.c |   255 -
 drivers/net/tap/bpf/tap_rss.c         |   269 +
 drivers/net/tap/meson.build           |    26 +-
 drivers/net/tap/rte_eth_tap.c         |     2 +
 drivers/net/tap/rte_eth_tap.h         |     9 +-
 drivers/net/tap/tap_bpf.h             |   121 -
 drivers/net/tap/tap_bpf_api.c         |   190 -
 drivers/net/tap/tap_bpf_insns.h       |  1743 ----
 drivers/net/tap/tap_flow.c            |   530 +-
 drivers/net/tap/tap_flow.h            |    11 +-
 drivers/net/tap/tap_rss.h             |    14 +-
 drivers/net/tap/tap_rss.skel.h        | 11625 ++++++++++++++++++++++++
 drivers/net/tap/tap_rss.stub.h        |    45 +
 20 files changed, 12137 insertions(+), 3156 deletions(-)
 create mode 100644 drivers/net/tap/bpf/.gitignore
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h
 create mode 100644 drivers/net/tap/tap_rss.skel.h
 create mode 100644 drivers/net/tap/tap_rss.stub.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [RFC 1/2] tap: stop "vendoring" linux bpf headers
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
@ 2024-01-30  3:46 ` Stephen Hemminger
  2024-01-30  3:46 ` [RFC 2/2] tap: rework BPF handling Stephen Hemminger
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-01-30  3:46 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF. This is not
a supportable build method, and not how rest of DPDK works.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

Since DPDK officially supports only LTS or later kernel
there is no need for the #ifdef workarounds in the TAP flow
code. Cloning headers leads to problems and no longer needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   1 -
 drivers/net/tap/tap_flow.c         |  89 ---------------------
 5 files changed, 13 insertions(+), 219 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b809f..73c4dafe4eca 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111fe0..000000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917ed..9e05e2ddf19b 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6b0..88aec6885a06 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,7 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
 
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index ed4d42f92f9f..a5d38ee7c46c 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -18,95 +18,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
 
 /* RSS key management */
 enum bpf_rss_key_e {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [RFC 2/2] tap: rework BPF handling
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
  2024-01-30  3:46 ` [RFC 1/2] tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-01-30  3:46 ` Stephen Hemminger
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-01-30  3:46 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Key points:
    - works with current kernels requiring BTF support[1]
    - use libbpf for interactions with kernel
      (no longer need the python extraction code)
    - no longer needs to process packets twice;
      the BPF reclassifier step is not needed
    - does error checking on RSS flow parameters
    - supports setting RSS key per flow (never done in original code)
    - supports L3 only hash (original code was broken)
    - supports IPv4 options and IPv6 extension header
    - BPF program is only loaded once and not modified,
      tc classid is used to find configuration
    - remove unused code and fields
    - code rewritten and commented for clarity

[1] This is based of the BPF map work in earlier patch
    from Madhuker Mythri <madhuker.mythri@oracle.com>

Expect multiple checkpatch errors because it contains non RTE
code (the BPF program) and autogenerated code from bpftool.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |     3 -
 drivers/net/tap/bpf/.gitignore        |     2 +
 drivers/net/tap/bpf/Makefile          |    21 +-
 drivers/net/tap/bpf/README            |    12 +
 drivers/net/tap/bpf/bpf_api.h         |   276 -
 drivers/net/tap/bpf/bpf_elf.h         |    53 -
 drivers/net/tap/bpf/bpf_extract.py    |    85 -
 drivers/net/tap/bpf/tap_bpf_program.c |   255 -
 drivers/net/tap/bpf/tap_rss.c         |   269 +
 drivers/net/tap/meson.build           |    26 +-
 drivers/net/tap/rte_eth_tap.c         |     2 +
 drivers/net/tap/rte_eth_tap.h         |     9 +-
 drivers/net/tap/tap_bpf_api.c         |   196 -
 drivers/net/tap/tap_bpf_insns.h       |  1742 ----
 drivers/net/tap/tap_flow.c            |   443 +-
 drivers/net/tap/tap_flow.h            |    11 +-
 drivers/net/tap/tap_rss.h             |    14 +-
 drivers/net/tap/tap_rss.skel.h        | 11625 ++++++++++++++++++++++++
 drivers/net/tap/tap_rss.stub.h        |    45 +
 19 files changed, 12138 insertions(+), 2951 deletions(-)
 create mode 100644 drivers/net/tap/bpf/.gitignore
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h
 create mode 100644 drivers/net/tap/tap_rss.skel.h
 create mode 100644 drivers/net/tap/tap_rss.stub.h

diff --git a/.gitignore b/.gitignore
index 3f444dcace2e..01a47a760660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/.gitignore b/drivers/net/tap/bpf/.gitignore
new file mode 100644
index 000000000000..8ae453adf290
--- /dev/null
+++ b/drivers/net/tap/bpf/.gitignore
@@ -0,0 +1,2 @@
+# ignore the BPF object file
+tap_rss.o
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
index 9efeeb1bc704..c963a088e58e 100644
--- a/drivers/net/tap/bpf/Makefile
+++ b/drivers/net/tap/bpf/Makefile
@@ -2,18 +2,21 @@
 # This file is not built as part of normal DPDK build.
 # It is used to generate the eBPF code for TAP RSS.
 
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
+CLANG = clang
+BPFTOOL = /usr/sbin/bpftool
+CLANG_OPTS = -O2 -Wall -Wextra
+TARGET = ../tap_rss.skel.h
+
+CLANG_BPF_SYS_INCLUDES ?= $(shell $(CLANG) -v -E - </dev/null 2>&1 \
+	| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')
 
 all: $(TARGET)
 
 clean:
-	rm tap_bpf_program.o $(TARGET)
+	rm tap_rss.o $(TARGET)
 
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
+$(TARGET): tap_rss.o
+	$(BPFTOOL) gen skeleton $< > $@
 
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
+tap_rss.o: tap_rss.c
+	$(CLANG) $(CLANG_OPTS) $(CLANG_BPF_SYS_INCLUDES) -target bpf -c $< -g -o $@
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 000000000000..960a10da73b8
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,12 @@
+This is the BPF program used to implement the RSS across queues
+flow action. It works like the skbedit tc filter but instead of mapping
+to only one queues, it maps to multiple queues based on RSS hash.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+- requires libbpf version XX or later
+- rebuilding the BPF requires clang and bpftool
+- only Toeplitz hash with standard 40 byte key is supported
+- the number of queues per RSS action is limited to 16
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 2638a8a4ac9a..000000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	({								\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c0f..000000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4eca..000000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c30..000000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 000000000000..43bd6cca673e
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,269 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <stdbool.h>
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows
+ * which need BPF RSS.
+ *
+ * The hash is indexed by the tc_index.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u16));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+static bool __attribute__((always_inline))
+is_ipv4_fragment(const struct iphdr *iph)
+{
+	return (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0;
+}
+
+/* Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* Get ports for non-fragmented TCP/UDP */
+	if (is_ipv4_fragment(&iph) ||
+	    !(iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP)) {
+		return 0;
+	} else {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off,
+						&src_dst_port, sizeof(src_dst_port), BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+}
+
+/* parse ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh), BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh), BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	if (frag || !(proto == IPPROTO_UDP || proto == IPPROTO_TCP)) {
+		return 0;
+	} else {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+	}
+
+	return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/* scale value to be into range [0, n), assumes val is large */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/* layout of qdisc skb cb (from sch_generic.h) */
+struct qdisc_skb_cb {
+	struct {
+		unsigned int	pkt_len;
+		__u16		slave_dev_queue_mapping;
+		__u16		tc_classid;
+	};
+#define QDISC_CB_PRIV_LEN 20
+	unsigned char		data[QDISC_CB_PRIV_LEN];
+};
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ */
+SEC("tc/ingress") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	char fmt[] = "rss_flow_action classid:%u\n";
+	__u16 classid;
+	__u32 hash;
+
+	/* TC layer puts the BPF_CLASSID into the skb cb area */
+	classid = ((const struct qdisc_skb_cb *)skb->cb)->tc_classid;
+	bpf_trace_printk(fmt, sizeof(fmt), classid);
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &classid);
+	if (rsskey == NULL) {
+		bpf_printk("hash(): rss not configured");
+		return TC_ACT_OK;
+	}
+
+	hash = calculate_rss_hash(skb, rsskey);
+	bpf_printk("hash %u\n", hash);
+	if (hash) {
+		/* Fold hash to the number of queues configured */
+		skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+		bpf_printk("queue %u\n", skb->queue_mapping);
+		return TC_ACT_PIPE;
+	}
+	return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff11b..52e0fde3b06c 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,21 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
+bpf_dep = dependency('libbpf', required: false, method: 'pkg-config')
+if bpf_dep.found()
+    message('drivers/tap: RSS support (bpf)')
+    cflags += '-DHAVE_LIBBPF'
+    ext_deps += bpf_dep
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
-
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b41fa971cb7e..a98cc8f01ae1 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1138,6 +1138,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1959,6 +1960,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e961..0cf2b30bb03b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@ struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf19b..000000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index 88aec6885a06..000000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1742 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a5d38ee7c46c..b9184cd1c9ff 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,27 +11,25 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#pragma GCC diagnostic push
+#ifdef HAVE_LIBBPF
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#else
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include "tap_rss.stub.h"
+#endif
+#pragma GCC diagnostic pop
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -39,8 +37,7 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
+	uint16_t flowid;
 	struct nlmsg msg;
 };
 
@@ -70,7 +67,7 @@ struct action_data {
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
-			int bpf_fd;
+			uint16_t classid;
 			const char *annotation;
 		} bpf;
 	};
@@ -110,10 +107,7 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
@@ -827,7 +821,8 @@ tap_flow_item_validate(const struct rte_flow_item *item,
  *   -1 on failure, 0 on success
  */
 static int
-add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
+add_action(struct rte_flow *flow, struct pmd_internals *pmd,
+	   size_t *act_index, struct action_data *adata)
 {
 	struct nlmsg *msg = &flow->msg;
 
@@ -856,13 +851,18 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
 			     adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
-		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
+		struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
+
+		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, bpf_program__fd(rss_prog));
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
 			   adata->bpf.annotation);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+		tap_nlattr_add(&msg->nh, TCA_BPF_CLASSID,
+			       sizeof(adata->bpf.classid),
+			       &adata->bpf.classid);
 	} else {
 		return -1;
 	}
@@ -890,7 +890,8 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
  *   -1 on failure, 0 on success
  */
 static int
-add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
+add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
+	    int nb_actions, struct action_data *data,
 	    int classifier_action)
 {
 	struct nlmsg *msg = &flow->msg;
@@ -900,7 +901,7 @@ add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
 	if (tap_nlattr_nested_start(msg, classifier_action) < 0)
 		return -1;
 	for (i = 0; i < nb_actions; i++)
-		if (add_action(flow, &act_index, data + i) < 0)
+		if (add_action(flow, pmd,  &act_index, data + i) < 0)
 			return -1;
 	tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
 	return 0;
@@ -1060,7 +1061,7 @@ priv_flow_process(struct pmd_internals *pmd,
 			adata.mirred.action = TC_ACT_PIPE;
 		else
 			adata.mirred.action = TC_ACT_STOLEN;
-		if (add_actions(flow, 1, &adata, TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, pmd, 1, &adata, TCA_FLOWER_ACT) < 0)
 			goto exit_action_not_supported;
 		else
 			goto end;
@@ -1083,7 +1084,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
+				err = add_actions(flow, pmd, 1, &adata,
 						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
@@ -1099,7 +1100,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
+				err = add_actions(flow, pmd, 1, &adata,
 						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
@@ -1124,8 +1125,8 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-					TCA_FLOWER_ACT);
+				err = add_actions(flow, pmd, 1, &adata,
+						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
@@ -1135,8 +1136,8 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_action_not_supported;
 			}
@@ -1239,23 +1240,14 @@ tap_flow_set_handle(struct rte_flow *flow)
 static void
 tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
 {
-	int i;
+	struct tap_rss *rss = pmd->rss;
 
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map, &flow->flowid,
+				     sizeof(flow->flowid), 0);
 
 	/* Free flow allocated memory */
 	rte_free(flow);
@@ -1723,13 +1715,16 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd)
+{
+	if (pmd->rss == NULL)
+		return;
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+}
 
 /**
  * Enable RSS on tap: create TC rules for queuing.
@@ -1745,225 +1740,76 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
+	return 0;
 }
 
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
 
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
+/* Choose next flow id to use for BPF action */
+static int tap_rss_flow_assign(struct pmd_internals *pmd, uint16_t *flow_id)
+{
+	struct rte_flow *flow;
+	uint16_t id;
 
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
+	id = pmd->bpf_flowid;
 
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
+next_id:
+	/* Skip 0xffff and 0 as id's */
+	if (++id == UINT16_MAX)
+		id = 1;
 
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
+	/* Wrapped around, all id's have been used */
+	if (id == pmd->bpf_flowid)
+		return -1;
 
-	default:
-		break;
+	/* Make sure this id has not been used already */
+	for (flow = LIST_FIRST(&pmd->flows); flow; flow = LIST_NEXT(flow, next)) {
+		if (flow->flowid == id)
+			goto next_id;
 	}
 
-	return err;
+	/* Record starting point for next time */
+	pmd->bpf_flowid = id;
+	*flow_id = id;
+	return 0;
 }
 
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -1982,11 +1828,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -1998,31 +1844,69 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
+
+	/* Choose new flow id, which is used as index into the BPF map */
+	err = tap_rss_flow_assign(pmd, &flow->flowid);
 	if (err < 0) {
 		rte_flow_error_set(
 			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
+			"Failed to get BPF flowid");
 
 		return -1;
 	}
 
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
 
 	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
-
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &flow->flowid, sizeof(uint16_t),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
 			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			flow->flowid, errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2031,33 +1915,14 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
 	/* Actions */
 	{
 		struct action_data adata[] = {
 			{
 				.id = "bpf",
 				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
+					.annotation = "tap_rss",
+					.classid = flow->flowid,
 					.bpf = {
 						.action = TC_ACT_PIPE,
 					},
@@ -2065,8 +1930,8 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			},
 		};
 
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, pmd, RTE_DIM(adata), adata,
+				TCA_FLOWER_ACT) < 0)
 			return -1;
 	}
 
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfaef..41f9833619a1 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,6 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +40,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +52,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f94..51b7ff0d007e 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -9,6 +9,9 @@
 #define TAP_MAX_QUEUES 16
 #endif
 
+/* Size of the map from BPF classid to queue table */
+#define TAP_RSS_MAX	TAP_MAX_QUEUES
+
 /* Fixed RSS hash key size in bytes. */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
@@ -21,20 +24,13 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
diff --git a/drivers/net/tap/tap_rss.skel.h b/drivers/net/tap/tap_rss.skel.h
new file mode 100644
index 000000000000..16b396f84919
--- /dev/null
+++ b/drivers/net/tap/tap_rss.skel.h
@@ -0,0 +1,11625 @@
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+
+/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
+#ifndef __TAP_RSS_SKEL_H__
+#define __TAP_RSS_SKEL_H__
+
+#include <errno.h>
+#include <stdlib.h>
+#include <bpf/libbpf.h>
+
+struct tap_rss {
+	struct bpf_object_skeleton *skeleton;
+	struct bpf_object *obj;
+	struct {
+		struct bpf_map *rss_map;
+		struct bpf_map *rodata_str1_1;
+		struct bpf_map *rodata;
+	} maps;
+	struct {
+		struct bpf_program *rss_flow_action;
+	} progs;
+	struct {
+		struct bpf_link *rss_flow_action;
+	} links;
+
+#ifdef __cplusplus
+	static inline struct tap_rss *open(const struct bpf_object_open_opts *opts = nullptr);
+	static inline struct tap_rss *open_and_load();
+	static inline int load(struct tap_rss *skel);
+	static inline int attach(struct tap_rss *skel);
+	static inline void detach(struct tap_rss *skel);
+	static inline void destroy(struct tap_rss *skel);
+	static inline const void *elf_bytes(size_t *sz);
+#endif /* __cplusplus */
+};
+
+static void
+tap_rss__destroy(struct tap_rss *obj)
+{
+	if (!obj)
+		return;
+	if (obj->skeleton)
+		bpf_object__destroy_skeleton(obj->skeleton);
+	free(obj);
+}
+
+static inline int
+tap_rss__create_skeleton(struct tap_rss *obj);
+
+static inline struct tap_rss *
+tap_rss__open_opts(const struct bpf_object_open_opts *opts)
+{
+	struct tap_rss *obj;
+	int err;
+
+	obj = (struct tap_rss *)calloc(1, sizeof(*obj));
+	if (!obj) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	err = tap_rss__create_skeleton(obj);
+	if (err)
+		goto err_out;
+
+	err = bpf_object__open_skeleton(obj->skeleton, opts);
+	if (err)
+		goto err_out;
+
+	return obj;
+err_out:
+	tap_rss__destroy(obj);
+	errno = -err;
+	return NULL;
+}
+
+static inline struct tap_rss *
+tap_rss__open(void)
+{
+	return tap_rss__open_opts(NULL);
+}
+
+static inline int
+tap_rss__load(struct tap_rss *obj)
+{
+	return bpf_object__load_skeleton(obj->skeleton);
+}
+
+static inline struct tap_rss *
+tap_rss__open_and_load(void)
+{
+	struct tap_rss *obj;
+	int err;
+
+	obj = tap_rss__open();
+	if (!obj)
+		return NULL;
+	err = tap_rss__load(obj);
+	if (err) {
+		tap_rss__destroy(obj);
+		errno = -err;
+		return NULL;
+	}
+	return obj;
+}
+
+static inline int
+tap_rss__attach(struct tap_rss *obj)
+{
+	return bpf_object__attach_skeleton(obj->skeleton);
+}
+
+static inline void
+tap_rss__detach(struct tap_rss *obj)
+{
+	bpf_object__detach_skeleton(obj->skeleton);
+}
+
+static inline const void *tap_rss__elf_bytes(size_t *sz);
+
+static inline int
+tap_rss__create_skeleton(struct tap_rss *obj)
+{
+	struct bpf_object_skeleton *s;
+	int err;
+
+	s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));
+	if (!s)	{
+		err = -ENOMEM;
+		goto err;
+	}
+
+	s->sz = sizeof(*s);
+	s->name = "tap_rss";
+	s->obj = &obj->obj;
+
+	/* maps */
+	s->map_cnt = 3;
+	s->map_skel_sz = sizeof(*s->maps);
+	s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);
+	if (!s->maps) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	s->maps[0].name = "rss_map";
+	s->maps[0].map = &obj->maps.rss_map;
+
+	s->maps[1].name = ".rodata.str1.1";
+	s->maps[1].map = &obj->maps.rodata_str1_1;
+
+	s->maps[2].name = "tap_rss.rodata";
+	s->maps[2].map = &obj->maps.rodata;
+
+	/* programs */
+	s->prog_cnt = 1;
+	s->prog_skel_sz = sizeof(*s->progs);
+	s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
+	if (!s->progs) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	s->progs[0].name = "rss_flow_action";
+	s->progs[0].prog = &obj->progs.rss_flow_action;
+	s->progs[0].link = &obj->links.rss_flow_action;
+
+	s->data = (void *)tap_rss__elf_bytes(&s->data_sz);
+
+	obj->skeleton = s;
+	return 0;
+err:
+	bpf_object__destroy_skeleton(s);
+	return err;
+}
+
+static inline const void *tap_rss__elf_bytes(size_t *sz)
+{
+	*sz = 301248;
+	return (const void *)"\
+\x7f\x45\x4c\x46\x02\x01\x01\0\0\0\0\0\0\0\0\0\x01\0\xf7\0\x01\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x40\x91\x04\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x1e\0\
+\x01\0\xbf\x17\0\0\0\0\0\0\xb7\x01\0\0\x25\x75\x0a\0\x63\x1a\xc8\xff\0\0\0\0\
+\x18\x01\0\0\x63\x6c\x61\x73\0\0\0\0\x73\x69\x64\x3a\x7b\x1a\xc0\xff\0\0\0\0\
+\x18\x01\0\0\x5f\x61\x63\x74\0\0\0\0\x69\x6f\x6e\x20\x7b\x1a\xb8\xff\0\0\0\0\
+\x18\x01\0\0\x72\x73\x73\x5f\0\0\0\0\x66\x6c\x6f\x77\x7b\x1a\xb0\xff\0\0\0\0\
+\x69\x73\x36\0\0\0\0\0\x6b\x3a\xae\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\
+\xb0\xff\xff\xff\xb7\x02\0\0\x1c\0\0\0\x85\0\0\0\x06\0\0\0\xbf\xa2\0\0\0\0\0\0\
+\x07\x02\0\0\xae\xff\xff\xff\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x01\
+\0\0\0\x55\0\x06\0\0\0\0\0\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\x02\0\0\x1b\
+\0\0\0\x85\0\0\0\x06\0\0\0\xb7\x07\0\0\0\0\0\0\x05\0\xb9\x1e\0\0\0\0\xbf\x02\0\
+\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\x07\x03\0\0\x04\0\0\0\x61\x71\x10\0\0\0\0\0\x15\
+\x01\x08\0\x08\0\0\0\x15\x01\xeb\x02\x86\xdd\0\0\xb7\x07\0\0\0\0\0\0\x18\x01\0\
+\0\x1b\0\0\0\0\0\0\0\0\0\0\0\xb7\x02\0\0\x09\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\
+\0\x06\0\0\0\x05\0\xac\x1e\0\0\0\0\x7b\x3a\x98\xff\0\0\0\0\x7b\x0a\x78\xff\0\0\
+\0\0\x71\x26\x03\0\0\0\0\0\x71\x29\x02\0\0\0\0\0\x71\x28\0\0\0\0\0\0\xbf\x71\0\
+\0\0\0\0\0\x7b\x2a\x80\xff\0\0\0\0\x71\x27\x01\0\0\0\0\0\xb7\x02\0\0\0\0\0\0\
+\x7b\x2a\x90\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd8\xff\xff\xff\x7b\
+\x1a\x88\xff\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
+\0\0\0\x55\0\x7d\x1e\0\0\0\0\x67\x07\0\0\x08\0\0\0\x4f\x87\0\0\0\0\0\0\x67\x09\
+\0\0\x10\0\0\0\x67\x06\0\0\x18\0\0\0\x4f\x96\0\0\0\0\0\0\x4f\x76\0\0\0\0\0\0\
+\x61\xa8\xe8\xff\0\0\0\0\xdc\x08\0\0\x20\0\0\0\x61\xa9\xe4\xff\0\0\0\0\xdc\x09\
+\0\0\x20\0\0\0\x57\x06\0\0\x01\0\0\0\x15\x06\xae\x0d\0\0\0\0\xb7\x05\0\0\0\0\0\
+\0\x79\xa4\x78\xff\0\0\0\0\xbf\x41\0\0\0\0\0\0\x07\x01\0\0\x08\0\0\0\xbf\x92\0\
+\0\0\0\0\0\x57\x02\0\0\0\0\0\x40\x15\x02\x07\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\
+\x61\x25\0\0\0\0\0\0\x67\x05\0\0\x01\0\0\0\x61\x12\0\0\0\0\0\0\x77\x02\0\0\x1f\
+\0\0\0\x57\x02\0\0\x01\0\0\0\x4f\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\
+\0\0\0\0\x20\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\
+\x67\x02\0\0\x02\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x1e\0\0\0\x57\x03\0\0\
+\x03\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\
+\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x10\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\
+\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x03\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\
+\x1d\0\0\0\x57\x03\0\0\x07\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\
+\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x08\x15\x02\x09\0\0\0\0\
+\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x04\0\0\0\x61\x13\0\
+\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\x57\x03\0\0\x0f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\
+\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x04\
+\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\
+\x05\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\x03\0\0\x1f\0\0\0\x4f\
+\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\
+\x57\x02\0\0\0\0\0\x02\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\
+\0\0\0\0\0\x67\x02\0\0\x06\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x1a\0\0\0\x57\
+\x03\0\0\x3f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\
+\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x01\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\
+\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x07\0\0\0\x61\x13\0\0\0\0\0\0\x77\
+\x03\0\0\x19\0\0\0\x57\x03\0\0\x7f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\
+\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\x80\0\x15\x02\x09\0\
+\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x61\
+\x13\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\xff\0\0\0\x4f\x32\0\0\0\0\0\
+\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\
+\x40\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\
+\x02\0\0\x09\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\x03\0\0\xff\
+\x01\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\
+\0\0\0\0\0\x57\x02\0\0\0\0\x20\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\
+\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x0a\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x16\
+\0\0\0\x57\x03\0\0\xff\x03\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\
+\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\x10\0\x15\x02\x09\0\0\0\0\0\
+\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x0b\0\0\0\x61\x13\0\0\
+\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\xff\x07\0\0\x4f\x32\0\0\0\0\0\0\xaf\
+\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\x08\0\
+\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\
+\x0c\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\xff\x0f\0\0\
+\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\
+\0\x57\x02\0\0\0\0\x04\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\
+\0\0\0\0\0\0\x67\x02\0\0\x0d\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x13\0\0\0\
+\x57\x03\0\0\xff\x1f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\
+\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\x02\0\x15\x02\x09\0\0\0\0\0\x79\xa2\
+\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x0e\0\0\0\x61\x13\0\0\0\0\0\0\
+\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\xff\x3f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\
+\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\0\x01\0\x15\x02\
+\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x0f\0\0\
+\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\xff\x7f\0\0\x4f\x32\0\
+\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\
+\0\0\0\x80\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\
+\0\x67\x02\0\0\x10\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x10\0\0\0\x57\x03\0\0\
+\xff\xff\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x92\0\0\0\0\0\0\x57\x02\0\0\0\x40\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\
+\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x11\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\
+\0\x0f\0\0\0\x57\x03\0\0\xff\xff\x01\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\
+\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\x20\0\0\x15\x02\x09\0\0\
+\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x12\0\0\0\x61\
+\x13\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\xff\xff\x03\0\x4f\x32\0\0\0\
+\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\
+\0\x10\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\
+\x67\x02\0\0\x13\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x0d\0\0\0\x57\x03\0\0\
+\xff\xff\x07\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x92\0\0\0\0\0\0\x57\x02\0\0\0\x08\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\
+\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x14\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\
+\0\x0c\0\0\0\x57\x03\0\0\xff\xff\x0f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\
+\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\0\x04\0\0\x15\x02\x09\0\0\
+\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x15\0\0\0\x61\
+\x13\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\xff\xff\x1f\0\x4f\x32\0\0\0\
+\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\
+\0\x02\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\
+\x67\x02\0\0\x16\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x0a\0\0\0\x57\x03\0\0\
+\xff\xff\x3f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x92\0\0\0\0\0\0\x57\x02\0\0\0\x01\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\
+\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x17\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\
+\0\x09\0\0\0\x57\x03\0\0\xff\xff\x7f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\
+\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\x80\0\0\0\x15\x02\x09\0\0\
+\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x18\0\0\0\x61\
+\x13\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\xff\xff\xff\0\x4f\x32\0\0\0\
+\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\
+\x40\0\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\
+\x67\x02\0\0\x19\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x07\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x01\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\
+\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\
+\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x1a\0\0\0\x61\x13\0\0\0\0\0\0\x77\
+\x03\0\0\x06\0\0\0\x57\x03\0\0\xff\xff\xff\x03\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\
+\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\x15\x02\
+\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x1b\0\0\
+\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\x03\0\0\xff\xff\xff\x07\x4f\
+\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\
+\x57\x02\0\0\x08\0\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\
+\0\0\0\0\0\x67\x02\0\0\x1c\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x04\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x0f\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\
+\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\x02\x09\0\0\0\0\0\x79\xa2\
+\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x1d\0\0\0\x61\x13\0\0\0\0\0\0\
+\x77\x03\0\0\x03\0\0\0\x57\x03\0\0\xff\xff\xff\x1f\x4f\x32\0\0\0\0\0\0\xaf\x52\
+\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\
+\x02\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x1e\
+\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x02\0\0\0\x57\x03\0\0\xff\xff\xff\x3f\
+\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\x57\x09\0\0\x01\0\
+\0\0\x15\x09\x09\0\0\0\0\0\x79\xa2\x98\xff\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\
+\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\
+\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\x07\x04\0\
+\0\x0c\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x40\x15\x02\x08\0\0\0\0\0\
+\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x01\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1f\
+\0\0\0\x57\x03\0\0\x01\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\
+\0\0\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x20\x15\x02\x08\0\0\0\0\0\x61\
+\x12\0\0\0\0\0\0\x67\x02\0\0\x02\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1e\0\0\
+\0\x57\x03\0\0\x03\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\
+\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x10\x15\x02\x08\0\0\0\0\0\x61\x12\
+\0\0\0\0\0\0\x67\x02\0\0\x03\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1d\0\0\0\
+\x57\x03\0\0\x07\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\
+\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x08\x15\x02\x08\0\0\0\0\0\x61\x12\0\
+\0\0\0\0\0\x67\x02\0\0\x04\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\x57\
+\x03\0\0\x0f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\
+\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x04\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\
+\0\0\0\x67\x02\0\0\x05\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\x03\
+\0\0\x1f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x02\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x06\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x1a\0\0\0\x57\x03\0\0\
+\x3f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x82\
+\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x01\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\
+\x67\x02\0\0\x07\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x19\0\0\0\x57\x03\0\0\
+\x7f\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x82\
+\0\0\0\0\0\0\x57\x02\0\0\0\0\x80\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\
+\x67\x02\0\0\x08\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\
+\xff\0\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\x82\
+\0\0\0\0\0\0\x57\x02\0\0\0\0\x40\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\
+\x67\x02\0\0\x09\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\x03\0\0\
+\xff\x01\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x20\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0a\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x16\0\0\0\x57\x03\0\0\
+\xff\x03\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x10\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0b\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\
+\xff\x07\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x08\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0c\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\
+\xff\x0f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x04\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0d\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x13\0\0\0\x57\x03\0\0\
+\xff\x1f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x02\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0e\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\
+\xff\x3f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\0\x01\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x0f\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\
+\xff\x7f\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x80\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x10\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x10\0\0\0\x57\x03\0\0\
+\xff\xff\0\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x40\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x11\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0f\0\0\0\x57\x03\0\0\
+\xff\xff\x01\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x20\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x12\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\
+\xff\xff\x03\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x10\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x13\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0d\0\0\0\x57\x03\0\0\
+\xff\xff\x07\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x08\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x14\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0c\0\0\0\x57\x03\0\0\
+\xff\xff\x0f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x04\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x15\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\
+\xff\xff\x1f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x02\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x16\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x0a\0\0\0\x57\x03\0\0\
+\xff\xff\x3f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\0\x01\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x17\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x09\0\0\0\x57\x03\0\0\
+\xff\xff\x7f\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\x80\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x18\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\
+\xff\xff\xff\0\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\xbf\
+\x82\0\0\0\0\0\0\x57\x02\0\0\x40\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\
+\0\x67\x02\0\0\x19\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x07\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x01\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\0\
+\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\
+\0\0\0\x67\x02\0\0\x1a\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x06\0\0\0\x57\x03\
+\0\0\xff\xff\xff\x03\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\0\0\
+\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\
+\0\0\0\0\x67\x02\0\0\x1b\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x07\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\0\0\
+\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x12\
+\0\0\0\0\0\0\x67\x02\0\0\x1c\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x04\0\0\0\
+\x57\x03\0\0\xff\xff\xff\x0f\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\0\
+\0\0\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\x02\x08\0\0\0\0\0\x61\
+\x12\0\0\0\0\0\0\x67\x02\0\0\x1d\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x03\0\0\
+\0\x57\x03\0\0\xff\xff\xff\x1f\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x25\
+\0\0\0\0\0\0\xbf\x82\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\x02\x08\0\0\0\0\0\
+\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1e\0\0\0\x61\x43\0\0\0\0\0\0\x77\x03\0\0\x02\
+\0\0\0\x57\x03\0\0\xff\xff\xff\x3f\x4f\x32\0\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\
+\x25\0\0\0\0\0\0\x7b\x5a\x90\xff\0\0\0\0\x57\x08\0\0\x01\0\0\0\x15\x08\xae\x1b\
+\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x42\0\0\0\0\0\0\x05\0\
+\xe0\x0a\0\0\0\0\x7b\x3a\x98\xff\0\0\0\0\x7b\x0a\x78\xff\0\0\0\0\x71\x26\x03\0\
+\0\0\0\0\xbf\x71\0\0\0\0\0\0\x71\x27\x02\0\0\0\0\0\x71\x28\0\0\0\0\0\0\x7b\x2a\
+\x80\xff\0\0\0\0\x71\x29\x01\0\0\0\0\0\xb7\x02\0\0\0\0\0\0\x7b\x2a\x90\xff\0\0\
+\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd8\xff\xff\xff\x7b\x1a\x88\xff\0\0\0\0\
+\xb7\x04\0\0\x28\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\x99\x1b\
+\0\0\0\0\x67\x09\0\0\x08\0\0\0\x4f\x89\0\0\0\0\0\0\x67\x07\0\0\x10\0\0\0\x67\
+\x06\0\0\x18\0\0\0\x4f\x76\0\0\0\0\0\0\x4f\x96\0\0\0\0\0\0\x61\xa1\xfc\xff\0\0\
+\0\0\xdc\x01\0\0\x20\0\0\0\x7b\x1a\x68\xff\0\0\0\0\x61\xa1\xec\xff\0\0\0\0\xdc\
+\x01\0\0\x20\0\0\0\x7b\x1a\x70\xff\0\0\0\0\x61\xa0\xf8\xff\0\0\0\0\xdc\0\0\0\
+\x20\0\0\0\x61\xa1\xe8\xff\0\0\0\0\xdc\x01\0\0\x20\0\0\0\x7b\x1a\xa0\xff\0\0\0\
+\0\x61\xa1\xf4\xff\0\0\0\0\xdc\x01\0\0\x20\0\0\0\x7b\x1a\x58\xff\0\0\0\0\x61\
+\xa7\xe4\xff\0\0\0\0\xdc\x07\0\0\x20\0\0\0\x61\xa1\xf0\xff\0\0\0\0\xdc\x01\0\0\
+\x20\0\0\0\x7b\x1a\x60\xff\0\0\0\0\x61\xa9\xe0\xff\0\0\0\0\xdc\x09\0\0\x20\0\0\
+\0\x57\x06\0\0\x04\0\0\0\x15\x06\xd3\x0e\0\0\0\0\x79\xa2\x78\xff\0\0\0\0\x07\
+\x02\0\0\x08\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x40\xb7\x08\0\0\0\0\0\
+\0\x79\xa4\x98\xff\0\0\0\0\x15\x01\x06\0\0\0\0\0\x61\x48\0\0\0\0\0\0\x67\x08\0\
+\0\x01\0\0\0\x61\x21\0\0\0\0\0\0\x77\x01\0\0\x1f\0\0\0\x57\x01\0\0\x01\0\0\0\
+\x4f\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x20\x79\xa6\x58\xff\
+\0\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\x02\0\0\0\x61\
+\x23\0\0\0\0\0\0\x77\x03\0\0\x1e\0\0\0\x57\x03\0\0\x03\0\0\0\x4f\x31\0\0\0\0\0\
+\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\
+\0\x10\x79\xa5\x60\xff\0\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\
+\x01\0\0\x03\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1d\0\0\0\x57\x03\0\0\x07\0\
+\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\
+\0\0\0\x57\x01\0\0\0\0\0\x08\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\
+\0\0\x04\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\x57\x03\0\0\x0f\0\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\0\x04\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x05\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\x03\0\0\x1f\0\0\0\x4f\
+\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x02\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x06\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1a\0\0\0\x57\x03\0\0\x3f\0\0\0\x4f\
+\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x01\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x07\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x19\0\0\0\x57\x03\0\0\x7f\0\0\0\x4f\
+\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\x80\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x08\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\xff\0\0\0\x4f\
+\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\x40\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x09\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\x03\0\0\xff\x01\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x20\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0a\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x16\0\0\0\x57\x03\0\0\xff\x03\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x10\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0b\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\xff\x07\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x08\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\xff\x0f\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x04\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0d\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x13\0\0\0\x57\x03\0\0\xff\x1f\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x02\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0e\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\xff\x3f\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x01\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x0f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\xff\x7f\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x80\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x10\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x10\0\0\0\x57\x03\0\0\xff\xff\0\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x40\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x11\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0f\0\0\0\x57\x03\0\0\xff\xff\x01\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x20\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x12\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\xff\xff\x03\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x10\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x13\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0d\0\0\0\x57\x03\0\0\xff\xff\x07\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x08\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x14\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0c\0\0\0\x57\x03\0\0\xff\xff\x0f\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x04\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x15\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\xff\xff\x1f\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x02\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x16\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0a\0\0\0\x57\x03\0\0\xff\xff\x3f\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\0\x01\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x17\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x09\0\0\0\x57\x03\0\0\xff\xff\x7f\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\x80\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x18\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\xff\xff\xff\0\
+\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\
+\0\x57\x01\0\0\x40\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\
+\x19\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x07\0\0\0\x57\x03\0\0\xff\xff\xff\
+\x01\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\
+\0\0\0\x57\x01\0\0\x20\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\
+\0\0\x1a\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x06\0\0\0\x57\x03\0\0\xff\xff\
+\xff\x03\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\
+\0\0\0\0\0\x57\x01\0\0\x10\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\
+\x01\0\0\x1b\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\x03\0\0\xff\
+\xff\xff\x07\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\x08\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x1c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x04\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x0f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x04\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\
+\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x03\0\0\0\x57\x03\
+\0\0\xff\xff\xff\x1f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\
+\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x02\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\
+\0\0\0\0\x67\x01\0\0\x1e\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x02\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x3f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\x57\x09\0\0\x01\0\0\0\x15\x09\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\
+\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\
+\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\x79\xa1\
+\x78\xff\0\0\0\0\x07\x01\0\0\x0c\0\0\0\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\0\0\0\
+\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x14\0\
+\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x20\
+\x79\xa9\x70\xff\0\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x02\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x03\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x04\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x05\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x06\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x07\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x08\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x09\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x10\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x11\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x12\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x13\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x14\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x15\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x16\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x17\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x18\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x19\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\
+\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\
+\0\0\x1a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\
+\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\
+\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\
+\x03\0\0\x1b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\
+\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x73\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x1c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\
+\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x57\x07\0\0\x01\0\0\0\x15\x07\x08\0\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\
+\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\
+\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\x79\xa7\
+\x78\xff\0\0\0\0\xbf\x72\0\0\0\0\0\0\x07\x02\0\0\x10\0\0\0\x79\xa3\xa0\xff\0\0\
+\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\
+\0\x01\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x02\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x03\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x04\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x05\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x06\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x07\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x08\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x09\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\
+\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\
+\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\
+\x03\0\0\x0a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\
+\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\
+\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\
+\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\
+\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x0c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\
+\0\0\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\
+\0\0\0\0\0\x67\x03\0\0\x0d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\
+\x04\0\0\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x13\
+\0\0\0\0\0\0\x67\x03\0\0\x0e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\
+\x57\x04\0\0\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\
+\x13\0\0\0\0\0\0\x67\x03\0\0\x0f\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\
+\0\x57\x04\0\0\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\
+\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x10\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x10\
+\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\
+\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x11\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\
+\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\
+\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\
+\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x12\0\0\0\x61\x24\0\0\0\0\0\0\x77\
+\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x13\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x08\0\0\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x14\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x04\
+\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x15\0\0\0\x61\x24\0\
+\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\
+\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x16\0\0\0\x61\
+\x24\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x43\0\0\0\
+\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\
+\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x17\0\0\0\
+\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x43\0\
+\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\
+\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x18\0\
+\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\
+\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x19\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\
+\xff\0\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x1a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\
+\0\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x13\0\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\
+\0\x57\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\
+\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\
+\x03\0\0\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\
+\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\
+\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x24\0\0\0\0\0\0\x77\
+\x04\0\0\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x01\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\
+\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\
+\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x71\0\0\0\0\0\0\x07\x01\0\0\x14\0\0\0\
+\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\
+\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x02\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\
+\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x03\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\
+\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x04\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\
+\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x05\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\
+\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x06\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\
+\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x07\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\
+\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x08\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\
+\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x93\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x09\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\
+\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\
+\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\
+\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\
+\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\
+\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\
+\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\
+\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x10\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\
+\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x11\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\
+\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x12\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\
+\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x13\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\
+\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x14\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\
+\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x15\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\
+\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x16\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\
+\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x17\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\
+\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x18\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\
+\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x93\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x19\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\
+\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\
+\0\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\
+\x57\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\
+\0\0\0\0\0\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x23\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\
+\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\xbf\x93\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x02\
+\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\
+\x38\0\0\0\0\0\0\x57\x09\0\0\x01\0\0\0\x15\x09\x08\0\0\0\0\0\x61\x22\0\0\0\0\0\
+\0\x67\x02\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\
+\xbf\x72\0\0\0\0\0\0\x07\x02\0\0\x18\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\
+\0\x40\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x24\
+\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\
+\x20\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x02\0\0\0\x61\x24\0\
+\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x03\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x04\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x05\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x06\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x07\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x08\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x09\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0a\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0b\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0c\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0d\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0e\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0f\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x10\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\
+\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\
+\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x11\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\
+\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x12\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x13\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x14\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x15\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x16\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x17\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x18\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x19\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\x10\0\
+\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x24\0\
+\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\
+\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\x08\
+\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x24\
+\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\
+\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\0\
+\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\
+\x24\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\
+\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x53\0\0\0\0\0\0\x57\x03\0\
+\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\
+\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\
+\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x57\x05\0\0\x01\0\0\0\x15\
+\x05\x08\0\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\
+\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\
+\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x71\0\0\0\0\0\0\x07\x01\0\0\x1c\0\0\0\
+\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\
+\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x02\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\
+\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x03\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\
+\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x04\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\
+\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x05\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\
+\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x06\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\
+\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x07\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\
+\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x08\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\
+\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x09\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\
+\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\
+\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\
+\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\
+\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\
+\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\
+\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\
+\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x10\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\
+\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x11\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\
+\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x12\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\
+\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x13\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\
+\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x14\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\
+\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x15\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\
+\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x16\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\
+\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x17\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\
+\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x18\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\
+\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x19\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\
+\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\
+\0\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\
+\x57\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\
+\0\0\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x23\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\
+\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x02\
+\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\
+\x38\0\0\0\0\0\0\x57\x06\0\0\x01\0\0\0\x15\x06\x08\0\0\0\0\0\x61\x22\0\0\0\0\0\
+\0\x67\x02\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\
+\xbf\x72\0\0\0\0\0\0\x07\x02\0\0\x20\0\0\0\xbf\x03\0\0\0\0\0\0\x57\x03\0\0\0\0\
+\0\x40\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x24\
+\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\x57\x03\0\0\0\0\0\
+\x20\x79\xa6\x68\xff\0\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x02\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x03\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x04\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x05\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x06\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x07\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x08\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x09\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0f\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x10\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x11\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x12\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x13\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x14\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x15\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x16\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x17\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x18\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\0\0\
+\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x19\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\0\0\
+\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x1a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\
+\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x03\0\
+\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\
+\x03\0\0\x1b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\
+\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x03\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x1c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x03\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x03\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\
+\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x57\0\0\0\x01\0\0\0\x15\0\x08\0\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\
+\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\xff\
+\x7f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\x07\x07\0\0\
+\x24\0\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x40\x15\x01\x08\0\0\0\0\0\x61\
+\x21\0\0\0\0\0\0\x67\x01\0\0\x01\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1f\0\0\
+\0\x57\x03\0\0\x01\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x20\x15\x01\x08\0\0\0\0\0\x61\x21\
+\0\0\0\0\0\0\x67\x01\0\0\x02\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1e\0\0\0\
+\x57\x03\0\0\x03\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\
+\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x10\x15\x01\x08\0\0\0\0\0\x61\x21\0\
+\0\0\0\0\0\x67\x01\0\0\x03\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1d\0\0\0\x57\
+\x03\0\0\x07\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x08\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\
+\0\0\0\x67\x01\0\0\x04\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\x57\x03\
+\0\0\x0f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x04\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x05\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\x03\0\0\
+\x1f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x61\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x02\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\
+\x67\x01\0\0\x06\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x1a\0\0\0\x57\x03\0\0\
+\x3f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x61\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x01\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\
+\x67\x01\0\0\x07\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x19\0\0\0\x57\x03\0\0\
+\x7f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x61\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\x80\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\
+\x67\x01\0\0\x08\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\
+\xff\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x61\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\x40\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\
+\x67\x01\0\0\x09\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\x03\0\0\
+\xff\x01\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x20\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0a\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x16\0\0\0\x57\x03\0\0\
+\xff\x03\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x10\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0b\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\
+\xff\x07\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x08\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0c\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\
+\xff\x0f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x04\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0d\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x13\0\0\0\x57\x03\0\0\
+\xff\x1f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x02\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0e\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\
+\xff\x3f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\0\x01\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x0f\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\
+\xff\x7f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x80\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x10\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x10\0\0\0\x57\x03\0\0\
+\xff\xff\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x40\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x11\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0f\0\0\0\x57\x03\0\0\
+\xff\xff\x01\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x20\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x12\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\
+\xff\xff\x03\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x10\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x13\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0d\0\0\0\x57\x03\0\0\
+\xff\xff\x07\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x08\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x14\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0c\0\0\0\x57\x03\0\0\
+\xff\xff\x0f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x04\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x15\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\
+\xff\xff\x1f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x02\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x16\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x0a\0\0\0\x57\x03\0\0\
+\xff\xff\x3f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\0\x01\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x17\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x09\0\0\0\x57\x03\0\0\
+\xff\xff\x7f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\x80\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x18\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\
+\xff\xff\xff\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x61\0\0\0\0\0\0\x57\x01\0\0\x40\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x19\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x07\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x01\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\x20\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\
+\0\0\0\x67\x01\0\0\x1a\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x06\0\0\0\x57\x03\
+\0\0\xff\xff\xff\x03\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\
+\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\x10\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\
+\0\0\0\0\x67\x01\0\0\x1b\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x07\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\x08\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\
+\0\0\0\0\0\0\x67\x01\0\0\x1c\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x04\0\0\0\
+\x57\x03\0\0\xff\xff\xff\x0f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\
+\0\0\0\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\x04\0\0\0\x15\x01\x08\0\0\0\0\0\x61\
+\x21\0\0\0\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x03\0\0\
+\0\x57\x03\0\0\xff\xff\xff\x1f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\
+\0\0\0\0\0\0\xbf\x61\0\0\0\0\0\0\x57\x01\0\0\x02\0\0\0\x15\x01\x08\0\0\0\0\0\
+\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1e\0\0\0\x61\x73\0\0\0\0\0\0\x77\x03\0\0\x02\
+\0\0\0\x57\x03\0\0\xff\xff\xff\x3f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\
+\x18\0\0\0\0\0\0\x7b\x8a\x90\xff\0\0\0\0\xbf\x75\0\0\0\0\0\0\x57\x06\0\0\x01\0\
+\0\0\x15\x06\xcd\x10\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x52\
+\0\0\0\0\0\0\x77\x02\0\0\x01\0\0\0\x57\x02\0\0\xff\xff\xff\x7f\x4f\x21\0\0\0\0\
+\0\0\x79\xa2\x90\xff\0\0\0\0\xaf\x21\0\0\0\0\0\0\x7b\x1a\x90\xff\0\0\0\0\x05\0\
+\xc3\x10\0\0\0\0\x69\xa1\xde\xff\0\0\0\0\x57\x01\0\0\x3f\xff\0\0\x55\x01\xc0\
+\x10\0\0\0\0\x71\xa1\xe1\xff\0\0\0\0\x15\x01\x01\0\x11\0\0\0\x55\x01\xbd\x10\
+\x06\0\0\0\x71\xa2\xd8\xff\0\0\0\0\x67\x02\0\0\x02\0\0\0\x57\x02\0\0\x3c\0\0\0\
+\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\x79\xa1\x88\xff\0\0\0\0\xb7\
+\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xb7\x07\0\0\0\0\0\
+\0\x55\0\x07\x04\0\0\0\0\x79\xa6\x78\xff\0\0\0\0\xbf\x62\0\0\0\0\0\0\x07\x02\0\
+\0\x08\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x40\x79\xa4\x98\xff\0\0\0\0\
+\x15\x01\x07\0\0\0\0\0\x61\x41\0\0\0\0\0\0\x67\x01\0\0\x01\0\0\0\x61\x23\0\0\0\
+\0\0\0\x77\x03\0\0\x1f\0\0\0\x57\x03\0\0\x01\0\0\0\x4f\x31\0\0\0\0\0\0\xbf\x17\
+\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x20\x15\x01\x08\0\0\0\0\0\
+\x61\x41\0\0\0\0\0\0\x67\x01\0\0\x02\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1e\
+\0\0\0\x57\x03\0\0\x03\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\
+\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x10\x15\x01\x08\0\0\0\0\0\x61\
+\x41\0\0\0\0\0\0\x67\x01\0\0\x03\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1d\0\0\
+\0\x57\x03\0\0\x07\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\
+\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x08\x15\x01\x08\0\0\0\0\0\x61\x41\
+\0\0\0\0\0\0\x67\x01\0\0\x04\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\
+\x57\x03\0\0\x0f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\
+\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x04\x15\x01\x08\0\0\0\0\0\x61\x41\0\
+\0\0\0\0\0\x67\x01\0\0\x05\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\
+\x03\0\0\x1f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\
+\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x02\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\
+\0\0\0\x67\x01\0\0\x06\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1a\0\0\0\x57\x03\
+\0\0\x3f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x01\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x07\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x19\0\0\0\x57\x03\0\0\
+\x7f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\x91\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\x80\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\
+\x67\x01\0\0\x08\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\
+\xff\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\x91\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\x40\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\0\
+\x67\x01\0\0\x09\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\x03\0\0\
+\xff\x01\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x20\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0a\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x16\0\0\0\x57\x03\0\0\
+\xff\x03\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x10\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0b\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\
+\xff\x07\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x08\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\
+\xff\x0f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x04\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0d\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x13\0\0\0\x57\x03\0\0\
+\xff\x1f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x02\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0e\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\
+\xff\x3f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x01\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x0f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\
+\xff\x7f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x80\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x10\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x10\0\0\0\x57\x03\0\0\
+\xff\xff\0\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x40\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x11\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0f\0\0\0\x57\x03\0\0\
+\xff\xff\x01\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x20\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x12\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\
+\xff\xff\x03\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x10\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x13\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0d\0\0\0\x57\x03\0\0\
+\xff\xff\x07\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x08\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x14\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0c\0\0\0\x57\x03\0\0\
+\xff\xff\x0f\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x04\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x15\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\
+\xff\xff\x1f\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x02\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x16\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0a\0\0\0\x57\x03\0\0\
+\xff\xff\x3f\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\x01\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x17\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x09\0\0\0\x57\x03\0\0\
+\xff\xff\x7f\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\x80\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x18\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\
+\xff\xff\xff\0\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\x40\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x19\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x07\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x01\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\
+\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x20\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\0\
+\0\0\0\x67\x01\0\0\x1a\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x06\0\0\0\x57\x03\
+\0\0\xff\xff\xff\x03\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\
+\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x10\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\0\0\
+\0\0\0\0\x67\x01\0\0\x1b\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x07\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\
+\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x08\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x41\
+\0\0\0\0\0\0\x67\x01\0\0\x1c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x04\0\0\0\
+\x57\x03\0\0\xff\xff\xff\x0f\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\
+\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x04\0\0\0\x15\x01\x08\0\0\0\0\0\x61\
+\x41\0\0\0\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x03\0\0\
+\0\x57\x03\0\0\xff\xff\xff\x1f\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\
+\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x02\0\0\0\x15\x01\x08\0\0\0\0\0\
+\x61\x41\0\0\0\0\0\0\x67\x01\0\0\x1e\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x02\
+\0\0\0\x57\x03\0\0\xff\xff\xff\x3f\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\
+\x17\0\0\0\0\0\0\x57\x09\0\0\x01\0\0\0\x15\x09\x08\0\0\0\0\0\x61\x41\0\0\0\0\0\
+\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\0\xbf\x17\0\0\0\0\0\0\
+\xbf\x61\0\0\0\0\0\0\x07\x01\0\0\x0c\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\
+\0\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x14\
+\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x73\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\
+\x20\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x02\0\0\0\x61\x14\0\
+\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x73\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\
+\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x03\0\0\0\x61\x14\0\0\0\
+\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x04\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x05\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\0\
+\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x06\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\0\
+\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x07\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\0\
+\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x08\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\0\
+\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x09\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0a\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0b\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0c\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0d\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0e\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x0f\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x10\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\0\
+\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\
+\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x11\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x73\0\
+\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x12\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x13\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x14\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x15\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x16\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x17\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x18\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x73\
+\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x19\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\
+\x73\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\
+\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x14\0\0\0\
+\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\
+\xaf\x73\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\xbf\x83\0\0\0\0\0\0\x57\x03\0\0\x10\0\
+\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x14\0\
+\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\
+\0\xaf\x73\0\0\0\0\0\0\xbf\x37\0\0\0\0\0\0\x69\xa3\xd2\xff\0\0\0\0\xbf\x84\0\0\
+\0\0\0\0\x57\x04\0\0\x08\0\0\0\x15\x04\x08\0\0\0\0\0\x61\x24\0\0\0\0\0\0\x67\
+\x04\0\0\x1c\0\0\0\x61\x15\0\0\0\0\0\0\x77\x05\0\0\x04\0\0\0\x57\x05\0\0\xff\
+\xff\xff\x0f\x4f\x54\0\0\0\0\0\0\xaf\x74\0\0\0\0\0\0\xbf\x47\0\0\0\0\0\0\x67\
+\x03\0\0\x10\0\0\0\x69\xa4\xd0\xff\0\0\0\0\xbf\x85\0\0\0\0\0\0\x57\x05\0\0\x04\
+\0\0\0\x15\x05\x08\0\0\0\0\0\x61\x25\0\0\0\0\0\0\x67\x05\0\0\x1d\0\0\0\x61\x10\
+\0\0\0\0\0\0\x77\0\0\0\x03\0\0\0\x57\0\0\0\xff\xff\xff\x1f\x4f\x05\0\0\0\0\0\0\
+\xaf\x75\0\0\0\0\0\0\xbf\x57\0\0\0\0\0\0\x4f\x43\0\0\0\0\0\0\xbf\x84\0\0\0\0\0\
+\0\x57\x04\0\0\x02\0\0\0\x15\x04\x08\0\0\0\0\0\x61\x24\0\0\0\0\0\0\x67\x04\0\0\
+\x1e\0\0\0\x61\x15\0\0\0\0\0\0\x77\x05\0\0\x02\0\0\0\x57\x05\0\0\xff\xff\xff\
+\x3f\x4f\x54\0\0\0\0\0\0\xaf\x74\0\0\0\0\0\0\xbf\x47\0\0\0\0\0\0\xdc\x03\0\0\
+\x20\0\0\0\x57\x08\0\0\x01\0\0\0\x15\x08\x08\0\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\
+\x02\0\0\x1f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x01\0\0\0\x57\x04\0\0\xff\
+\xff\xff\x7f\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\x27\0\0\0\0\0\0\x07\
+\x06\0\0\x10\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x40\x15\x02\x08\0\0\0\
+\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x01\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x20\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x02\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x10\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x03\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x08\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x04\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x04\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x05\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x02\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x06\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x01\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x07\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x80\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x40\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x09\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x20\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0a\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x10\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0b\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x08\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0c\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x04\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0d\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x02\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0e\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\0\x01\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x0f\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x80\0\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x10\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\xbf\
+\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x40\0\0\x15\x02\x08\0\0\0\0\
+\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x11\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\0\
+\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x20\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x12\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x10\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x13\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x08\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x14\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x04\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x15\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x02\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x16\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\0\x01\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x17\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x80\0\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x18\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\0\
+\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x40\0\0\0\x15\x02\x08\0\0\
+\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x19\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\0\
+\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\0\
+\0\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x08\0\
+\0\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1a\0\0\0\x61\x64\0\0\0\0\0\0\x77\x04\
+\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\0\0\
+\0\0\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\x15\x02\x08\
+\0\0\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1b\0\0\0\x61\x64\0\0\0\0\0\0\x77\
+\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\x42\0\0\0\0\0\0\xaf\x72\0\0\
+\0\0\0\0\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\x15\x02\
+\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1c\0\0\0\x61\x64\0\0\0\0\0\0\
+\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\xff\xff\xff\x0f\x4f\x42\0\0\0\0\0\0\xaf\x72\
+\0\0\0\0\0\0\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1d\0\0\0\x61\x64\0\0\0\0\0\
+\0\x77\x04\0\0\x03\0\0\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x42\0\0\0\0\0\0\xaf\
+\x72\0\0\0\0\0\0\xbf\x27\0\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\
+\x15\x02\x08\0\0\0\0\0\x61\x12\0\0\0\0\0\0\x67\x02\0\0\x1e\0\0\0\x61\x64\0\0\0\
+\0\0\0\x77\x04\0\0\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x42\0\0\0\0\0\0\
+\xaf\x72\0\0\0\0\0\0\xbf\x27\0\0\0\0\0\0\x57\x03\0\0\x01\0\0\0\x15\x03\x08\0\0\
+\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x62\0\0\0\0\0\0\x77\x02\0\
+\0\x01\0\0\0\x57\x02\0\0\xff\xff\xff\x7f\x4f\x21\0\0\0\0\0\0\xaf\x71\0\0\0\0\0\
+\0\xbf\x17\0\0\0\0\0\0\x7b\x7a\x90\xff\0\0\0\0\x05\0\xa9\x0c\0\0\0\0\xb7\x02\0\
+\0\x28\0\0\0\x71\xa1\xde\xff\0\0\0\0\x79\xa6\x88\xff\0\0\0\0\x65\x01\x3b\x0c\
+\x2b\0\0\0\x15\x01\x3c\x0c\0\0\0\0\x15\x01\x3b\x0c\x2b\0\0\0\x15\x01\x01\0\x06\
+\0\0\0\x55\x01\xa1\x0c\x11\0\0\0\xbf\x06\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\
+\x03\0\0\xd0\xff\xff\xff\x79\xa1\x88\xff\0\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\
+\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\x99\x0c\0\0\0\0\x79\xa2\x78\xff\0\0\0\
+\0\xbf\x24\0\0\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\
+\0\0\x40\xb7\x08\0\0\0\0\0\0\x15\x01\x07\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\
+\x18\0\0\0\0\0\0\x67\x08\0\0\x01\0\0\0\x61\x21\0\0\0\0\0\0\x77\x01\0\0\x1f\0\0\
+\0\x57\x01\0\0\x01\0\0\0\x4f\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\
+\0\0\x20\xbf\x65\0\0\0\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\
+\x11\0\0\0\0\0\0\x67\x01\0\0\x02\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1e\0\0\
+\0\x57\x03\0\0\x03\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x10\x79\xa0\x58\xff\0\0\0\0\x79\
+\xa3\x68\xff\0\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\
+\0\0\0\0\x67\x01\0\0\x03\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1d\0\0\0\x57\
+\x03\0\0\x07\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x08\x79\xa6\x60\xff\0\0\0\0\x15\x01\x09\
+\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x04\0\0\0\
+\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1c\0\0\0\x57\x03\0\0\x0f\0\0\0\x4f\x31\0\0\0\
+\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\
+\0\0\0\x04\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\
+\x67\x01\0\0\x05\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x1b\0\0\0\x57\x03\0\0\
+\x1f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\
+\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x02\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\
+\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x06\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\
+\x1a\0\0\0\x57\x03\0\0\x3f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\
+\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x01\x15\x01\x09\0\0\0\0\
+\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x07\0\0\0\x61\x23\0\
+\0\0\0\0\0\x77\x03\0\0\x19\0\0\0\x57\x03\0\0\x7f\0\0\0\x4f\x31\0\0\0\0\0\0\xaf\
+\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x80\0\
+\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\
+\x08\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x18\0\0\0\x57\x03\0\0\xff\0\0\0\x4f\
+\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\x40\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\
+\0\0\0\0\0\x67\x01\0\0\x09\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x17\0\0\0\x57\
+\x03\0\0\xff\x01\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\
+\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x20\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\
+\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x0a\0\0\0\x61\x23\0\0\0\0\0\0\x77\
+\x03\0\0\x16\0\0\0\x57\x03\0\0\xff\x03\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\
+\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x10\0\x15\x01\x09\
+\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x0b\0\0\0\
+\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x15\0\0\0\x57\x03\0\0\xff\x07\0\0\x4f\x31\0\0\
+\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\
+\0\0\0\x08\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\
+\x67\x01\0\0\x0c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x14\0\0\0\x57\x03\0\0\
+\xff\x0f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x04\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\
+\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x0d\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\
+\0\x13\0\0\0\x57\x03\0\0\xff\x1f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\
+\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\0\x02\0\x15\x01\x09\0\0\
+\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x0e\0\0\0\x61\
+\x23\0\0\0\0\0\0\x77\x03\0\0\x12\0\0\0\x57\x03\0\0\xff\x3f\0\0\x4f\x31\0\0\0\0\
+\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\
+\0\x01\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\
+\x01\0\0\x0f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x11\0\0\0\x57\x03\0\0\xff\
+\x7f\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\
+\0\0\0\0\0\x57\x01\0\0\0\x80\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\
+\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x10\
+\0\0\0\x57\x03\0\0\xff\xff\0\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\
+\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\x40\0\0\x15\x01\x09\0\0\0\0\0\
+\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x11\0\0\0\x61\x23\0\0\
+\0\0\0\0\x77\x03\0\0\x0f\0\0\0\x57\x03\0\0\xff\xff\x01\0\x4f\x31\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\x20\
+\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\
+\0\0\x12\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0e\0\0\0\x57\x03\0\0\xff\xff\
+\x03\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\
+\0\0\0\0\x57\x01\0\0\0\x10\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\
+\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x13\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0d\
+\0\0\0\x57\x03\0\0\xff\xff\x07\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\
+\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\x08\0\0\x15\x01\x09\0\0\0\0\
+\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x14\0\0\0\x61\x23\0\
+\0\0\0\0\0\x77\x03\0\0\x0c\0\0\0\x57\x03\0\0\xff\xff\x0f\0\x4f\x31\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\x04\
+\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\
+\0\0\x15\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0b\0\0\0\x57\x03\0\0\xff\xff\
+\x1f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\
+\0\0\0\0\x57\x01\0\0\0\x02\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\
+\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x16\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x0a\
+\0\0\0\x57\x03\0\0\xff\xff\x3f\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\
+\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\0\x01\0\0\x15\x01\x09\0\0\0\0\
+\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x17\0\0\0\x61\x23\0\
+\0\0\0\0\0\x77\x03\0\0\x09\0\0\0\x57\x03\0\0\xff\xff\x7f\0\x4f\x31\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x80\0\
+\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\
+\0\0\x18\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x08\0\0\0\x57\x03\0\0\xff\xff\
+\xff\0\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\
+\0\0\0\0\x57\x01\0\0\x40\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\
+\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x19\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x07\
+\0\0\0\x57\x03\0\0\xff\xff\xff\x01\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\
+\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x20\0\0\0\x15\x01\x09\0\0\0\0\
+\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1a\0\0\0\x61\x23\0\
+\0\0\0\0\0\x77\x03\0\0\x06\0\0\0\x57\x03\0\0\xff\xff\xff\x03\x4f\x31\0\0\0\0\0\
+\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x10\
+\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\
+\x01\0\0\x1b\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x05\0\0\0\x57\x03\0\0\xff\
+\xff\xff\x07\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x91\0\0\0\0\0\0\x57\x01\0\0\x08\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\
+\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1c\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\
+\0\x04\0\0\0\x57\x03\0\0\xff\xff\xff\x0f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\
+\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\x04\0\0\0\x15\x01\x09\0\
+\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\
+\x23\0\0\0\0\0\0\x77\x03\0\0\x03\0\0\0\x57\x03\0\0\xff\xff\xff\x1f\x4f\x31\0\0\
+\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\
+\0\x02\0\0\0\x15\x01\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\0\0\0\0\0\
+\x67\x01\0\0\x1e\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x02\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x3f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\x57\x09\0\0\x01\0\0\0\x15\x09\x09\0\0\0\0\0\x79\xa1\x98\xff\0\0\0\0\x61\x11\0\
+\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\
+\x03\0\0\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\xbf\x49\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x07\x01\0\0\x0c\0\0\0\xbf\x73\0\
+\0\0\0\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\
+\x03\0\0\x01\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\
+\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\
+\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\
+\0\0\x02\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x03\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x04\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x05\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x06\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x07\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x08\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\0\
+\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x09\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x0f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x10\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x11\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x12\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x13\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x14\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x15\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x16\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x17\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x18\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\0\0\
+\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x19\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\0\0\
+\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\
+\0\0\x1a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\
+\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x73\0\
+\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\
+\x03\0\0\x1b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\
+\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x73\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x1c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x73\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\
+\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x57\x07\0\0\x01\0\0\0\x15\x07\x08\0\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\
+\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\
+\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x92\0\
+\0\0\0\0\0\x07\x02\0\0\x10\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x40\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x20\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x02\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x10\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x03\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x08\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x04\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x04\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x05\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x02\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x06\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\0\x01\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x07\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x80\0\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x08\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\x40\0\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x09\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\0\
+\x20\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0a\0\0\0\x61\x24\
+\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\
+\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0b\0\0\0\x61\
+\x24\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x43\0\0\0\0\
+\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\
+\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0c\0\0\0\
+\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x43\0\0\
+\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\
+\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x0d\0\
+\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x43\
+\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\
+\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x0e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\
+\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\
+\0\0\x0f\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\
+\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\
+\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\
+\x03\0\0\x10\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\
+\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\
+\xa0\xff\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x11\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\
+\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\
+\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x12\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\
+\0\0\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\
+\0\0\0\0\0\x67\x03\0\0\x13\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\
+\x04\0\0\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\
+\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x13\0\0\0\0\0\0\x67\x03\0\0\x14\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\
+\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\
+\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x15\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0b\
+\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\
+\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\
+\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x16\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\
+\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\
+\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\
+\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x17\0\0\0\x61\x24\0\0\0\0\0\0\x77\
+\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x18\0\0\0\x61\x24\0\0\0\0\0\
+\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x40\0\0\0\
+\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x19\0\0\0\x61\x24\0\0\0\
+\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\
+\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\
+\x24\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x43\0\0\
+\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\
+\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1b\0\
+\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\xff\0\0\0\
+\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\x67\x03\0\0\
+\x1c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\xa0\
+\xff\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x1d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\
+\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x79\xa3\xa0\xff\0\0\0\0\x57\x03\0\0\x01\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\
+\0\x57\x03\0\0\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\
+\0\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x07\x01\0\0\x14\0\0\0\x79\xa3\x70\xff\0\0\0\0\
+\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x01\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x02\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x03\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x04\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x05\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x06\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x07\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x08\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x09\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\
+\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\
+\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\
+\0\0\x0a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\
+\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\
+\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\
+\x03\0\0\x0b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\
+\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\
+\x70\xff\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\
+\0\x67\x03\0\0\x0c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\
+\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\
+\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\
+\0\0\0\x67\x03\0\0\x0d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\
+\0\0\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\
+\0\0\0\0\0\x67\x03\0\0\x0e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\
+\x04\0\0\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x23\
+\0\0\0\0\0\0\x67\x03\0\0\x0f\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\
+\x57\x04\0\0\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x23\0\0\0\0\0\0\x67\x03\0\0\x10\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\
+\0\x57\x04\0\0\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\
+\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x11\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x0f\
+\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\
+\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\
+\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x12\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\
+\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\
+\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\
+\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x13\0\0\0\x61\x14\0\0\0\0\0\0\x77\
+\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\
+\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\
+\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x14\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\
+\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x04\0\0\
+\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x15\0\0\0\x61\x14\0\0\0\
+\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\
+\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\x02\
+\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x16\0\0\0\x61\x14\0\
+\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\
+\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\0\
+\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x17\0\0\0\x61\
+\x14\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x43\0\0\0\
+\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\
+\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x18\0\0\0\
+\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x43\0\
+\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\
+\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x19\0\
+\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\
+\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\
+\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\
+\x1a\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\
+\xff\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\0\0\0\0\0\
+\x67\x03\0\0\x1b\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x23\0\
+\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x23\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\
+\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\
+\0\x61\x23\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x14\0\0\0\0\0\0\x77\x04\0\0\
+\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\
+\xbf\x38\0\0\0\0\0\0\x79\xa3\x70\xff\0\0\0\0\x57\x03\0\0\x01\0\0\0\x15\x03\x08\
+\0\0\0\0\0\x61\x22\0\0\0\0\0\0\x67\x02\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\0\x77\
+\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x07\x02\0\0\x18\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x01\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\
+\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x02\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\
+\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x03\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\
+\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x04\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\
+\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x05\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\
+\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x06\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\
+\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x07\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\
+\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x08\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\
+\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x09\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\
+\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\
+\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\
+\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\
+\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\
+\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\
+\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0f\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\
+\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x10\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\
+\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x11\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\
+\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x12\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\
+\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x13\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\
+\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x14\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\
+\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x15\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\
+\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x16\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\
+\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x17\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\
+\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x18\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\
+\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x19\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\
+\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x08\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\
+\0\0\0\0\0\0\x67\x03\0\0\x1c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\
+\x57\x04\0\0\xff\xff\xff\x0f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\
+\0\0\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x04\0\0\0\x15\x03\x08\0\0\0\0\0\x61\
+\x13\0\0\0\0\0\0\x67\x03\0\0\x1d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\
+\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\
+\0\0\0\0\0\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x02\0\0\0\x15\x03\x08\0\0\0\0\0\
+\x61\x13\0\0\0\0\0\0\x67\x03\0\0\x1e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x02\
+\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\
+\x38\0\0\0\0\0\0\x57\x06\0\0\x01\0\0\0\x15\x06\x08\0\0\0\0\0\x61\x11\0\0\0\0\0\
+\0\x67\x01\0\0\x1f\0\0\0\x61\x23\0\0\0\0\0\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\
+\xff\xff\xff\x7f\x4f\x31\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x93\0\0\0\0\0\0\x07\x03\0\0\x1c\0\0\0\xbf\x01\0\0\0\0\0\0\x57\x01\0\0\0\0\
+\0\x40\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x01\0\0\0\x61\x34\
+\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x41\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\x57\x01\0\0\0\0\0\
+\x20\x79\xa6\x68\xff\0\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\
+\0\0\x02\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\0\x10\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x03\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x08\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x04\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x04\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x05\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x02\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x06\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\0\x01\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x07\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\x80\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x08\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\
+\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\0\
+\x57\x01\0\0\0\0\x40\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x09\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x20\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0a\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x10\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0b\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x08\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0c\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x04\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0d\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x02\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0e\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\0\x01\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x0f\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x80\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x10\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x40\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x11\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x20\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x12\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x10\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x13\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x08\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x14\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x04\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x15\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x02\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x16\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\0\x01\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x17\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\x80\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x18\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\
+\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\0\0\
+\0\x57\x01\0\0\x40\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x19\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\
+\x01\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\0\0\
+\0\0\0\x57\x01\0\0\x20\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\
+\0\0\x1a\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\
+\xff\x03\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x01\0\
+\0\0\0\0\0\x57\x01\0\0\x10\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\
+\x01\0\0\x1b\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\
+\xff\xff\x07\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\
+\x01\0\0\0\0\0\0\x57\x01\0\0\x08\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\
+\0\x67\x01\0\0\x1c\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x0f\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\
+\xbf\x01\0\0\0\0\0\0\x57\x01\0\0\x04\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\
+\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x1f\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\
+\0\xbf\x01\0\0\0\0\0\0\x57\x01\0\0\x02\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\
+\0\0\0\0\x67\x01\0\0\x1e\0\0\0\x61\x34\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x3f\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\
+\0\0\0\x57\0\0\0\x01\0\0\0\x15\0\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\
+\x1f\0\0\0\x61\x32\0\0\0\0\0\0\x77\x02\0\0\x01\0\0\0\x57\x02\0\0\xff\xff\xff\
+\x7f\x4f\x21\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x91\0\0\0\
+\0\0\0\x07\x01\0\0\x20\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x40\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x01\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x20\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x02\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x10\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x03\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x08\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x04\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x04\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x05\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x02\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x06\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\0\x01\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x07\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x80\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\0\
+\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x40\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x09\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x20\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0a\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x10\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0b\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x08\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0c\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x04\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0d\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x02\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0e\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\0\x01\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x0f\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x80\0\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x10\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\0\
+\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x40\0\0\x15\x02\
+\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x11\0\0\0\x61\x14\0\0\0\0\0\0\
+\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x42\0\0\0\0\0\0\xaf\x82\0\
+\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x20\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x12\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x10\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x13\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x08\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x14\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x04\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x15\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x02\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x16\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\0\x01\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x17\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\x80\0\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x18\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x42\0\0\0\0\0\0\xaf\x82\
+\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\x40\0\0\0\x15\
+\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x19\0\0\0\x61\x14\0\0\0\0\0\
+\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x42\0\0\0\0\0\0\xaf\
+\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\x20\0\0\0\
+\x15\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1a\0\0\0\x61\x14\0\0\0\
+\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x42\0\0\0\0\0\0\
+\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\x10\0\
+\0\0\x15\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1b\0\0\0\x61\x14\0\
+\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\x42\0\0\0\0\0\
+\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\x08\
+\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1c\0\0\0\x61\x14\
+\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\xff\xff\xff\x0f\x4f\x42\0\0\0\0\
+\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\0\
+\x04\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1d\0\0\0\x61\
+\x14\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x42\0\0\
+\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x52\0\0\0\0\0\0\x57\x02\0\
+\0\x02\0\0\0\x15\x02\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1e\0\0\0\
+\x61\x14\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x42\
+\0\0\0\0\0\0\xaf\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\x57\x05\0\0\x01\0\0\0\x15\
+\x05\x08\0\0\0\0\0\x61\x32\0\0\0\0\0\0\x67\x02\0\0\x1f\0\0\0\x61\x13\0\0\0\0\0\
+\0\x77\x03\0\0\x01\0\0\0\x57\x03\0\0\xff\xff\xff\x7f\x4f\x32\0\0\0\0\0\0\xaf\
+\x82\0\0\0\0\0\0\xbf\x28\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x07\x02\0\0\x24\0\0\0\
+\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x40\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x01\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\
+\0\0\x01\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x20\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x02\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\
+\x03\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x10\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x03\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\
+\x07\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x08\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x04\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\
+\x0f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x04\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x05\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\
+\x1f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x02\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x06\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\
+\x3f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\0\x01\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x07\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\
+\x7f\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x80\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x08\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\
+\xff\0\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\x63\
+\0\0\0\0\0\0\x57\x03\0\0\0\0\x40\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\0\
+\x67\x03\0\0\x09\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\
+\xff\x01\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x20\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\
+\xff\x03\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x10\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\
+\xff\x07\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x08\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0c\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\
+\xff\x0f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x04\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0d\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\
+\xff\x1f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x02\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0e\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\
+\xff\x3f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\0\x01\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x0f\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\
+\xff\x7f\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x80\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x10\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\
+\xff\xff\0\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x40\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x11\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\
+\xff\xff\x01\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x20\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x12\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\
+\xff\xff\x03\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x10\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x13\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\
+\xff\xff\x07\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x08\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x14\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\
+\xff\xff\x0f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x04\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x15\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\
+\xff\xff\x1f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x02\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x16\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\
+\xff\xff\x3f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\0\x01\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x17\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\
+\xff\xff\x7f\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x80\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x18\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\
+\xff\xff\xff\0\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\xbf\
+\x63\0\0\0\0\0\0\x57\x03\0\0\x40\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\0\0\
+\0\x67\x03\0\0\x19\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\
+\xff\xff\xff\x01\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\0\
+\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x20\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\0\
+\0\0\0\x67\x03\0\0\x1a\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\
+\0\0\xff\xff\xff\x03\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\0\0\
+\0\xbf\x63\0\0\0\0\0\0\x57\x03\0\0\x10\0\0\0\x15\x03\x08\0\0\0\0\0\x61\x13\0\0\
+\0\0\0\0\x67\x03\0\0\x1b\0\0\0\x61\x24\0\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\
+\x04\0\0\xff\xff\xff\x07\x4f\x43\0\0\0\0\0\0\xaf\x83\0\0\0\0\0\0\xbf\x38\0\0\0\
+\0\0\0\x69\xa3\xd2\xff\0\0\0\0\xbf\x64\0\0\0\0\0\0\x57\x04\0\0\x08\0\0\0\x15\
+\x04\x08\0\0\0\0\0\x61\x14\0\0\0\0\0\0\x67\x04\0\0\x1c\0\0\0\x61\x25\0\0\0\0\0\
+\0\x77\x05\0\0\x04\0\0\0\x57\x05\0\0\xff\xff\xff\x0f\x4f\x54\0\0\0\0\0\0\xaf\
+\x84\0\0\0\0\0\0\xbf\x48\0\0\0\0\0\0\x67\x03\0\0\x10\0\0\0\x69\xa4\xd0\xff\0\0\
+\0\0\xbf\x65\0\0\0\0\0\0\x57\x05\0\0\x04\0\0\0\x15\x05\x08\0\0\0\0\0\x61\x15\0\
+\0\0\0\0\0\x67\x05\0\0\x1d\0\0\0\x61\x20\0\0\0\0\0\0\x77\0\0\0\x03\0\0\0\x57\0\
+\0\0\xff\xff\xff\x1f\x4f\x05\0\0\0\0\0\0\xaf\x85\0\0\0\0\0\0\xbf\x58\0\0\0\0\0\
+\0\x4f\x43\0\0\0\0\0\0\xbf\x64\0\0\0\0\0\0\x57\x04\0\0\x02\0\0\0\x15\x04\x08\0\
+\0\0\0\0\x61\x14\0\0\0\0\0\0\x67\x04\0\0\x1e\0\0\0\x61\x25\0\0\0\0\0\0\x77\x05\
+\0\0\x02\0\0\0\x57\x05\0\0\xff\xff\xff\x3f\x4f\x54\0\0\0\0\0\0\xaf\x84\0\0\0\0\
+\0\0\xbf\x48\0\0\0\0\0\0\xdc\x03\0\0\x20\0\0\0\x57\x06\0\0\x01\0\0\0\x15\x06\
+\x08\0\0\0\0\0\x61\x11\0\0\0\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x24\0\0\0\0\0\0\
+\x77\x04\0\0\x01\0\0\0\x57\x04\0\0\xff\xff\xff\x7f\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\x07\x09\0\0\x28\0\0\0\xbf\x31\0\0\0\0\0\0\x57\
+\x01\0\0\0\0\0\x40\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x01\0\
+\0\0\x61\x94\0\0\0\0\0\0\x77\x04\0\0\x1f\0\0\0\x57\x04\0\0\x01\0\0\0\x4f\x41\0\
+\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\
+\0\0\0\0\0\x20\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x02\0\0\0\
+\x61\x94\0\0\0\0\0\0\x77\x04\0\0\x1e\0\0\0\x57\x04\0\0\x03\0\0\0\x4f\x41\0\0\0\
+\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\
+\0\0\0\x10\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x03\0\0\0\x61\
+\x94\0\0\0\0\0\0\x77\x04\0\0\x1d\0\0\0\x57\x04\0\0\x07\0\0\0\x4f\x41\0\0\0\0\0\
+\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\
+\0\x08\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x04\0\0\0\x61\x94\
+\0\0\0\0\0\0\x77\x04\0\0\x1c\0\0\0\x57\x04\0\0\x0f\0\0\0\x4f\x41\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\0\
+\x04\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x05\0\0\0\x61\x94\0\
+\0\0\0\0\0\x77\x04\0\0\x1b\0\0\0\x57\x04\0\0\x1f\0\0\0\x4f\x41\0\0\0\0\0\0\xaf\
+\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x02\
+\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x06\0\0\0\x61\x94\0\0\0\
+\0\0\0\x77\x04\0\0\x1a\0\0\0\x57\x04\0\0\x3f\0\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\0\x01\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x07\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x19\0\0\0\x57\x04\0\0\x7f\0\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x80\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x08\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x18\0\0\0\x57\x04\0\0\xff\0\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\0\
+\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x40\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x09\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x17\0\0\0\x57\x04\0\0\xff\x01\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x20\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0a\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x16\0\0\0\x57\x04\0\0\xff\x03\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x10\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0b\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x15\0\0\0\x57\x04\0\0\xff\x07\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x08\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0c\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x14\0\0\0\x57\x04\0\0\xff\x0f\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x04\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0d\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x13\0\0\0\x57\x04\0\0\xff\x1f\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x02\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0e\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x12\0\0\0\x57\x04\0\0\xff\x3f\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\0\x01\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x0f\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x11\0\0\0\x57\x04\0\0\xff\x7f\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x80\0\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x10\0\0\0\x57\x04\0\0\xff\xff\0\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\0\
+\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x40\0\0\x15\x01\
+\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x11\0\0\0\x61\x94\0\0\0\0\0\0\
+\x77\x04\0\0\x0f\0\0\0\x57\x04\0\0\xff\xff\x01\0\x4f\x41\0\0\0\0\0\0\xaf\x81\0\
+\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x20\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x12\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x0e\0\0\0\x57\x04\0\0\xff\xff\x03\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x10\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x13\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x0d\0\0\0\x57\x04\0\0\xff\xff\x07\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x08\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x14\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x0c\0\0\0\x57\x04\0\0\xff\xff\x0f\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x04\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x15\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x0b\0\0\0\x57\x04\0\0\xff\xff\x1f\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x02\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x16\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x0a\0\0\0\x57\x04\0\0\xff\xff\x3f\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\0\x01\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x17\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x09\0\0\0\x57\x04\0\0\xff\xff\x7f\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\x80\0\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x18\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x08\0\0\0\x57\x04\0\0\xff\xff\xff\0\x4f\x41\0\0\0\0\0\0\xaf\x81\
+\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\x40\0\0\0\x15\
+\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x19\0\0\0\x61\x94\0\0\0\0\0\
+\0\x77\x04\0\0\x07\0\0\0\x57\x04\0\0\xff\xff\xff\x01\x4f\x41\0\0\0\0\0\0\xaf\
+\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\x20\0\0\0\
+\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1a\0\0\0\x61\x94\0\0\0\
+\0\0\0\x77\x04\0\0\x06\0\0\0\x57\x04\0\0\xff\xff\xff\x03\x4f\x41\0\0\0\0\0\0\
+\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\x10\0\
+\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1b\0\0\0\x61\x94\0\
+\0\0\0\0\0\x77\x04\0\0\x05\0\0\0\x57\x04\0\0\xff\xff\xff\x07\x4f\x41\0\0\0\0\0\
+\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\x08\
+\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1c\0\0\0\x61\x94\
+\0\0\0\0\0\0\x77\x04\0\0\x04\0\0\0\x57\x04\0\0\xff\xff\xff\x0f\x4f\x41\0\0\0\0\
+\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\0\
+\x04\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1d\0\0\0\x61\
+\x94\0\0\0\0\0\0\x77\x04\0\0\x03\0\0\0\x57\x04\0\0\xff\xff\xff\x1f\x4f\x41\0\0\
+\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xbf\x31\0\0\0\0\0\0\x57\x01\0\
+\0\x02\0\0\0\x15\x01\x08\0\0\0\0\0\x61\x21\0\0\0\0\0\0\x67\x01\0\0\x1e\0\0\0\
+\x61\x94\0\0\0\0\0\0\x77\x04\0\0\x02\0\0\0\x57\x04\0\0\xff\xff\xff\x3f\x4f\x41\
+\0\0\0\0\0\0\xaf\x81\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\x7b\x8a\x90\xff\0\0\0\0\
+\xbf\x96\0\0\0\0\0\0\x57\x03\0\0\x01\0\0\0\x15\x03\x6e\0\0\0\0\0\x61\x21\0\0\0\
+\0\0\0\x67\x01\0\0\x1f\0\0\0\x61\x62\0\0\0\0\0\0\x05\0\xa0\xef\0\0\0\0\x15\x01\
+\x63\0\x2c\0\0\0\x55\x01\xc5\xf3\x3c\0\0\0\xbf\x08\0\0\0\0\0\0\xbf\xa3\0\0\0\0\
+\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\
+\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\x60\0\0\0\0\0\x71\xa3\xd1\xff\0\0\
+\0\0\x67\x03\0\0\x03\0\0\0\xbf\x32\0\0\0\0\0\0\x07\x02\0\0\x30\0\0\0\x71\xa1\
+\xd0\xff\0\0\0\0\x65\x01\x04\0\x2b\0\0\0\xbf\x80\0\0\0\0\0\0\x15\x01\x05\0\0\0\
+\0\0\x15\x01\x04\0\x2b\0\0\0\x05\0\xb3\xf3\0\0\0\0\xbf\x80\0\0\0\0\0\0\x15\x01\
+\x4e\0\x2c\0\0\0\x55\x01\xb0\xf3\x3c\0\0\0\x7b\x3a\x50\xff\0\0\0\0\xbf\xa3\0\0\
+\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\
+\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\x4b\0\0\0\0\0\x71\xa1\xd1\xff\
+\0\0\0\0\x67\x01\0\0\x03\0\0\0\x79\xa4\x50\xff\0\0\0\0\x0f\x14\0\0\0\0\0\0\x07\
+\x04\0\0\x38\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x65\x01\x05\0\x2b\0\0\0\xbf\x80\0\0\
+\0\0\0\0\x15\x01\x08\0\0\0\0\0\xbf\x42\0\0\0\0\0\0\x15\x01\x06\0\x2b\0\0\0\x05\
+\0\x9c\xf3\0\0\0\0\xbf\x42\0\0\0\0\0\0\xbf\x80\0\0\0\0\0\0\x15\x01\x36\0\x2c\0\
+\0\0\xbf\x42\0\0\0\0\0\0\x55\x01\x97\xf3\x3c\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\
+\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x7b\x4a\x50\xff\0\0\0\0\xbf\x42\0\0\0\
+\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\
+\x31\0\0\0\0\0\x71\xa1\xd1\xff\0\0\0\0\x67\x01\0\0\x03\0\0\0\x79\xa4\x50\xff\0\
+\0\0\0\x0f\x14\0\0\0\0\0\0\x07\x04\0\0\x08\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x65\
+\x01\x05\0\x2b\0\0\0\xbf\x80\0\0\0\0\0\0\x15\x01\x08\0\0\0\0\0\xbf\x42\0\0\0\0\
+\0\0\x15\x01\x06\0\x2b\0\0\0\x05\0\x82\xf3\0\0\0\0\xbf\x42\0\0\0\0\0\0\xbf\x80\
+\0\0\0\0\0\0\x15\x01\x1c\0\x2c\0\0\0\xbf\x42\0\0\0\0\0\0\x55\x01\x7d\xf3\x3c\0\
+\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x7b\
+\x4a\x50\xff\0\0\0\0\xbf\x42\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\
+\0\0\0\x85\0\0\0\x44\0\0\0\x55\0\x17\0\0\0\0\0\x71\xa1\xd1\xff\0\0\0\0\x67\x01\
+\0\0\x03\0\0\0\x79\xa4\x50\xff\0\0\0\0\x0f\x14\0\0\0\0\0\0\x07\x04\0\0\x08\0\0\
+\0\x71\xa1\xd0\xff\0\0\0\0\xbf\x42\0\0\0\0\0\0\xbf\x80\0\0\0\0\0\0\x25\x01\x6b\
+\xf3\x3c\0\0\0\xb7\x03\0\0\x01\0\0\0\x6f\x13\0\0\0\0\0\0\x18\x02\0\0\x01\0\0\0\
+\0\0\0\0\0\x18\0\x10\x5f\x23\0\0\0\0\0\0\xbf\x42\0\0\0\0\0\0\x55\x03\x01\0\0\0\
+\0\0\x05\0\x63\xf3\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\
+\x61\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\
+\0\x18\x01\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\xb7\x02\0\0\x09\0\0\0\x79\xa6\x90\xff\
+\0\0\0\0\xbf\x63\0\0\0\0\0\0\x85\0\0\0\x06\0\0\0\xb7\x07\0\0\0\0\0\0\x67\x06\0\
+\0\x20\0\0\0\x77\x06\0\0\x20\0\0\0\x15\x06\x14\0\0\0\0\0\x79\xa3\x80\xff\0\0\0\
+\0\x71\x31\x2d\0\0\0\0\0\x67\x01\0\0\x08\0\0\0\x71\x32\x2c\0\0\0\0\0\x4f\x21\0\
+\0\0\0\0\0\x71\x32\x2e\0\0\0\0\0\x67\x02\0\0\x10\0\0\0\x71\x33\x2f\0\0\0\0\0\
+\x67\x03\0\0\x18\0\0\0\x4f\x23\0\0\0\0\0\0\x4f\x13\0\0\0\0\0\0\x2f\x63\0\0\0\0\
+\0\0\x77\x03\0\0\x20\0\0\0\x79\xa1\x88\xff\0\0\0\0\x63\x31\x0c\0\0\0\0\0\x18\
+\x01\0\0\x24\0\0\0\0\0\0\0\0\0\0\0\xb7\x02\0\0\x0a\0\0\0\x85\0\0\0\x06\0\0\0\
+\xb7\x07\0\0\x03\0\0\0\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x72\x73\x73\x5f\
+\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x69\x64\
+\x3a\x25\x75\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x68\x61\x73\x68\x28\x29\x3a\x20\x72\x73\x73\x20\x6e\x6f\x74\x20\
+\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\x64\0\x68\x61\x73\x68\x20\x25\x75\x0a\0\
+\x71\x75\x65\x75\x65\x20\x25\x75\x0a\0\x44\x75\x61\x6c\x20\x42\x53\x44\x2f\x47\
+\x50\x4c\0\x31\x4f\0\0\x05\0\x08\0\x22\0\0\0\x88\0\0\0\xa9\0\0\0\xb4\0\0\0\xd1\
+\0\0\0\xe7\0\0\0\xfd\0\0\0\x13\x01\0\0\x30\x01\0\0\x43\x01\0\0\x58\x01\0\0\x6b\
+\x01\0\0\xec\x01\0\0\xe5\x03\0\0\xf6\x03\0\0\x57\x07\0\0\x80\x07\0\0\x87\x0b\0\
+\0\x9d\x0b\0\0\xb1\x0b\0\0\xe5\x0b\0\0\xfb\x14\0\0\x45\x15\0\0\xfd\x24\0\0\xb4\
+\x28\0\0\xd3\x28\0\0\x5f\x2f\0\0\x74\x2f\0\0\x8a\x2f\0\0\xc7\x2f\0\0\xdc\x2f\0\
+\0\xf2\x2f\0\0\xfe\x2f\0\0\x35\x3b\0\0\x90\x3b\0\0\x04\0\x08\x01\x51\x04\x08\
+\xe8\x01\x01\x57\x04\xf0\x01\xa8\x02\x01\x57\x04\xd8\x02\x98\x03\x01\x57\x04\
+\xf8\x30\xa0\x31\x01\x57\0\x04\x90\x01\xc8\xed\x03\x03\x7a\xde\0\0\x04\xb8\x01\
+\xe0\x01\x01\x50\x04\xf0\x01\xd0\x02\x01\x50\x04\xd8\x02\xd8\x03\x01\x50\x04\
+\xf8\x30\xf8\x31\x01\x50\0\x04\xf8\x01\xa0\x02\x01\x52\x04\xd8\x02\xa0\x03\x01\
+\x52\x04\xf8\x30\xc0\x31\x01\x52\0\x04\xf8\x01\xa0\x02\x01\x57\x04\xd8\x02\x98\
+\x03\x01\x57\x04\xf8\x30\xa0\x31\x01\x57\0\x04\x88\x02\xa0\x02\x01\x53\x04\xd8\
+\x02\xb0\x03\x01\x53\x04\xf8\x30\xd0\x31\x01\x53\0\x04\xa0\x02\xd8\x02\x02\x30\
+\x9f\x04\xc8\xeb\x03\xe8\xeb\x03\x03\x7a\xc0\0\x04\xe8\xeb\x03\x88\xec\x03\x01\
+\x56\0\x04\x98\x03\xf8\x30\x02\x30\x9f\x04\xb0\xdf\x01\xe8\xdf\x01\x02\x30\x9f\
+\0\x04\x98\x03\xf8\x30\x03\x7a\xc8\0\x04\xb0\xdf\x01\xf0\xa0\x02\x03\x7a\xc8\0\
+\0\x04\xc0\x03\xf8\x30\x02\x7a\x38\x04\xb0\xdf\x01\xf0\xa0\x02\x02\x7a\x38\0\
+\x04\xa0\x04\xb0\x04\x05\x93\x04\x58\x93\x04\x04\xb0\x04\x98\x1b\x0a\x59\x93\
+\x04\x58\x93\x04\x30\x9f\x93\x04\x04\x98\x1b\xd0\x30\x09\x93\x04\x58\x93\x04\
+\x30\x9f\x93\x04\x04\xd0\x30\xf8\x30\x06\x93\x08\x30\x9f\x93\x04\x04\xb0\xdf\
+\x01\xb8\xe0\x01\x0a\x59\x93\x04\x58\x93\x04\x30\x9f\x93\x04\x04\xb8\xe0\x01\
+\xa8\xf5\x01\x06\x59\x93\x04\x58\x93\x04\x04\xa8\xf5\x01\xf8\x8a\x02\x05\x93\
+\x04\x58\x93\x04\x04\xf8\x8a\x02\x80\x8b\x02\x08\x93\x04\x58\x93\x04\x53\x93\
+\x04\x04\x80\x8b\x02\xa8\xa0\x02\x05\x93\x08\x53\x93\x04\0\x04\xe0\x04\xb0\x05\
+\x02\x31\x9f\x04\xb0\x05\x90\x06\x02\x32\x9f\x04\x90\x06\xf0\x06\x02\x33\x9f\
+\x04\xf0\x06\xd0\x07\x02\x34\x9f\x04\xd0\x07\xb0\x08\x02\x35\x9f\x04\xb0\x08\
+\x90\x09\x02\x36\x9f\x04\x90\x09\xf0\x09\x02\x37\x9f\x04\xf0\x09\xd0\x0a\x02\
+\x38\x9f\x04\xd0\x0a\xb0\x0b\x02\x39\x9f\x04\xb0\x0b\x90\x0c\x02\x3a\x9f\x04\
+\x90\x0c\xf0\x0c\x02\x3b\x9f\x04\xf0\x0c\xd0\x0d\x02\x3c\x9f\x04\xd0\x0d\xb0\
+\x0e\x02\x3d\x9f\x04\xb0\x0e\x90\x0f\x02\x3e\x9f\x04\x90\x0f\xf0\x0f\x02\x3f\
+\x9f\x04\xf0\x0f\xd0\x10\x02\x40\x9f\x04\xd0\x10\xb0\x11\x02\x41\x9f\x04\xb0\
+\x11\x90\x12\x02\x42\x9f\x04\x90\x12\xf0\x12\x02\x43\x9f\x04\xf0\x12\xd0\x13\
+\x02\x44\x9f\x04\xd0\x13\xb0\x14\x02\x45\x9f\x04\xb0\x14\x90\x15\x02\x46\x9f\
+\x04\x90\x15\xf0\x15\x02\x47\x9f\x04\xf0\x15\xd0\x16\x02\x48\x9f\x04\xd0\x16\
+\xb0\x17\x02\x49\x9f\x04\xb0\x17\x90\x18\x02\x4a\x9f\x04\x90\x18\xf0\x18\x02\
+\x4b\x9f\x04\xf0\x18\xd0\x19\x02\x4c\x9f\x04\xd0\x19\xb0\x1a\x02\x4d\x9f\x04\
+\xb0\x1a\x90\x1b\x02\x4e\x9f\x04\x90\x1b\xe8\x1b\x02\x4f\x9f\x04\xe8\x1b\xf0\
+\x1b\x02\x30\x9f\x04\xf0\x1b\xc8\x1c\x02\x31\x9f\x04\xc8\x1c\xa0\x1d\x02\x32\
+\x9f\x04\xa0\x1d\xf8\x1d\x02\x33\x9f\x04\xf8\x1d\xd0\x1e\x02\x34\x9f\x04\xd0\
+\x1e\xa8\x1f\x02\x35\x9f\x04\xa8\x1f\x80\x20\x02\x36\x9f\x04\x80\x20\xd8\x20\
+\x02\x37\x9f\x04\xd8\x20\xb0\x21\x02\x38\x9f\x04\xb0\x21\x88\x22\x02\x39\x9f\
+\x04\x88\x22\xe0\x22\x02\x3a\x9f\x04\xe0\x22\xb8\x23\x02\x3b\x9f\x04\xb8\x23\
+\x90\x24\x02\x3c\x9f\x04\x90\x24\xe8\x24\x02\x3d\x9f\x04\xe8\x24\xc0\x25\x02\
+\x3e\x9f\x04\xc0\x25\x98\x26\x02\x3f\x9f\x04\x98\x26\xf0\x26\x02\x40\x9f\x04\
+\xf0\x26\xc8\x27\x02\x41\x9f\x04\xc8\x27\xa0\x28\x02\x42\x9f\x04\xa0\x28\xf8\
+\x28\x02\x43\x9f\x04\xf8\x28\xd0\x29\x02\x44\x9f\x04\xd0\x29\xa8\x2a\x02\x45\
+\x9f\x04\xa8\x2a\x80\x2b\x02\x46\x9f\x04\x80\x2b\xd8\x2b\x02\x47\x9f\x04\xd8\
+\x2b\xb0\x2c\x02\x48\x9f\x04\xb0\x2c\x88\x2d\x02\x49\x9f\x04\x88\x2d\xe0\x2d\
+\x02\x4a\x9f\x04\xe0\x2d\xb8\x2e\x02\x4b\x9f\x04\xb8\x2e\x90\x2f\x02\x4c\x9f\
+\x04\x90\x2f\xe8\x2f\x02\x4d\x9f\x04\xe8\x2f\xc0\x30\x02\x4e\x9f\x04\xc0\x30\
+\xf8\x30\x02\x4f\x9f\0\x04\xe0\x04\xe8\x1b\x02\x30\x9f\x04\xe8\x1b\xf8\x30\x02\
+\x31\x9f\0\x04\xe0\x04\xb0\x05\x02\x30\x9f\x04\xb0\x05\x88\x06\x01\x55\x04\x88\
+\x06\x90\x06\x01\x52\x04\x90\x06\xe8\x06\x01\x55\x04\xe8\x06\xf0\x06\x01\x52\
+\x04\xf0\x06\xc8\x07\x01\x55\x04\xc8\x07\xd0\x07\x01\x52\x04\xd0\x07\xa8\x08\
+\x01\x55\x04\xa8\x08\xb0\x08\x01\x52\x04\xb0\x08\x88\x09\x01\x55\x04\x88\x09\
+\x90\x09\x01\x52\x04\x90\x09\xe8\x09\x01\x55\x04\xe8\x09\xf0\x09\x01\x52\x04\
+\xf0\x09\xc8\x0a\x01\x55\x04\xc8\x0a\xd0\x0a\x01\x52\x04\xd0\x0a\xa8\x0b\x01\
+\x55\x04\xa8\x0b\xb0\x0b\x01\x52\x04\xb0\x0b\x88\x0c\x01\x55\x04\x88\x0c\x90\
+\x0c\x01\x52\x04\x90\x0c\xe8\x0c\x01\x55\x04\xe8\x0c\xf0\x0c\x01\x52\x04\xf0\
+\x0c\xc8\x0d\x01\x55\x04\xc8\x0d\xd0\x0d\x01\x52\x04\xd0\x0d\xa8\x0e\x01\x55\
+\x04\xa8\x0e\xb0\x0e\x01\x52\x04\xb0\x0e\x88\x0f\x01\x55\x04\x88\x0f\x90\x0f\
+\x01\x52\x04\x90\x0f\xe8\x0f\x01\x55\x04\xe8\x0f\xf0\x0f\x01\x52\x04\xf0\x0f\
+\xc8\x10\x01\x55\x04\xc8\x10\xd0\x10\x01\x52\x04\xd0\x10\xa8\x11\x01\x55\x04\
+\xa8\x11\xb0\x11\x01\x52\x04\xb0\x11\x88\x12\x01\x55\x04\x88\x12\x90\x12\x01\
+\x52\x04\x90\x12\xe8\x12\x01\x55\x04\xe8\x12\xf0\x12\x01\x52\x04\xf0\x12\xc8\
+\x13\x01\x55\x04\xc8\x13\xd0\x13\x01\x52\x04\xd0\x13\xa8\x14\x01\x55\x04\xa8\
+\x14\xb0\x14\x01\x52\x04\xb0\x14\x88\x15\x01\x55\x04\x88\x15\x90\x15\x01\x52\
+\x04\x90\x15\xe8\x15\x01\x55\x04\xe8\x15\xf0\x15\x01\x52\x04\xf0\x15\xc8\x16\
+\x01\x55\x04\xc8\x16\xd0\x16\x01\x52\x04\xd0\x16\xa8\x17\x01\x55\x04\xa8\x17\
+\xb0\x17\x01\x52\x04\xb0\x17\x88\x18\x01\x55\x04\x88\x18\x90\x18\x01\x52\x04\
+\x90\x18\xe8\x18\x01\x55\x04\xe8\x18\xf0\x18\x01\x52\x04\xf0\x18\xc8\x19\x01\
+\x55\x04\xc8\x19\xd0\x19\x01\x52\x04\xd0\x19\xa8\x1a\x01\x55\x04\xa8\x1a\xb0\
+\x1a\x01\x52\x04\xb0\x1a\x88\x1b\x01\x55\x04\x88\x1b\x90\x1b\x01\x52\x04\x90\
+\x1b\xe0\x1b\x01\x55\x04\xe0\x1b\xe8\x1b\x01\x52\x04\xe8\x1b\xc0\x1c\x01\x55\
+\x04\xc0\x1c\xc8\x1c\x01\x52\x04\xc8\x1c\x98\x1d\x01\x55\x04\x98\x1d\xa0\x1d\
+\x01\x52\x04\xa0\x1d\xf0\x1d\x01\x55\x04\xf0\x1d\xf8\x1d\x01\x52\x04\xf8\x1d\
+\xc8\x1e\x01\x55\x04\xc8\x1e\xd0\x1e\x01\x52\x04\xd0\x1e\xa0\x1f\x01\x55\x04\
+\xa0\x1f\xa8\x1f\x01\x52\x04\xa8\x1f\xf8\x1f\x01\x55\x04\xf8\x1f\x80\x20\x01\
+\x52\x04\x80\x20\xd0\x20\x01\x55\x04\xd0\x20\xd8\x20\x01\x52\x04\xd8\x20\xa8\
+\x21\x01\x55\x04\xa8\x21\xb0\x21\x01\x52\x04\xb0\x21\x80\x22\x01\x55\x04\x80\
+\x22\x88\x22\x01\x52\x04\x88\x22\xd8\x22\x01\x55\x04\xd8\x22\xe0\x22\x01\x52\
+\x04\xe0\x22\xb0\x23\x01\x55\x04\xb0\x23\xb8\x23\x01\x52\x04\xb8\x23\x88\x24\
+\x01\x55\x04\x88\x24\x90\x24\x01\x52\x04\x90\x24\xe0\x24\x01\x55\x04\xe0\x24\
+\xe8\x24\x01\x52\x04\xe8\x24\xb8\x25\x01\x55\x04\xb8\x25\xc0\x25\x01\x52\x04\
+\xc0\x25\x90\x26\x01\x55\x04\x90\x26\x98\x26\x01\x52\x04\x98\x26\xe8\x26\x01\
+\x55\x04\xe8\x26\xf0\x26\x01\x52\x04\xf0\x26\xc0\x27\x01\x55\x04\xc0\x27\xc8\
+\x27\x01\x52\x04\xc8\x27\x98\x28\x01\x55\x04\x98\x28\xa0\x28\x01\x52\x04\xa0\
+\x28\xf0\x28\x01\x55\x04\xf0\x28\xf8\x28\x01\x52\x04\xf8\x28\xc8\x29\x01\x55\
+\x04\xc8\x29\xd0\x29\x01\x52\x04\xd0\x29\xa0\x2a\x01\x55\x04\xa0\x2a\xa8\x2a\
+\x01\x52\x04\xa8\x2a\xf8\x2a\x01\x55\x04\xf8\x2a\x80\x2b\x01\x52\x04\x80\x2b\
+\xd0\x2b\x01\x55\x04\xd0\x2b\xd8\x2b\x01\x52\x04\xd8\x2b\xa8\x2c\x01\x55\x04\
+\xa8\x2c\xb0\x2c\x01\x52\x04\xb0\x2c\x80\x2d\x01\x55\x04\x80\x2d\x88\x2d\x01\
+\x52\x04\x88\x2d\xd8\x2d\x01\x55\x04\xd8\x2d\xe0\x2d\x01\x52\x04\xe0\x2d\xb0\
+\x2e\x01\x55\x04\xb0\x2e\xb8\x2e\x01\x52\x04\xb8\x2e\x88\x2f\x01\x55\x04\x88\
+\x2f\x90\x2f\x01\x52\x04\x90\x2f\xe0\x2f\x01\x55\x04\xe0\x2f\xe8\x2f\x01\x52\
+\x04\xe8\x2f\xb8\x30\x01\x55\x04\xb8\x30\xc0\x30\x01\x52\x04\xc0\x30\xc8\x30\
+\x01\x55\x04\xc8\x30\xf8\x30\x03\x7a\xc0\0\0\x04\xb8\x31\xf8\xde\x01\x02\x30\
+\x9f\x04\x80\xa1\x02\xc0\xa1\x02\x03\x10\x28\x9f\x04\xc0\xa1\x02\xf8\xa1\x02\
+\x01\x52\x04\xf8\xe4\x03\xc8\xeb\x03\x03\x10\x28\x9f\0\x04\xb8\x31\xc0\x32\x24\
+\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\
+\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x04\xc0\
+\x32\xc8\x32\x23\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\
+\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x51\x93\x04\x30\x9f\x93\
+\x04\x04\xc8\x32\xd8\x32\x24\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\
+\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x7a\x18\x93\
+\x04\x30\x9f\x93\x04\x04\xd8\x32\xe0\x32\x23\x30\x9f\x93\x04\x30\x9f\x93\x04\
+\x30\x9f\x93\x04\x51\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\
+\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xe0\x32\xf0\x32\x24\x30\x9f\x93\x04\x30\
+\x9f\x93\x04\x30\x9f\x93\x04\x7a\x20\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\
+\x30\x9f\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xf0\x32\x80\x33\x23\x30\
+\x9f\x93\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x7a\x20\x93\x04\x30\x9f\x93\x04\
+\x30\x9f\x93\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\x80\x33\x88\
+\x33\x22\x30\x9f\x93\x04\x30\x9f\x93\x04\x51\x93\x04\x7a\x20\x93\x04\x30\x9f\
+\x93\x04\x30\x9f\x93\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\x88\
+\x33\x98\x33\x24\x30\x9f\x93\x04\x30\x9f\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\
+\x04\x30\x9f\x93\x04\x30\x9f\x93\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\
+\x04\x04\x98\x33\xa0\x33\x23\x30\x9f\x93\x04\x30\x9f\x93\x04\x7a\xd0\0\x93\x04\
+\x7a\x20\x93\x04\x30\x9f\x93\x04\x51\x93\x04\x50\x93\x04\x7a\x18\x93\x04\x30\
+\x9f\x93\x04\x04\xa0\x33\xb0\x33\x24\x30\x9f\x93\x04\x30\x9f\x93\x04\x7a\xd0\0\
+\x93\x04\x7a\x20\x93\x04\x30\x9f\x93\x04\x7a\x08\x93\x04\x50\x93\x04\x7a\x18\
+\x93\x04\x30\x9f\x93\x04\x04\xb0\x33\xc0\x33\x23\x30\x9f\x93\x04\x57\x93\x04\
+\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x30\x9f\x93\x04\x7a\x08\x93\x04\x50\x93\x04\
+\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xc0\x33\xc8\x33\x22\x30\x9f\x93\x04\x57\
+\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x51\x93\x04\x7a\x08\x93\x04\x50\x93\
+\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xc8\x33\xd8\x33\x23\x30\x9f\x93\x04\
+\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\
+\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xd8\x33\xe0\x48\x22\x59\x93\
+\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\
+\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xe0\x48\x98\x5e\x21\x93\
+\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\
+\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\x98\x5e\xa0\xc9\x01\x1e\
+\x93\x08\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\x50\
+\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xa0\xc9\x01\xf8\xde\x01\x1d\x93\
+\x08\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\x93\x04\
+\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\x80\xa1\x02\xb0\xa1\x02\x22\x59\x93\x04\
+\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\
+\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xb0\xa1\x02\x80\xa2\x02\x21\
+\x59\x93\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\
+\x08\x93\x04\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\x80\xa2\x02\xf8\xb8\
+\x02\x1d\x59\x93\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\
+\x04\x7a\x08\x93\x04\x93\x04\x7a\x18\x93\x04\x04\xf8\xb8\x02\xb8\xce\x02\x1c\
+\x93\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\
+\x93\x04\x93\x04\x7a\x18\x93\x04\x04\xb8\xce\x02\x90\xcf\x03\x19\x93\x08\x7a\
+\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\x93\x04\x7a\x18\
+\x93\x04\x04\x90\xcf\x03\xd0\xe4\x03\x1c\x93\x08\x7a\xd0\0\x93\x04\x7a\x20\x93\
+\x04\x7a\x10\x93\x04\x7a\x08\x93\x04\x93\x04\x7a\x18\x93\x04\x53\x93\x04\x04\
+\xd0\xe4\x03\xf8\xe4\x03\x19\x93\x08\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\
+\x93\x04\x7a\x08\x93\x04\x93\x04\x7a\x18\x93\x04\x04\xf8\xe4\x03\xc0\xe5\x03\
+\x22\x59\x93\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\x10\x93\x04\
+\x7a\x08\x93\x04\x50\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\x04\xc0\xe5\x03\
+\xc8\xeb\x03\x21\x59\x93\x04\x57\x93\x04\x7a\xd0\0\x93\x04\x7a\x20\x93\x04\x7a\
+\x10\x93\x04\x7a\x08\x93\x04\x93\x04\x7a\x18\x93\x04\x30\x9f\x93\x04\0\x04\xb8\
+\x31\xf8\xde\x01\x03\x7a\xc8\0\x04\x80\xa1\x02\xc8\xeb\x03\x03\x7a\xc8\0\0\x04\
+\xe0\x31\xf8\xde\x01\x02\x7a\x38\x04\x80\xa1\x02\xc8\xeb\x03\x02\x7a\x38\0\x04\
+\xb0\x32\xc0\x32\x02\x30\x9f\x04\xc0\x32\xf0\x32\x02\x33\x9f\x04\xf0\x32\x98\
+\x33\x02\x32\x9f\x04\x98\x33\xd8\x33\x02\x31\x9f\x04\xd8\x33\xf8\xde\x01\x02\
+\x34\x9f\x04\x80\xa1\x02\xc8\xeb\x03\x02\x34\x9f\0\x04\xf8\x33\xd0\x34\x02\x31\
+\x9f\x04\xd0\x34\xb0\x35\x02\x32\x9f\x04\xb0\x35\x90\x36\x02\x33\x9f\x04\x90\
+\x36\xe8\x36\x02\x34\x9f\x04\xe8\x36\xc0\x37\x02\x35\x9f\x04\xc0\x37\x98\x38\
+\x02\x36\x9f\x04\x98\x38\xf0\x38\x02\x37\x9f\x04\xf0\x38\xc8\x39\x02\x38\x9f\
+\x04\xc8\x39\xa0\x3a\x02\x39\x9f\x04\xa0\x3a\xf8\x3a\x02\x3a\x9f\x04\xf8\x3a\
+\xd0\x3b\x02\x3b\x9f\x04\xd0\x3b\xa8\x3c\x02\x3c\x9f\x04\xa8\x3c\x80\x3d\x02\
+\x3d\x9f\x04\x80\x3d\xd8\x3d\x02\x3e\x9f\x04\xd8\x3d\xb0\x3e\x02\x3f\x9f\x04\
+\xb0\x3e\x88\x3f\x02\x40\x9f\x04\x88\x3f\xe0\x3f\x02\x41\x9f\x04\xe0\x3f\xb8\
+\x40\x02\x42\x9f\x04\xb8\x40\x90\x41\x02\x43\x9f\x04\x90\x41\xe8\x41\x02\x44\
+\x9f\x04\xe8\x41\xc0\x42\x02\x45\x9f\x04\xc0\x42\x98\x43\x02\x46\x9f\x04\x98\
+\x43\xf0\x43\x02\x47\x9f\x04\xf0\x43\xc8\x44\x02\x48\x9f\x04\xc8\x44\xa0\x45\
+\x02\x49\x9f\x04\xa0\x45\xf8\x45\x02\x4a\x9f\x04\xf8\x45\xd0\x46\x02\x4b\x9f\
+\x04\xd0\x46\xa8\x47\x02\x4c\x9f\x04\xa8\x47\x80\x48\x02\x4d\x9f\x04\x80\x48\
+\xd8\x48\x02\x4e\x9f\x04\xd8\x48\xa8\x49\x02\x4f\x9f\x04\xa8\x49\xb8\x49\x02\
+\x30\x9f\x04\xb8\x49\x90\x4a\x02\x31\x9f\x04\x90\x4a\xf0\x4a\x02\x32\x9f\x04\
+\xf0\x4a\xc8\x4b\x02\x33\x9f\x04\xc8\x4b\xa0\x4c\x02\x34\x9f\x04\xa0\x4c\xf8\
+\x4c\x02\x35\x9f\x04\xf8\x4c\xd0\x4d\x02\x36\x9f\x04\xd0\x4d\xa8\x4e\x02\x37\
+\x9f\x04\xa8\x4e\x80\x4f\x02\x38\x9f\x04\x80\x4f\xd8\x4f\x02\x39\x9f\x04\xd8\
+\x4f\xb0\x50\x02\x3a\x9f\x04\xb0\x50\x88\x51\x02\x3b\x9f\x04\x88\x51\xe0\x51\
+\x02\x3c\x9f\x04\xe0\x51\xb8\x52\x02\x3d\x9f\x04\xb8\x52\x90\x53\x02\x3e\x9f\
+\x04\x90\x53\xe8\x53\x02\x3f\x9f\x04\xe8\x53\xc0\x54\x02\x40\x9f\x04\xc0\x54\
+\x98\x55\x02\x41\x9f\x04\x98\x55\xf0\x55\x02\x42\x9f\x04\xf0\x55\xc8\x56\x02\
+\x43\x9f\x04\xc8\x56\xa0\x57\x02\x44\x9f\x04\xa0\x57\xf8\x57\x02\x45\x9f\x04\
+\xf8\x57\xd0\x58\x02\x46\x9f\x04\xd0\x58\xa8\x59\x02\x47\x9f\x04\xa8\x59\x80\
+\x5a\x02\x48\x9f\x04\x80\x5a\xd8\x5a\x02\x49\x9f\x04\xd8\x5a\xb0\x5b\x02\x4a\
+\x9f\x04\xb0\x5b\x88\x5c\x02\x4b\x9f\x04\x88\x5c\xe0\x5c\x02\x4c\x9f\x04\xe0\
+\x5c\xb8\x5d\x02\x4d\x9f\x04\xb8\x5d\x90\x5e\x02\x4e\x9f\x04\x90\x5e\xe0\x5e\
+\x02\x4f\x9f\x04\xe0\x5e\xf8\x5e\x02\x30\x9f\x04\xf8\x5e\xd0\x5f\x02\x31\x9f\
+\x04\xd0\x5f\xa8\x60\x02\x32\x9f\x04\xa8\x60\x80\x61\x02\x33\x9f\x04\x80\x61\
+\xd8\x61\x02\x34\x9f\x04\xd8\x61\xb0\x62\x02\x35\x9f\x04\xb0\x62\x88\x63\x02\
+\x36\x9f\x04\x88\x63\xe0\x63\x02\x37\x9f\x04\xe0\x63\xb8\x64\x02\x38\x9f\x04\
+\xb8\x64\x90\x65\x02\x39\x9f\x04\x90\x65\xe8\x65\x02\x3a\x9f\x04\xe8\x65\xc0\
+\x66\x02\x3b\x9f\x04\xc0\x66\x98\x67\x02\x3c\x9f\x04\x98\x67\xf0\x67\x02\x3d\
+\x9f\x04\xf0\x67\xc8\x68\x02\x3e\x9f\x04\xc8\x68\xa0\x69\x02\x3f\x9f\x04\xa0\
+\x69\xf8\x69\x02\x40\x9f\x04\xf8\x69\xd0\x6a\x02\x41\x9f\x04\xd0\x6a\xa8\x6b\
+\x02\x42\x9f\x04\xa8\x6b\x80\x6c\x02\x43\x9f\x04\x80\x6c\xd8\x6c\x02\x44\x9f\
+\x04\xd8\x6c\xb0\x6d\x02\x45\x9f\x04\xb0\x6d\x88\x6e\x02\x46\x9f\x04\x88\x6e\
+\xe0\x6e\x02\x47\x9f\x04\xe0\x6e\xb8\x6f\x02\x48\x9f\x04\xb8\x6f\x90\x70\x02\
+\x49\x9f\x04\x90\x70\xe8\x70\x02\x4a\x9f\x04\xe8\x70\xc0\x71\x02\x4b\x9f\x04\
+\xc0\x71\x98\x72\x02\x4c\x9f\x04\x98\x72\xf0\x72\x02\x4d\x9f\x04\xf0\x72\xc8\
+\x73\x02\x4e\x9f\x04\xc8\x73\xa0\x74\x02\x4f\x9f\x04\xa0\x74\xb0\x74\x02\x30\
+\x9f\x04\xb0\x74\x88\x75\x02\x31\x9f\x04\x88\x75\xe0\x75\x02\x32\x9f\x04\xe0\
+\x75\xb8\x76\x02\x33\x9f\x04\xb8\x76\x90\x77\x02\x34\x9f\x04\x90\x77\xe8\x77\
+\x02\x35\x9f\x04\xe8\x77\xc0\x78\x02\x36\x9f\x04\xc0\x78\x98\x79\x02\x37\x9f\
+\x04\x98\x79\xf0\x79\x02\x38\x9f\x04\xf0\x79\xc8\x7a\x02\x39\x9f\x04\xc8\x7a\
+\xa0\x7b\x02\x3a\x9f\x04\xa0\x7b\xf8\x7b\x02\x3b\x9f\x04\xf8\x7b\xd0\x7c\x02\
+\x3c\x9f\x04\xd0\x7c\xa8\x7d\x02\x3d\x9f\x04\xa8\x7d\x80\x7e\x02\x3e\x9f\x04\
+\x80\x7e\xd8\x7e\x02\x3f\x9f\x04\xd8\x7e\xb0\x7f\x02\x40\x9f\x04\xb0\x7f\x88\
+\x80\x01\x02\x41\x9f\x04\x88\x80\x01\xe0\x80\x01\x02\x42\x9f\x04\xe0\x80\x01\
+\xb8\x81\x01\x02\x43\x9f\x04\xb8\x81\x01\x90\x82\x01\x02\x44\x9f\x04\x90\x82\
+\x01\xe8\x82\x01\x02\x45\x9f\x04\xe8\x82\x01\xc0\x83\x01\x02\x46\x9f\x04\xc0\
+\x83\x01\x98\x84\x01\x02\x47\x9f\x04\x98\x84\x01\xf0\x84\x01\x02\x48\x9f\x04\
+\xf0\x84\x01\xc8\x85\x01\x02\x49\x9f\x04\xc8\x85\x01\xa0\x86\x01\x02\x4a\x9f\
+\x04\xa0\x86\x01\xf8\x86\x01\x02\x4b\x9f\x04\xf8\x86\x01\xd0\x87\x01\x02\x4c\
+\x9f\x04\xd0\x87\x01\xa8\x88\x01\x02\x4d\x9f\x04\xa8\x88\x01\x80\x89\x01\x02\
+\x4e\x9f\x04\x80\x89\x01\xd0\x89\x01\x02\x4f\x9f\x04\xd0\x89\x01\xe0\x89\x01\
+\x02\x30\x9f\x04\xe0\x89\x01\xb8\x8a\x01\x02\x31\x9f\x04\xb8\x8a\x01\x90\x8b\
+\x01\x02\x32\x9f\x04\x90\x8b\x01\xe8\x8b\x01\x02\x33\x9f\x04\xe8\x8b\x01\xc0\
+\x8c\x01\x02\x34\x9f\x04\xc0\x8c\x01\x98\x8d\x01\x02\x35\x9f\x04\x98\x8d\x01\
+\xf0\x8d\x01\x02\x36\x9f\x04\xf0\x8d\x01\xc8\x8e\x01\x02\x37\x9f\x04\xc8\x8e\
+\x01\xa0\x8f\x01\x02\x38\x9f\x04\xa0\x8f\x01\xf8\x8f\x01\x02\x39\x9f\x04\xf8\
+\x8f\x01\xd0\x90\x01\x02\x3a\x9f\x04\xd0\x90\x01\xa8\x91\x01\x02\x3b\x9f\x04\
+\xa8\x91\x01\x80\x92\x01\x02\x3c\x9f\x04\x80\x92\x01\xd8\x92\x01\x02\x3d\x9f\
+\x04\xd8\x92\x01\xb0\x93\x01\x02\x3e\x9f\x04\xb0\x93\x01\x88\x94\x01\x02\x3f\
+\x9f\x04\x88\x94\x01\xe0\x94\x01\x02\x40\x9f\x04\xe0\x94\x01\xb8\x95\x01\x02\
+\x41\x9f\x04\xb8\x95\x01\x90\x96\x01\x02\x42\x9f\x04\x90\x96\x01\xe8\x96\x01\
+\x02\x43\x9f\x04\xe8\x96\x01\xc0\x97\x01\x02\x44\x9f\x04\xc0\x97\x01\x98\x98\
+\x01\x02\x45\x9f\x04\x98\x98\x01\xf0\x98\x01\x02\x46\x9f\x04\xf0\x98\x01\xc8\
+\x99\x01\x02\x47\x9f\x04\xc8\x99\x01\xa0\x9a\x01\x02\x48\x9f\x04\xa0\x9a\x01\
+\xf8\x9a\x01\x02\x49\x9f\x04\xf8\x9a\x01\xd0\x9b\x01\x02\x4a\x9f\x04\xd0\x9b\
+\x01\xa8\x9c\x01\x02\x4b\x9f\x04\xa8\x9c\x01\x80\x9d\x01\x02\x4c\x9f\x04\x80\
+\x9d\x01\xd8\x9d\x01\x02\x4d\x9f\x04\xd8\x9d\x01\xb0\x9e\x01\x02\x4e\x9f\x04\
+\xb0\x9e\x01\x80\x9f\x01\x02\x4f\x9f\x04\x80\x9f\x01\x90\x9f\x01\x02\x30\x9f\
+\x04\x90\x9f\x01\xe8\x9f\x01\x02\x31\x9f\x04\xe8\x9f\x01\xc0\xa0\x01\x02\x32\
+\x9f\x04\xc0\xa0\x01\x98\xa1\x01\x02\x33\x9f\x04\x98\xa1\x01\xf0\xa1\x01\x02\
+\x34\x9f\x04\xf0\xa1\x01\xc8\xa2\x01\x02\x35\x9f\x04\xc8\xa2\x01\xa0\xa3\x01\
+\x02\x36\x9f\x04\xa0\xa3\x01\xf8\xa3\x01\x02\x37\x9f\x04\xf8\xa3\x01\xd0\xa4\
+\x01\x02\x38\x9f\x04\xd0\xa4\x01\xa8\xa5\x01\x02\x39\x9f\x04\xa8\xa5\x01\x80\
+\xa6\x01\x02\x3a\x9f\x04\x80\xa6\x01\xd8\xa6\x01\x02\x3b\x9f\x04\xd8\xa6\x01\
+\xb0\xa7\x01\x02\x3c\x9f\x04\xb0\xa7\x01\x88\xa8\x01\x02\x3d\x9f\x04\x88\xa8\
+\x01\xe0\xa8\x01\x02\x3e\x9f\x04\xe0\xa8\x01\xb8\xa9\x01\x02\x3f\x9f\x04\xb8\
+\xa9\x01\x90\xaa\x01\x02\x40\x9f\x04\x90\xaa\x01\xe8\xaa\x01\x02\x41\x9f\x04\
+\xe8\xaa\x01\xc0\xab\x01\x02\x42\x9f\x04\xc0\xab\x01\x98\xac\x01\x02\x43\x9f\
+\x04\x98\xac\x01\xf0\xac\x01\x02\x44\x9f\x04\xf0\xac\x01\xc8\xad\x01\x02\x45\
+\x9f\x04\xc8\xad\x01\xa0\xae\x01\x02\x46\x9f\x04\xa0\xae\x01\xf8\xae\x01\x02\
+\x47\x9f\x04\xf8\xae\x01\xd0\xaf\x01\x02\x48\x9f\x04\xd0\xaf\x01\xa8\xb0\x01\
+\x02\x49\x9f\x04\xa8\xb0\x01\x80\xb1\x01\x02\x4a\x9f\x04\x80\xb1\x01\xd8\xb1\
+\x01\x02\x4b\x9f\x04\xd8\xb1\x01\xb0\xb2\x01\x02\x4c\x9f\x04\xb0\xb2\x01\x88\
+\xb3\x01\x02\x4d\x9f\x04\x88\xb3\x01\xe0\xb3\x01\x02\x4e\x9f\x04\xe0\xb3\x01\
+\xb0\xb4\x01\x02\x4f\x9f\x04\xb0\xb4\x01\xc0\xb4\x01\x02\x30\x9f\x04\xc0\xb4\
+\x01\x98\xb5\x01\x02\x31\x9f\x04\x98\xb5\x01\xf8\xb5\x01\x02\x32\x9f\x04\xf8\
+\xb5\x01\xd0\xb6\x01\x02\x33\x9f\x04\xd0\xb6\x01\xa8\xb7\x01\x02\x34\x9f\x04\
+\xa8\xb7\x01\x80\xb8\x01\x02\x35\x9f\x04\x80\xb8\x01\xd8\xb8\x01\x02\x36\x9f\
+\x04\xd8\xb8\x01\xb0\xb9\x01\x02\x37\x9f\x04\xb0\xb9\x01\x88\xba\x01\x02\x38\
+\x9f\x04\x88\xba\x01\xe0\xba\x01\x02\x39\x9f\x04\xe0\xba\x01\xb8\xbb\x01\x02\
+\x3a\x9f\x04\xb8\xbb\x01\x90\xbc\x01\x02\x3b\x9f\x04\x90\xbc\x01\xe8\xbc\x01\
+\x02\x3c\x9f\x04\xe8\xbc\x01\xc0\xbd\x01\x02\x3d\x9f\x04\xc0\xbd\x01\x98\xbe\
+\x01\x02\x3e\x9f\x04\x98\xbe\x01\xf0\xbe\x01\x02\x3f\x9f\x04\xf0\xbe\x01\xc8\
+\xbf\x01\x02\x40\x9f\x04\xc8\xbf\x01\xa0\xc0\x01\x02\x41\x9f\x04\xa0\xc0\x01\
+\xf8\xc0\x01\x02\x42\x9f\x04\xf8\xc0\x01\xd0\xc1\x01\x02\x43\x9f\x04\xd0\xc1\
+\x01\xa8\xc2\x01\x02\x44\x9f\x04\xa8\xc2\x01\x80\xc3\x01\x02\x45\x9f\x04\x80\
+\xc3\x01\xd8\xc3\x01\x02\x46\x9f\x04\xd8\xc3\x01\xb0\xc4\x01\x02\x47\x9f\x04\
+\xb0\xc4\x01\x88\xc5\x01\x02\x48\x9f\x04\x88\xc5\x01\xe0\xc5\x01\x02\x49\x9f\
+\x04\xe0\xc5\x01\xb8\xc6\x01\x02\x4a\x9f\x04\xb8\xc6\x01\x90\xc7\x01\x02\x4b\
+\x9f\x04\x90\xc7\x01\xe8\xc7\x01\x02\x4c\x9f\x04\xe8\xc7\x01\xc0\xc8\x01\x02\
+\x4d\x9f\x04\xc0\xc8\x01\x98\xc9\x01\x02\x4e\x9f\x04\x98\xc9\x01\xe8\xc9\x01\
+\x02\x4f\x9f\x04\xe8\xc9\x01\xf0\xc9\x01\x02\x30\x9f\x04\xf0\xc9\x01\xc8\xca\
+\x01\x02\x31\x9f\x04\xc8\xca\x01\xa0\xcb\x01\x02\x32\x9f\x04\xa0\xcb\x01\xf8\
+\xcb\x01\x02\x33\x9f\x04\xf8\xcb\x01\xd0\xcc\x01\x02\x34\x9f\x04\xd0\xcc\x01\
+\xa8\xcd\x01\x02\x35\x9f\x04\xa8\xcd\x01\x80\xce\x01\x02\x36\x9f\x04\x80\xce\
+\x01\xd8\xce\x01\x02\x37\x9f\x04\xd8\xce\x01\xb0\xcf\x01\x02\x38\x9f\x04\xb0\
+\xcf\x01\x88\xd0\x01\x02\x39\x9f\x04\x88\xd0\x01\xe0\xd0\x01\x02\x3a\x9f\x04\
+\xe0\xd0\x01\xb8\xd1\x01\x02\x3b\x9f\x04\xb8\xd1\x01\x90\xd2\x01\x02\x3c\x9f\
+\x04\x90\xd2\x01\xe8\xd2\x01\x02\x3d\x9f\x04\xe8\xd2\x01\xc0\xd3\x01\x02\x3e\
+\x9f\x04\xc0\xd3\x01\x98\xd4\x01\x02\x3f\x9f\x04\x98\xd4\x01\xf0\xd4\x01\x02\
+\x40\x9f\x04\xf0\xd4\x01\xc8\xd5\x01\x02\x41\x9f\x04\xc8\xd5\x01\xa0\xd6\x01\
+\x02\x42\x9f\x04\xa0\xd6\x01\xf8\xd6\x01\x02\x43\x9f\x04\xf8\xd6\x01\xd0\xd7\
+\x01\x02\x44\x9f\x04\xd0\xd7\x01\xa8\xd8\x01\x02\x45\x9f\x04\xa8\xd8\x01\x80\
+\xd9\x01\x02\x46\x9f\x04\x80\xd9\x01\xd8\xd9\x01\x02\x47\x9f\x04\xd8\xd9\x01\
+\xb0\xda\x01\x02\x48\x9f\x04\xb0\xda\x01\x88\xdb\x01\x02\x49\x9f\x04\x88\xdb\
+\x01\xe0\xdb\x01\x02\x4a\x9f\x04\xe0\xdb\x01\xb8\xdc\x01\x02\x4b\x9f\x04\xb8\
+\xdc\x01\x90\xdd\x01\x02\x4c\x9f\x04\x90\xdd\x01\xe8\xdd\x01\x02\x4d\x9f\x04\
+\xe8\xdd\x01\xc0\xde\x01\x02\x4e\x9f\x04\xc0\xde\x01\xf8\xde\x01\x02\x4f\x9f\0\
+\x04\xf8\x33\xa8\x49\x02\x30\x9f\x04\xa8\x49\xe0\x5e\x02\x31\x9f\x04\xe0\x5e\
+\xa0\x74\x02\x32\x9f\x04\xa0\x74\xd0\x89\x01\x02\x33\x9f\x04\xd0\x89\x01\x80\
+\x9f\x01\x02\x34\x9f\x04\x80\x9f\x01\xb0\xb4\x01\x02\x35\x9f\x04\xb0\xb4\x01\
+\xe8\xc9\x01\x02\x36\x9f\x04\xe8\xc9\x01\xf8\xde\x01\x02\x37\x9f\0\x04\xf8\x33\
+\xd0\x34\x02\x30\x9f\x04\xd0\x34\xa8\x35\x01\x58\x04\xa8\x35\xb0\x35\x01\x51\
+\x04\xb0\x35\x88\x36\x01\x58\x04\x88\x36\x90\x36\x01\x51\x04\x90\x36\xe0\x36\
+\x01\x58\x04\xe0\x36\xe8\x36\x01\x51\x04\xe8\x36\xb8\x37\x01\x58\x04\xb8\x37\
+\xc0\x37\x01\x51\x04\xc0\x37\x90\x38\x01\x58\x04\x90\x38\x98\x38\x01\x51\x04\
+\x98\x38\xe8\x38\x01\x58\x04\xe8\x38\xf0\x38\x01\x51\x04\xf0\x38\xc0\x39\x01\
+\x58\x04\xc0\x39\xc8\x39\x01\x51\x04\xc8\x39\x98\x3a\x01\x58\x04\x98\x3a\xa0\
+\x3a\x01\x51\x04\xa0\x3a\xf0\x3a\x01\x58\x04\xf0\x3a\xf8\x3a\x01\x51\x04\xf8\
+\x3a\xc8\x3b\x01\x58\x04\xc8\x3b\xd0\x3b\x01\x51\x04\xd0\x3b\xa0\x3c\x01\x58\
+\x04\xa0\x3c\xa8\x3c\x01\x51\x04\xa8\x3c\xf8\x3c\x01\x58\x04\xf8\x3c\x80\x3d\
+\x01\x51\x04\x80\x3d\xd0\x3d\x01\x58\x04\xd0\x3d\xd8\x3d\x01\x51\x04\xd8\x3d\
+\xa8\x3e\x01\x58\x04\xa8\x3e\xb0\x3e\x01\x51\x04\xb0\x3e\x80\x3f\x01\x58\x04\
+\x80\x3f\x88\x3f\x01\x51\x04\x88\x3f\xd8\x3f\x01\x58\x04\xd8\x3f\xe0\x3f\x01\
+\x51\x04\xe0\x3f\xb0\x40\x01\x58\x04\xb0\x40\xb8\x40\x01\x51\x04\xb8\x40\x88\
+\x41\x01\x58\x04\x88\x41\x90\x41\x01\x51\x04\x90\x41\xe0\x41\x01\x58\x04\xe0\
+\x41\xe8\x41\x01\x51\x04\xe8\x41\xb8\x42\x01\x58\x04\xb8\x42\xc0\x42\x01\x51\
+\x04\xc0\x42\x90\x43\x01\x58\x04\x90\x43\x98\x43\x01\x51\x04\x98\x43\xe8\x43\
+\x01\x58\x04\xe8\x43\xf0\x43\x01\x51\x04\xf0\x43\xc0\x44\x01\x58\x04\xc0\x44\
+\xc8\x44\x01\x51\x04\xc8\x44\x98\x45\x01\x58\x04\x98\x45\xa0\x45\x01\x51\x04\
+\xa0\x45\xf0\x45\x01\x58\x04\xf0\x45\xf8\x45\x01\x51\x04\xf8\x45\xc8\x46\x01\
+\x58\x04\xc8\x46\xd0\x46\x01\x51\x04\xd0\x46\xa0\x47\x01\x58\x04\xa0\x47\xa8\
+\x47\x01\x51\x04\xa8\x47\xf8\x47\x01\x58\x04\xf8\x47\x80\x48\x01\x51\x04\x80\
+\x48\xd0\x48\x01\x58\x04\xd0\x48\xd8\x48\x01\x51\x04\xd8\x48\xa0\x49\x01\x58\
+\x04\xa0\x49\xa8\x49\x01\x51\x04\xa8\x49\x88\x4a\x01\x58\x04\x88\x4a\x90\x4a\
+\x01\x53\x04\x90\x4a\xe8\x4a\x01\x58\x04\xe8\x4a\xf0\x4a\x01\x53\x04\xf0\x4a\
+\xc0\x4b\x01\x58\x04\xc0\x4b\xc8\x4b\x01\x53\x04\xc8\x4b\x98\x4c\x01\x58\x04\
+\x98\x4c\xa0\x4c\x01\x53\x04\xa0\x4c\xf0\x4c\x01\x58\x04\xf0\x4c\xf8\x4c\x01\
+\x53\x04\xf8\x4c\xc8\x4d\x01\x58\x04\xc8\x4d\xd0\x4d\x01\x53\x04\xd0\x4d\xa0\
+\x4e\x01\x58\x04\xa0\x4e\xa8\x4e\x01\x53\x04\xa8\x4e\xf8\x4e\x01\x58\x04\xf8\
+\x4e\x80\x4f\x01\x53\x04\x80\x4f\xd0\x4f\x01\x58\x04\xd0\x4f\xd8\x4f\x01\x53\
+\x04\xd8\x4f\xa8\x50\x01\x58\x04\xa8\x50\xb0\x50\x01\x53\x04\xb0\x50\x80\x51\
+\x01\x58\x04\x80\x51\x88\x51\x01\x53\x04\x88\x51\xd8\x51\x01\x58\x04\xd8\x51\
+\xe0\x51\x01\x53\x04\xe0\x51\xb0\x52\x01\x58\x04\xb0\x52\xb8\x52\x01\x53\x04\
+\xb8\x52\x88\x53\x01\x58\x04\x88\x53\x90\x53\x01\x53\x04\x90\x53\xe0\x53\x01\
+\x58\x04\xe0\x53\xe8\x53\x01\x53\x04\xe8\x53\xb8\x54\x01\x58\x04\xb8\x54\xc0\
+\x54\x01\x53\x04\xc0\x54\x90\x55\x01\x58\x04\x90\x55\x98\x55\x01\x53\x04\x98\
+\x55\xe8\x55\x01\x58\x04\xe8\x55\xf0\x55\x01\x53\x04\xf0\x55\xc0\x56\x01\x58\
+\x04\xc0\x56\xc8\x56\x01\x53\x04\xc8\x56\x98\x57\x01\x58\x04\x98\x57\xa0\x57\
+\x01\x53\x04\xa0\x57\xf0\x57\x01\x58\x04\xf0\x57\xf8\x57\x01\x53\x04\xf8\x57\
+\xc8\x58\x01\x58\x04\xc8\x58\xd0\x58\x01\x53\x04\xd0\x58\xa0\x59\x01\x58\x04\
+\xa0\x59\xa8\x59\x01\x53\x04\xa8\x59\xf8\x59\x01\x58\x04\xf8\x59\x80\x5a\x01\
+\x53\x04\x80\x5a\xd0\x5a\x01\x58\x04\xd0\x5a\xd8\x5a\x01\x53\x04\xd8\x5a\xa8\
+\x5b\x01\x58\x04\xa8\x5b\xb0\x5b\x01\x53\x04\xb0\x5b\x80\x5c\x01\x58\x04\x80\
+\x5c\x88\x5c\x01\x53\x04\x88\x5c\xd8\x5c\x01\x58\x04\xd8\x5c\xe0\x5c\x01\x53\
+\x04\xe0\x5c\xb0\x5d\x01\x58\x04\xb0\x5d\xb8\x5d\x01\x53\x04\xb8\x5d\x88\x5e\
+\x01\x58\x04\x88\x5e\x90\x5e\x01\x53\x04\x90\x5e\xd8\x5e\x01\x58\x04\xd8\x5e\
+\xe0\x5e\x01\x52\x04\xe0\x5e\xc8\x5f\x01\x58\x04\xc8\x5f\xd0\x5f\x01\x53\x04\
+\xd0\x5f\xa0\x60\x01\x58\x04\xa0\x60\xa8\x60\x01\x53\x04\xa8\x60\xf8\x60\x01\
+\x58\x04\xf8\x60\x80\x61\x01\x53\x04\x80\x61\xd0\x61\x01\x58\x04\xd0\x61\xd8\
+\x61\x01\x53\x04\xd8\x61\xa8\x62\x01\x58\x04\xa8\x62\xb0\x62\x01\x53\x04\xb0\
+\x62\x80\x63\x01\x58\x04\x80\x63\x88\x63\x01\x53\x04\x88\x63\xd8\x63\x01\x58\
+\x04\xd8\x63\xe0\x63\x01\x53\x04\xe0\x63\xb0\x64\x01\x58\x04\xb0\x64\xb8\x64\
+\x01\x53\x04\xb8\x64\x88\x65\x01\x58\x04\x88\x65\x90\x65\x01\x53\x04\x90\x65\
+\xe0\x65\x01\x58\x04\xe0\x65\xe8\x65\x01\x53\x04\xe8\x65\xb8\x66\x01\x58\x04\
+\xb8\x66\xc0\x66\x01\x53\x04\xc0\x66\x90\x67\x01\x58\x04\x90\x67\x98\x67\x01\
+\x53\x04\x98\x67\xe8\x67\x01\x58\x04\xe8\x67\xf0\x67\x01\x53\x04\xf0\x67\xc0\
+\x68\x01\x58\x04\xc0\x68\xc8\x68\x01\x53\x04\xc8\x68\x98\x69\x01\x58\x04\x98\
+\x69\xa0\x69\x01\x53\x04\xa0\x69\xf0\x69\x01\x58\x04\xf0\x69\xf8\x69\x01\x53\
+\x04\xf8\x69\xc8\x6a\x01\x58\x04\xc8\x6a\xd0\x6a\x01\x53\x04\xd0\x6a\xa0\x6b\
+\x01\x58\x04\xa0\x6b\xa8\x6b\x01\x53\x04\xa8\x6b\xf8\x6b\x01\x58\x04\xf8\x6b\
+\x80\x6c\x01\x53\x04\x80\x6c\xd0\x6c\x01\x58\x04\xd0\x6c\xd8\x6c\x01\x53\x04\
+\xd8\x6c\xa8\x6d\x01\x58\x04\xa8\x6d\xb0\x6d\x01\x53\x04\xb0\x6d\x80\x6e\x01\
+\x58\x04\x80\x6e\x88\x6e\x01\x53\x04\x88\x6e\xd8\x6e\x01\x58\x04\xd8\x6e\xe0\
+\x6e\x01\x53\x04\xe0\x6e\xb0\x6f\x01\x58\x04\xb0\x6f\xb8\x6f\x01\x53\x04\xb8\
+\x6f\x88\x70\x01\x58\x04\x88\x70\x90\x70\x01\x53\x04\x90\x70\xe0\x70\x01\x58\
+\x04\xe0\x70\xe8\x70\x01\x53\x04\xe8\x70\xb8\x71\x01\x58\x04\xb8\x71\xc0\x71\
+\x01\x53\x04\xc0\x71\x90\x72\x01\x58\x04\x90\x72\x98\x72\x01\x53\x04\x98\x72\
+\xe8\x72\x01\x58\x04\xe8\x72\xf0\x72\x01\x53\x04\xf0\x72\xc0\x73\x01\x58\x04\
+\xc0\x73\xc8\x73\x01\x53\x04\xc8\x73\x98\x74\x01\x58\x04\x98\x74\xa0\x74\x01\
+\x51\x04\xa0\x74\x80\x75\x01\x58\x04\x80\x75\x88\x75\x01\x53\x04\x88\x75\xd8\
+\x75\x01\x58\x04\xd8\x75\xe0\x75\x01\x53\x04\xe0\x75\xb0\x76\x01\x58\x04\xb0\
+\x76\xb8\x76\x01\x53\x04\xb8\x76\x88\x77\x01\x58\x04\x88\x77\x90\x77\x01\x53\
+\x04\x90\x77\xe0\x77\x01\x58\x04\xe0\x77\xe8\x77\x01\x53\x04\xe8\x77\xb8\x78\
+\x01\x58\x04\xb8\x78\xc0\x78\x01\x53\x04\xc0\x78\x90\x79\x01\x58\x04\x90\x79\
+\x98\x79\x01\x53\x04\x98\x79\xe8\x79\x01\x58\x04\xe8\x79\xf0\x79\x01\x53\x04\
+\xf0\x79\xc0\x7a\x01\x58\x04\xc0\x7a\xc8\x7a\x01\x53\x04\xc8\x7a\x98\x7b\x01\
+\x58\x04\x98\x7b\xa0\x7b\x01\x53\x04\xa0\x7b\xf0\x7b\x01\x58\x04\xf0\x7b\xf8\
+\x7b\x01\x53\x04\xf8\x7b\xc8\x7c\x01\x58\x04\xc8\x7c\xd0\x7c\x01\x53\x04\xd0\
+\x7c\xa0\x7d\x01\x58\x04\xa0\x7d\xa8\x7d\x01\x53\x04\xa8\x7d\xf8\x7d\x01\x58\
+\x04\xf8\x7d\x80\x7e\x01\x53\x04\x80\x7e\xd0\x7e\x01\x58\x04\xd0\x7e\xd8\x7e\
+\x01\x53\x04\xd8\x7e\xa8\x7f\x01\x58\x04\xa8\x7f\xb0\x7f\x01\x53\x04\xb0\x7f\
+\x80\x80\x01\x01\x58\x04\x80\x80\x01\x88\x80\x01\x01\x53\x04\x88\x80\x01\xd8\
+\x80\x01\x01\x58\x04\xd8\x80\x01\xe0\x80\x01\x01\x53\x04\xe0\x80\x01\xb0\x81\
+\x01\x01\x58\x04\xb0\x81\x01\xb8\x81\x01\x01\x53\x04\xb8\x81\x01\x88\x82\x01\
+\x01\x58\x04\x88\x82\x01\x90\x82\x01\x01\x53\x04\x90\x82\x01\xe0\x82\x01\x01\
+\x58\x04\xe0\x82\x01\xe8\x82\x01\x01\x53\x04\xe8\x82\x01\xb8\x83\x01\x01\x58\
+\x04\xb8\x83\x01\xc0\x83\x01\x01\x53\x04\xc0\x83\x01\x90\x84\x01\x01\x58\x04\
+\x90\x84\x01\x98\x84\x01\x01\x53\x04\x98\x84\x01\xe8\x84\x01\x01\x58\x04\xe8\
+\x84\x01\xf0\x84\x01\x01\x53\x04\xf0\x84\x01\xc0\x85\x01\x01\x58\x04\xc0\x85\
+\x01\xc8\x85\x01\x01\x53\x04\xc8\x85\x01\x98\x86\x01\x01\x58\x04\x98\x86\x01\
+\xa0\x86\x01\x01\x53\x04\xa0\x86\x01\xf0\x86\x01\x01\x58\x04\xf0\x86\x01\xf8\
+\x86\x01\x01\x53\x04\xf8\x86\x01\xc8\x87\x01\x01\x58\x04\xc8\x87\x01\xd0\x87\
+\x01\x01\x53\x04\xd0\x87\x01\xa0\x88\x01\x01\x58\x04\xa0\x88\x01\xa8\x88\x01\
+\x01\x53\x04\xa8\x88\x01\xf8\x88\x01\x01\x58\x04\xf8\x88\x01\x80\x89\x01\x01\
+\x53\x04\x80\x89\x01\xc8\x89\x01\x01\x58\x04\xc8\x89\x01\xd0\x89\x01\x01\x52\
+\x04\xd0\x89\x01\xb0\x8a\x01\x01\x58\x04\xb0\x8a\x01\xb8\x8a\x01\x01\x53\x04\
+\xb8\x8a\x01\x88\x8b\x01\x01\x58\x04\x88\x8b\x01\x90\x8b\x01\x01\x53\x04\x90\
+\x8b\x01\xe0\x8b\x01\x01\x58\x04\xe0\x8b\x01\xe8\x8b\x01\x01\x53\x04\xe8\x8b\
+\x01\xb8\x8c\x01\x01\x58\x04\xb8\x8c\x01\xc0\x8c\x01\x01\x53\x04\xc0\x8c\x01\
+\x90\x8d\x01\x01\x58\x04\x90\x8d\x01\x98\x8d\x01\x01\x53\x04\x98\x8d\x01\xe8\
+\x8d\x01\x01\x58\x04\xe8\x8d\x01\xf0\x8d\x01\x01\x53\x04\xf0\x8d\x01\xc0\x8e\
+\x01\x01\x58\x04\xc0\x8e\x01\xc8\x8e\x01\x01\x53\x04\xc8\x8e\x01\x98\x8f\x01\
+\x01\x58\x04\x98\x8f\x01\xa0\x8f\x01\x01\x53\x04\xa0\x8f\x01\xf0\x8f\x01\x01\
+\x58\x04\xf0\x8f\x01\xf8\x8f\x01\x01\x53\x04\xf8\x8f\x01\xc8\x90\x01\x01\x58\
+\x04\xc8\x90\x01\xd0\x90\x01\x01\x53\x04\xd0\x90\x01\xa0\x91\x01\x01\x58\x04\
+\xa0\x91\x01\xa8\x91\x01\x01\x53\x04\xa8\x91\x01\xf8\x91\x01\x01\x58\x04\xf8\
+\x91\x01\x80\x92\x01\x01\x53\x04\x80\x92\x01\xd0\x92\x01\x01\x58\x04\xd0\x92\
+\x01\xd8\x92\x01\x01\x53\x04\xd8\x92\x01\xa8\x93\x01\x01\x58\x04\xa8\x93\x01\
+\xb0\x93\x01\x01\x53\x04\xb0\x93\x01\x80\x94\x01\x01\x58\x04\x80\x94\x01\x88\
+\x94\x01\x01\x53\x04\x88\x94\x01\xd8\x94\x01\x01\x58\x04\xd8\x94\x01\xe0\x94\
+\x01\x01\x53\x04\xe0\x94\x01\xb0\x95\x01\x01\x58\x04\xb0\x95\x01\xb8\x95\x01\
+\x01\x53\x04\xb8\x95\x01\x88\x96\x01\x01\x58\x04\x88\x96\x01\x90\x96\x01\x01\
+\x53\x04\x90\x96\x01\xe0\x96\x01\x01\x58\x04\xe0\x96\x01\xe8\x96\x01\x01\x53\
+\x04\xe8\x96\x01\xb8\x97\x01\x01\x58\x04\xb8\x97\x01\xc0\x97\x01\x01\x53\x04\
+\xc0\x97\x01\x90\x98\x01\x01\x58\x04\x90\x98\x01\x98\x98\x01\x01\x53\x04\x98\
+\x98\x01\xe8\x98\x01\x01\x58\x04\xe8\x98\x01\xf0\x98\x01\x01\x53\x04\xf0\x98\
+\x01\xc0\x99\x01\x01\x58\x04\xc0\x99\x01\xc8\x99\x01\x01\x53\x04\xc8\x99\x01\
+\x98\x9a\x01\x01\x58\x04\x98\x9a\x01\xa0\x9a\x01\x01\x53\x04\xa0\x9a\x01\xf0\
+\x9a\x01\x01\x58\x04\xf0\x9a\x01\xf8\x9a\x01\x01\x53\x04\xf8\x9a\x01\xc8\x9b\
+\x01\x01\x58\x04\xc8\x9b\x01\xd0\x9b\x01\x01\x53\x04\xd0\x9b\x01\xa0\x9c\x01\
+\x01\x58\x04\xa0\x9c\x01\xa8\x9c\x01\x01\x53\x04\xa8\x9c\x01\xf8\x9c\x01\x01\
+\x58\x04\xf8\x9c\x01\x80\x9d\x01\x01\x53\x04\x80\x9d\x01\xd0\x9d\x01\x01\x58\
+\x04\xd0\x9d\x01\xd8\x9d\x01\x01\x53\x04\xd8\x9d\x01\xa8\x9e\x01\x01\x58\x04\
+\xa8\x9e\x01\xb0\x9e\x01\x01\x53\x04\xb0\x9e\x01\xf8\x9e\x01\x01\x58\x04\xf8\
+\x9e\x01\x80\x9f\x01\x01\x51\x04\x80\x9f\x01\xe0\x9f\x01\x01\x58\x04\xe0\x9f\
+\x01\xe8\x9f\x01\x01\x53\x04\xe8\x9f\x01\xb8\xa0\x01\x01\x58\x04\xb8\xa0\x01\
+\xc0\xa0\x01\x01\x53\x04\xc0\xa0\x01\x90\xa1\x01\x01\x58\x04\x90\xa1\x01\x98\
+\xa1\x01\x01\x53\x04\x98\xa1\x01\xe8\xa1\x01\x01\x58\x04\xe8\xa1\x01\xf0\xa1\
+\x01\x01\x53\x04\xf0\xa1\x01\xc0\xa2\x01\x01\x58\x04\xc0\xa2\x01\xc8\xa2\x01\
+\x01\x53\x04\xc8\xa2\x01\x98\xa3\x01\x01\x58\x04\x98\xa3\x01\xa0\xa3\x01\x01\
+\x53\x04\xa0\xa3\x01\xf0\xa3\x01\x01\x58\x04\xf0\xa3\x01\xf8\xa3\x01\x01\x53\
+\x04\xf8\xa3\x01\xc8\xa4\x01\x01\x58\x04\xc8\xa4\x01\xd0\xa4\x01\x01\x53\x04\
+\xd0\xa4\x01\xa0\xa5\x01\x01\x58\x04\xa0\xa5\x01\xa8\xa5\x01\x01\x53\x04\xa8\
+\xa5\x01\xf8\xa5\x01\x01\x58\x04\xf8\xa5\x01\x80\xa6\x01\x01\x53\x04\x80\xa6\
+\x01\xd0\xa6\x01\x01\x58\x04\xd0\xa6\x01\xd8\xa6\x01\x01\x53\x04\xd8\xa6\x01\
+\xa8\xa7\x01\x01\x58\x04\xa8\xa7\x01\xb0\xa7\x01\x01\x53\x04\xb0\xa7\x01\x80\
+\xa8\x01\x01\x58\x04\x80\xa8\x01\x88\xa8\x01\x01\x53\x04\x88\xa8\x01\xd8\xa8\
+\x01\x01\x58\x04\xd8\xa8\x01\xe0\xa8\x01\x01\x53\x04\xe0\xa8\x01\xb0\xa9\x01\
+\x01\x58\x04\xb0\xa9\x01\xb8\xa9\x01\x01\x53\x04\xb8\xa9\x01\x88\xaa\x01\x01\
+\x58\x04\x88\xaa\x01\x90\xaa\x01\x01\x53\x04\x90\xaa\x01\xe0\xaa\x01\x01\x58\
+\x04\xe0\xaa\x01\xe8\xaa\x01\x01\x53\x04\xe8\xaa\x01\xb8\xab\x01\x01\x58\x04\
+\xb8\xab\x01\xc0\xab\x01\x01\x53\x04\xc0\xab\x01\x90\xac\x01\x01\x58\x04\x90\
+\xac\x01\x98\xac\x01\x01\x53\x04\x98\xac\x01\xe8\xac\x01\x01\x58\x04\xe8\xac\
+\x01\xf0\xac\x01\x01\x53\x04\xf0\xac\x01\xc0\xad\x01\x01\x58\x04\xc0\xad\x01\
+\xc8\xad\x01\x01\x53\x04\xc8\xad\x01\x98\xae\x01\x01\x58\x04\x98\xae\x01\xa0\
+\xae\x01\x01\x53\x04\xa0\xae\x01\xf0\xae\x01\x01\x58\x04\xf0\xae\x01\xf8\xae\
+\x01\x01\x53\x04\xf8\xae\x01\xc8\xaf\x01\x01\x58\x04\xc8\xaf\x01\xd0\xaf\x01\
+\x01\x53\x04\xd0\xaf\x01\xa0\xb0\x01\x01\x58\x04\xa0\xb0\x01\xa8\xb0\x01\x01\
+\x53\x04\xa8\xb0\x01\xf8\xb0\x01\x01\x58\x04\xf8\xb0\x01\x80\xb1\x01\x01\x53\
+\x04\x80\xb1\x01\xd0\xb1\x01\x01\x58\x04\xd0\xb1\x01\xd8\xb1\x01\x01\x53\x04\
+\xd8\xb1\x01\xa8\xb2\x01\x01\x58\x04\xa8\xb2\x01\xb0\xb2\x01\x01\x53\x04\xb0\
+\xb2\x01\x80\xb3\x01\x01\x58\x04\x80\xb3\x01\x88\xb3\x01\x01\x53\x04\x88\xb3\
+\x01\xd8\xb3\x01\x01\x58\x04\xd8\xb3\x01\xe0\xb3\x01\x01\x53\x04\xe0\xb3\x01\
+\xa8\xb4\x01\x01\x58\x04\xa8\xb4\x01\xb0\xb4\x01\x01\x52\x04\xb0\xb4\x01\x90\
+\xb5\x01\x01\x58\x04\x90\xb5\x01\x98\xb5\x01\x01\x53\x04\x98\xb5\x01\xf0\xb5\
+\x01\x01\x58\x04\xf0\xb5\x01\xf8\xb5\x01\x01\x53\x04\xf8\xb5\x01\xc8\xb6\x01\
+\x01\x58\x04\xc8\xb6\x01\xd0\xb6\x01\x01\x53\x04\xd0\xb6\x01\xa0\xb7\x01\x01\
+\x58\x04\xa0\xb7\x01\xa8\xb7\x01\x01\x53\x04\xa8\xb7\x01\xf8\xb7\x01\x01\x58\
+\x04\xf8\xb7\x01\x80\xb8\x01\x01\x53\x04\x80\xb8\x01\xd0\xb8\x01\x01\x58\x04\
+\xd0\xb8\x01\xd8\xb8\x01\x01\x53\x04\xd8\xb8\x01\xa8\xb9\x01\x01\x58\x04\xa8\
+\xb9\x01\xb0\xb9\x01\x01\x53\x04\xb0\xb9\x01\x80\xba\x01\x01\x58\x04\x80\xba\
+\x01\x88\xba\x01\x01\x53\x04\x88\xba\x01\xd8\xba\x01\x01\x58\x04\xd8\xba\x01\
+\xe0\xba\x01\x01\x53\x04\xe0\xba\x01\xb0\xbb\x01\x01\x58\x04\xb0\xbb\x01\xb8\
+\xbb\x01\x01\x53\x04\xb8\xbb\x01\x88\xbc\x01\x01\x58\x04\x88\xbc\x01\x90\xbc\
+\x01\x01\x53\x04\x90\xbc\x01\xe0\xbc\x01\x01\x58\x04\xe0\xbc\x01\xe8\xbc\x01\
+\x01\x53\x04\xe8\xbc\x01\xb8\xbd\x01\x01\x58\x04\xb8\xbd\x01\xc0\xbd\x01\x01\
+\x53\x04\xc0\xbd\x01\x90\xbe\x01\x01\x58\x04\x90\xbe\x01\x98\xbe\x01\x01\x53\
+\x04\x98\xbe\x01\xe8\xbe\x01\x01\x58\x04\xe8\xbe\x01\xf0\xbe\x01\x01\x53\x04\
+\xf0\xbe\x01\xc0\xbf\x01\x01\x58\x04\xc0\xbf\x01\xc8\xbf\x01\x01\x53\x04\xc8\
+\xbf\x01\x98\xc0\x01\x01\x58\x04\x98\xc0\x01\xa0\xc0\x01\x01\x53\x04\xa0\xc0\
+\x01\xf0\xc0\x01\x01\x58\x04\xf0\xc0\x01\xf8\xc0\x01\x01\x53\x04\xf8\xc0\x01\
+\xc8\xc1\x01\x01\x58\x04\xc8\xc1\x01\xd0\xc1\x01\x01\x53\x04\xd0\xc1\x01\xa0\
+\xc2\x01\x01\x58\x04\xa0\xc2\x01\xa8\xc2\x01\x01\x53\x04\xa8\xc2\x01\xf8\xc2\
+\x01\x01\x58\x04\xf8\xc2\x01\x80\xc3\x01\x01\x53\x04\x80\xc3\x01\xd0\xc3\x01\
+\x01\x58\x04\xd0\xc3\x01\xd8\xc3\x01\x01\x53\x04\xd8\xc3\x01\xa8\xc4\x01\x01\
+\x58\x04\xa8\xc4\x01\xb0\xc4\x01\x01\x53\x04\xb0\xc4\x01\x80\xc5\x01\x01\x58\
+\x04\x80\xc5\x01\x88\xc5\x01\x01\x53\x04\x88\xc5\x01\xd8\xc5\x01\x01\x58\x04\
+\xd8\xc5\x01\xe0\xc5\x01\x01\x53\x04\xe0\xc5\x01\xb0\xc6\x01\x01\x58\x04\xb0\
+\xc6\x01\xb8\xc6\x01\x01\x53\x04\xb8\xc6\x01\x88\xc7\x01\x01\x58\x04\x88\xc7\
+\x01\x90\xc7\x01\x01\x53\x04\x90\xc7\x01\xe0\xc7\x01\x01\x58\x04\xe0\xc7\x01\
+\xe8\xc7\x01\x01\x53\x04\xe8\xc7\x01\xb8\xc8\x01\x01\x58\x04\xb8\xc8\x01\xc0\
+\xc8\x01\x01\x53\x04\xc0\xc8\x01\x90\xc9\x01\x01\x58\x04\x90\xc9\x01\x98\xc9\
+\x01\x01\x53\x04\x98\xc9\x01\xe0\xc9\x01\x01\x58\x04\xe0\xc9\x01\xe8\xc9\x01\
+\x01\x51\x04\xe8\xc9\x01\xc0\xca\x01\x01\x58\x04\xc0\xca\x01\xc8\xca\x01\x01\
+\x51\x04\xc8\xca\x01\x98\xcb\x01\x01\x58\x04\x98\xcb\x01\xa0\xcb\x01\x01\x51\
+\x04\xa0\xcb\x01\xf0\xcb\x01\x01\x58\x04\xf0\xcb\x01\xf8\xcb\x01\x01\x51\x04\
+\xf8\xcb\x01\xc8\xcc\x01\x01\x58\x04\xc8\xcc\x01\xd0\xcc\x01\x01\x51\x04\xd0\
+\xcc\x01\xa0\xcd\x01\x01\x58\x04\xa0\xcd\x01\xa8\xcd\x01\x01\x51\x04\xa8\xcd\
+\x01\xf8\xcd\x01\x01\x58\x04\xf8\xcd\x01\x80\xce\x01\x01\x51\x04\x80\xce\x01\
+\xd0\xce\x01\x01\x58\x04\xd0\xce\x01\xd8\xce\x01\x01\x51\x04\xd8\xce\x01\xa8\
+\xcf\x01\x01\x58\x04\xa8\xcf\x01\xb0\xcf\x01\x01\x51\x04\xb0\xcf\x01\x80\xd0\
+\x01\x01\x58\x04\x80\xd0\x01\x88\xd0\x01\x01\x51\x04\x88\xd0\x01\xd8\xd0\x01\
+\x01\x58\x04\xd8\xd0\x01\xe0\xd0\x01\x01\x51\x04\xe0\xd0\x01\xb0\xd1\x01\x01\
+\x58\x04\xb0\xd1\x01\xb8\xd1\x01\x01\x51\x04\xb8\xd1\x01\x88\xd2\x01\x01\x58\
+\x04\x88\xd2\x01\x90\xd2\x01\x01\x51\x04\x90\xd2\x01\xe0\xd2\x01\x01\x58\x04\
+\xe0\xd2\x01\xe8\xd2\x01\x01\x51\x04\xe8\xd2\x01\xb8\xd3\x01\x01\x58\x04\xb8\
+\xd3\x01\xc0\xd3\x01\x01\x51\x04\xc0\xd3\x01\x90\xd4\x01\x01\x58\x04\x90\xd4\
+\x01\x98\xd4\x01\x01\x51\x04\x98\xd4\x01\xe8\xd4\x01\x01\x58\x04\xe8\xd4\x01\
+\xf0\xd4\x01\x01\x51\x04\xf0\xd4\x01\xc0\xd5\x01\x01\x58\x04\xc0\xd5\x01\xc8\
+\xd5\x01\x01\x51\x04\xc8\xd5\x01\x98\xd6\x01\x01\x58\x04\x98\xd6\x01\xa0\xd6\
+\x01\x01\x51\x04\xa0\xd6\x01\xf0\xd6\x01\x01\x58\x04\xf0\xd6\x01\xf8\xd6\x01\
+\x01\x51\x04\xf8\xd6\x01\xc8\xd7\x01\x01\x58\x04\xc8\xd7\x01\xd0\xd7\x01\x01\
+\x51\x04\xd0\xd7\x01\xa0\xd8\x01\x01\x58\x04\xa0\xd8\x01\xa8\xd8\x01\x01\x51\
+\x04\xa8\xd8\x01\xf8\xd8\x01\x01\x58\x04\xf8\xd8\x01\x80\xd9\x01\x01\x51\x04\
+\x80\xd9\x01\xd0\xd9\x01\x01\x58\x04\xd0\xd9\x01\xd8\xd9\x01\x01\x51\x04\xd8\
+\xd9\x01\xa8\xda\x01\x01\x58\x04\xa8\xda\x01\xb0\xda\x01\x01\x51\x04\xb0\xda\
+\x01\x80\xdb\x01\x01\x58\x04\x80\xdb\x01\x88\xdb\x01\x01\x51\x04\x88\xdb\x01\
+\xd8\xdb\x01\x01\x58\x04\xd8\xdb\x01\xe0\xdb\x01\x01\x51\x04\xe0\xdb\x01\xb0\
+\xdc\x01\x01\x58\x04\xb0\xdc\x01\xb8\xdc\x01\x01\x51\x04\xb8\xdc\x01\x88\xdd\
+\x01\x01\x58\x04\x88\xdd\x01\x90\xdd\x01\x01\x51\x04\x90\xdd\x01\xe0\xdd\x01\
+\x01\x58\x04\xe0\xdd\x01\xe8\xdd\x01\x01\x51\x04\xe8\xdd\x01\xb8\xde\x01\x01\
+\x58\x04\xb8\xde\x01\xc0\xde\x01\x01\x51\x04\xc0\xde\x01\xc8\xde\x01\x01\x58\
+\x04\xc8\xde\x01\xf8\xde\x01\x03\x7a\xc0\0\0\x04\xd0\xe0\x01\xa8\xe1\x01\x02\
+\x31\x9f\x04\xa8\xe1\x01\x80\xe2\x01\x02\x32\x9f\x04\x80\xe2\x01\xd8\xe2\x01\
+\x02\x33\x9f\x04\xd8\xe2\x01\xb0\xe3\x01\x02\x34\x9f\x04\xb0\xe3\x01\x88\xe4\
+\x01\x02\x35\x9f\x04\x88\xe4\x01\xe0\xe4\x01\x02\x36\x9f\x04\xe0\xe4\x01\xb8\
+\xe5\x01\x02\x37\x9f\x04\xb8\xe5\x01\x90\xe6\x01\x02\x38\x9f\x04\x90\xe6\x01\
+\xe8\xe6\x01\x02\x39\x9f\x04\xe8\xe6\x01\xc0\xe7\x01\x02\x3a\x9f\x04\xc0\xe7\
+\x01\x98\xe8\x01\x02\x3b\x9f\x04\x98\xe8\x01\xf0\xe8\x01\x02\x3c\x9f\x04\xf0\
+\xe8\x01\xc8\xe9\x01\x02\x3d\x9f\x04\xc8\xe9\x01\xa0\xea\x01\x02\x3e\x9f\x04\
+\xa0\xea\x01\xf8\xea\x01\x02\x3f\x9f\x04\xf8\xea\x01\xd0\xeb\x01\x02\x40\x9f\
+\x04\xd0\xeb\x01\xa8\xec\x01\x02\x41\x9f\x04\xa8\xec\x01\x80\xed\x01\x02\x42\
+\x9f\x04\x80\xed\x01\xd8\xed\x01\x02\x43\x9f\x04\xd8\xed\x01\xb0\xee\x01\x02\
+\x44\x9f\x04\xb0\xee\x01\x88\xef\x01\x02\x45\x9f\x04\x88\xef\x01\xe0\xef\x01\
+\x02\x46\x9f\x04\xe0\xef\x01\xb8\xf0\x01\x02\x47\x9f\x04\xb8\xf0\x01\x90\xf1\
+\x01\x02\x48\x9f\x04\x90\xf1\x01\xe8\xf1\x01\x02\x49\x9f\x04\xe8\xf1\x01\xc0\
+\xf2\x01\x02\x4a\x9f\x04\xc0\xf2\x01\x98\xf3\x01\x02\x4b\x9f\x04\x98\xf3\x01\
+\xf0\xf3\x01\x02\x4c\x9f\x04\xf0\xf3\x01\xc8\xf4\x01\x02\x4d\x9f\x04\xc8\xf4\
+\x01\xa0\xf5\x01\x02\x4e\x9f\x04\xa0\xf5\x01\xf0\xf5\x01\x02\x4f\x9f\x04\xf0\
+\xf5\x01\x80\xf6\x01\x02\x30\x9f\x04\x80\xf6\x01\xd8\xf6\x01\x02\x31\x9f\x04\
+\xd8\xf6\x01\xb0\xf7\x01\x02\x32\x9f\x04\xb0\xf7\x01\x88\xf8\x01\x02\x33\x9f\
+\x04\x88\xf8\x01\xe0\xf8\x01\x02\x34\x9f\x04\xe0\xf8\x01\xb8\xf9\x01\x02\x35\
+\x9f\x04\xb8\xf9\x01\x90\xfa\x01\x02\x36\x9f\x04\x90\xfa\x01\xe8\xfa\x01\x02\
+\x37\x9f\x04\xe8\xfa\x01\xc0\xfb\x01\x02\x38\x9f\x04\xc0\xfb\x01\x98\xfc\x01\
+\x02\x39\x9f\x04\x98\xfc\x01\xf0\xfc\x01\x02\x3a\x9f\x04\xf0\xfc\x01\xc8\xfd\
+\x01\x02\x3b\x9f\x04\xc8\xfd\x01\xa0\xfe\x01\x02\x3c\x9f\x04\xa0\xfe\x01\xf8\
+\xfe\x01\x02\x3d\x9f\x04\xf8\xfe\x01\xd0\xff\x01\x02\x3e\x9f\x04\xd0\xff\x01\
+\xa8\x80\x02\x02\x3f\x9f\x04\xa8\x80\x02\x80\x81\x02\x02\x40\x9f\x04\x80\x81\
+\x02\xd8\x81\x02\x02\x41\x9f\x04\xd8\x81\x02\xb0\x82\x02\x02\x42\x9f\x04\xb0\
+\x82\x02\x88\x83\x02\x02\x43\x9f\x04\x88\x83\x02\xe0\x83\x02\x02\x44\x9f\x04\
+\xe0\x83\x02\xb8\x84\x02\x02\x45\x9f\x04\xb8\x84\x02\x90\x85\x02\x02\x46\x9f\
+\x04\x90\x85\x02\xe8\x85\x02\x02\x47\x9f\x04\xe8\x85\x02\xc0\x86\x02\x02\x48\
+\x9f\x04\xc0\x86\x02\x98\x87\x02\x02\x49\x9f\x04\x98\x87\x02\xf0\x87\x02\x02\
+\x4a\x9f\x04\xf0\x87\x02\xc8\x88\x02\x02\x4b\x9f\x04\xd0\x88\x02\xa8\x89\x02\
+\x02\x4c\x9f\x04\xb8\x89\x02\x90\x8a\x02\x02\x4d\x9f\x04\x98\x8a\x02\xf0\x8a\
+\x02\x02\x4e\x9f\x04\xf8\x8a\x02\xc8\x8b\x02\x02\x4f\x9f\x04\xc8\x8b\x02\xd0\
+\x8b\x02\x02\x30\x9f\x04\xd0\x8b\x02\xa8\x8c\x02\x02\x31\x9f\x04\xa8\x8c\x02\
+\x80\x8d\x02\x02\x32\x9f\x04\x80\x8d\x02\xd8\x8d\x02\x02\x33\x9f\x04\xd8\x8d\
+\x02\xb0\x8e\x02\x02\x34\x9f\x04\xb0\x8e\x02\x88\x8f\x02\x02\x35\x9f\x04\x88\
+\x8f\x02\xe0\x8f\x02\x02\x36\x9f\x04\xe0\x8f\x02\xb8\x90\x02\x02\x37\x9f\x04\
+\xb8\x90\x02\x90\x91\x02\x02\x38\x9f\x04\x90\x91\x02\xe8\x91\x02\x02\x39\x9f\
+\x04\xe8\x91\x02\xc0\x92\x02\x02\x3a\x9f\x04\xc0\x92\x02\x98\x93\x02\x02\x3b\
+\x9f\x04\x98\x93\x02\xf0\x93\x02\x02\x3c\x9f\x04\xf0\x93\x02\xc8\x94\x02\x02\
+\x3d\x9f\x04\xc8\x94\x02\xa0\x95\x02\x02\x3e\x9f\x04\xa0\x95\x02\xf8\x95\x02\
+\x02\x3f\x9f\x04\xf8\x95\x02\xd0\x96\x02\x02\x40\x9f\x04\xd0\x96\x02\xa8\x97\
+\x02\x02\x41\x9f\x04\xa8\x97\x02\x80\x98\x02\x02\x42\x9f\x04\x80\x98\x02\xd8\
+\x98\x02\x02\x43\x9f\x04\xd8\x98\x02\xb0\x99\x02\x02\x44\x9f\x04\xb0\x99\x02\
+\x88\x9a\x02\x02\x45\x9f\x04\x88\x9a\x02\xe0\x9a\x02\x02\x46\x9f\x04\xe0\x9a\
+\x02\xb8\x9b\x02\x02\x47\x9f\x04\xb8\x9b\x02\x90\x9c\x02\x02\x48\x9f\x04\x90\
+\x9c\x02\xe8\x9c\x02\x02\x49\x9f\x04\xe8\x9c\x02\xc0\x9d\x02\x02\x4a\x9f\x04\
+\xc0\x9d\x02\x98\x9e\x02\x02\x4b\x9f\x04\x98\x9e\x02\xf0\x9e\x02\x02\x4c\x9f\
+\x04\xf0\x9e\x02\xc8\x9f\x02\x02\x4d\x9f\x04\xc8\x9f\x02\xa0\xa0\x02\x02\x4e\
+\x9f\x04\xa0\xa0\x02\xf0\xa0\x02\x02\x4f\x9f\0\x04\xd0\xe0\x01\xf0\xf5\x01\x02\
+\x30\x9f\x04\xf0\xf5\x01\xc8\x8b\x02\x02\x31\x9f\x04\xc8\x8b\x02\xf0\xa0\x02\
+\x02\x32\x9f\0\x04\xd0\xe0\x01\xa0\xe1\x01\x02\x30\x9f\x04\xa0\xe1\x01\xa8\xe1\
+\x01\x01\x51\x04\xa8\xe1\x01\xf8\xe1\x01\x01\x57\x04\xf8\xe1\x01\x80\xe2\x01\
+\x01\x51\x04\x80\xe2\x01\xd0\xe2\x01\x01\x57\x04\xd0\xe2\x01\xd8\xe2\x01\x01\
+\x51\x04\xd8\xe2\x01\xa8\xe3\x01\x01\x57\x04\xa8\xe3\x01\xb0\xe3\x01\x01\x51\
+\x04\xb0\xe3\x01\x80\xe4\x01\x01\x57\x04\x80\xe4\x01\x88\xe4\x01\x01\x51\x04\
+\x88\xe4\x01\xd8\xe4\x01\x01\x57\x04\xd8\xe4\x01\xe0\xe4\x01\x01\x51\x04\xe0\
+\xe4\x01\xb0\xe5\x01\x01\x57\x04\xb0\xe5\x01\xb8\xe5\x01\x01\x51\x04\xb8\xe5\
+\x01\x88\xe6\x01\x01\x57\x04\x88\xe6\x01\x90\xe6\x01\x01\x51\x04\x90\xe6\x01\
+\xe0\xe6\x01\x01\x57\x04\xe0\xe6\x01\xe8\xe6\x01\x01\x51\x04\xe8\xe6\x01\xb8\
+\xe7\x01\x01\x57\x04\xb8\xe7\x01\xc0\xe7\x01\x01\x51\x04\xc0\xe7\x01\x90\xe8\
+\x01\x01\x57\x04\x90\xe8\x01\x98\xe8\x01\x01\x51\x04\x98\xe8\x01\xe8\xe8\x01\
+\x01\x57\x04\xe8\xe8\x01\xf0\xe8\x01\x01\x51\x04\xf0\xe8\x01\xc0\xe9\x01\x01\
+\x57\x04\xc0\xe9\x01\xc8\xe9\x01\x01\x51\x04\xc8\xe9\x01\x98\xea\x01\x01\x57\
+\x04\x98\xea\x01\xa0\xea\x01\x01\x51\x04\xa0\xea\x01\xf0\xea\x01\x01\x57\x04\
+\xf0\xea\x01\xf8\xea\x01\x01\x51\x04\xf8\xea\x01\xc8\xeb\x01\x01\x57\x04\xc8\
+\xeb\x01\xd0\xeb\x01\x01\x51\x04\xd0\xeb\x01\xa0\xec\x01\x01\x57\x04\xa0\xec\
+\x01\xa8\xec\x01\x01\x51\x04\xa8\xec\x01\xf8\xec\x01\x01\x57\x04\xf8\xec\x01\
+\x80\xed\x01\x01\x51\x04\x80\xed\x01\xd0\xed\x01\x01\x57\x04\xd0\xed\x01\xd8\
+\xed\x01\x01\x51\x04\xd8\xed\x01\xa8\xee\x01\x01\x57\x04\xa8\xee\x01\xb0\xee\
+\x01\x01\x51\x04\xb0\xee\x01\x80\xef\x01\x01\x57\x04\x80\xef\x01\x88\xef\x01\
+\x01\x51\x04\x88\xef\x01\xd8\xef\x01\x01\x57\x04\xd8\xef\x01\xe0\xef\x01\x01\
+\x51\x04\xe0\xef\x01\xb0\xf0\x01\x01\x57\x04\xb0\xf0\x01\xb8\xf0\x01\x01\x51\
+\x04\xb8\xf0\x01\x88\xf1\x01\x01\x57\x04\x88\xf1\x01\x90\xf1\x01\x01\x51\x04\
+\x90\xf1\x01\xe0\xf1\x01\x01\x57\x04\xe0\xf1\x01\xe8\xf1\x01\x01\x51\x04\xe8\
+\xf1\x01\xb8\xf2\x01\x01\x57\x04\xb8\xf2\x01\xc0\xf2\x01\x01\x51\x04\xc0\xf2\
+\x01\x90\xf3\x01\x01\x57\x04\x90\xf3\x01\x98\xf3\x01\x01\x51\x04\x98\xf3\x01\
+\xe8\xf3\x01\x01\x57\x04\xe8\xf3\x01\xf0\xf3\x01\x01\x51\x04\xf0\xf3\x01\xc0\
+\xf4\x01\x01\x57\x04\xc0\xf4\x01\xc8\xf4\x01\x01\x51\x04\xc8\xf4\x01\x98\xf5\
+\x01\x01\x57\x04\x98\xf5\x01\xa0\xf5\x01\x01\x51\x04\xa0\xf5\x01\xe8\xf5\x01\
+\x01\x57\x04\xe8\xf5\x01\xf0\xf5\x01\x01\x51\x04\xf0\xf5\x01\xd0\xf6\x01\x01\
+\x57\x04\xd0\xf6\x01\xd8\xf6\x01\x01\x53\x04\xd8\xf6\x01\xa8\xf7\x01\x01\x57\
+\x04\xa8\xf7\x01\xb0\xf7\x01\x01\x53\x04\xb0\xf7\x01\x80\xf8\x01\x01\x57\x04\
+\x80\xf8\x01\x88\xf8\x01\x01\x53\x04\x88\xf8\x01\xd8\xf8\x01\x01\x57\x04\xd8\
+\xf8\x01\xe0\xf8\x01\x01\x53\x04\xe0\xf8\x01\xb0\xf9\x01\x01\x57\x04\xb0\xf9\
+\x01\xb8\xf9\x01\x01\x53\x04\xb8\xf9\x01\x88\xfa\x01\x01\x57\x04\x88\xfa\x01\
+\x90\xfa\x01\x01\x53\x04\x90\xfa\x01\xe0\xfa\x01\x01\x57\x04\xe0\xfa\x01\xe8\
+\xfa\x01\x01\x53\x04\xe8\xfa\x01\xb8\xfb\x01\x01\x57\x04\xb8\xfb\x01\xc0\xfb\
+\x01\x01\x53\x04\xc0\xfb\x01\x90\xfc\x01\x01\x57\x04\x90\xfc\x01\x98\xfc\x01\
+\x01\x53\x04\x98\xfc\x01\xe8\xfc\x01\x01\x57\x04\xe8\xfc\x01\xf0\xfc\x01\x01\
+\x53\x04\xf0\xfc\x01\xc0\xfd\x01\x01\x57\x04\xc0\xfd\x01\xc8\xfd\x01\x01\x53\
+\x04\xc8\xfd\x01\x98\xfe\x01\x01\x57\x04\x98\xfe\x01\xa0\xfe\x01\x01\x53\x04\
+\xa0\xfe\x01\xf0\xfe\x01\x01\x57\x04\xf0\xfe\x01\xf8\xfe\x01\x01\x53\x04\xf8\
+\xfe\x01\xc8\xff\x01\x01\x57\x04\xc8\xff\x01\xd0\xff\x01\x01\x53\x04\xd0\xff\
+\x01\xa0\x80\x02\x01\x57\x04\xa0\x80\x02\xa8\x80\x02\x01\x53\x04\xa8\x80\x02\
+\xf8\x80\x02\x01\x57\x04\xf8\x80\x02\x80\x81\x02\x01\x53\x04\x80\x81\x02\xd0\
+\x81\x02\x01\x57\x04\xd0\x81\x02\xd8\x81\x02\x01\x53\x04\xd8\x81\x02\xa8\x82\
+\x02\x01\x57\x04\xa8\x82\x02\xb0\x82\x02\x01\x53\x04\xb0\x82\x02\x80\x83\x02\
+\x01\x57\x04\x80\x83\x02\x88\x83\x02\x01\x53\x04\x88\x83\x02\xd8\x83\x02\x01\
+\x57\x04\xd8\x83\x02\xe0\x83\x02\x01\x53\x04\xe0\x83\x02\xb0\x84\x02\x01\x57\
+\x04\xb0\x84\x02\xb8\x84\x02\x01\x53\x04\xb8\x84\x02\x88\x85\x02\x01\x57\x04\
+\x88\x85\x02\x90\x85\x02\x01\x53\x04\x90\x85\x02\xe0\x85\x02\x01\x57\x04\xe0\
+\x85\x02\xe8\x85\x02\x01\x53\x04\xe8\x85\x02\xb8\x86\x02\x01\x57\x04\xb8\x86\
+\x02\xc0\x86\x02\x01\x53\x04\xc0\x86\x02\x90\x87\x02\x01\x57\x04\x90\x87\x02\
+\x98\x87\x02\x01\x53\x04\x98\x87\x02\xe8\x87\x02\x01\x57\x04\xe8\x87\x02\xf0\
+\x87\x02\x01\x53\x04\xf0\x87\x02\xc0\x88\x02\x01\x57\x04\xc0\x88\x02\xc8\x88\
+\x02\x01\x53\x04\xc8\x88\x02\xa0\x89\x02\x01\x57\x04\xa0\x89\x02\xa8\x89\x02\
+\x01\x54\x04\xa8\x89\x02\x88\x8a\x02\x01\x57\x04\x88\x8a\x02\x90\x8a\x02\x01\
+\x55\x04\x90\x8a\x02\xe8\x8a\x02\x01\x57\x04\xe8\x8a\x02\xf0\x8a\x02\x01\x54\
+\x04\xf0\x8a\x02\xc0\x8b\x02\x01\x57\x04\xc0\x8b\x02\xc8\x8b\x02\x01\x52\x04\
+\xc8\x8b\x02\xa0\x8c\x02\x01\x57\x04\xa0\x8c\x02\xa8\x8c\x02\x01\x52\x04\xa8\
+\x8c\x02\xf8\x8c\x02\x01\x57\x04\xf8\x8c\x02\x80\x8d\x02\x01\x52\x04\x80\x8d\
+\x02\xd0\x8d\x02\x01\x57\x04\xd0\x8d\x02\xd8\x8d\x02\x01\x52\x04\xd8\x8d\x02\
+\xa8\x8e\x02\x01\x57\x04\xa8\x8e\x02\xb0\x8e\x02\x01\x52\x04\xb0\x8e\x02\x80\
+\x8f\x02\x01\x57\x04\x80\x8f\x02\x88\x8f\x02\x01\x52\x04\x88\x8f\x02\xd8\x8f\
+\x02\x01\x57\x04\xd8\x8f\x02\xe0\x8f\x02\x01\x52\x04\xe0\x8f\x02\xb0\x90\x02\
+\x01\x57\x04\xb0\x90\x02\xb8\x90\x02\x01\x52\x04\xb8\x90\x02\x88\x91\x02\x01\
+\x57\x04\x88\x91\x02\x90\x91\x02\x01\x52\x04\x90\x91\x02\xe0\x91\x02\x01\x57\
+\x04\xe0\x91\x02\xe8\x91\x02\x01\x52\x04\xe8\x91\x02\xb8\x92\x02\x01\x57\x04\
+\xb8\x92\x02\xc0\x92\x02\x01\x52\x04\xc0\x92\x02\x90\x93\x02\x01\x57\x04\x90\
+\x93\x02\x98\x93\x02\x01\x52\x04\x98\x93\x02\xe8\x93\x02\x01\x57\x04\xe8\x93\
+\x02\xf0\x93\x02\x01\x52\x04\xf0\x93\x02\xc0\x94\x02\x01\x57\x04\xc0\x94\x02\
+\xc8\x94\x02\x01\x52\x04\xc8\x94\x02\x98\x95\x02\x01\x57\x04\x98\x95\x02\xa0\
+\x95\x02\x01\x52\x04\xa0\x95\x02\xf0\x95\x02\x01\x57\x04\xf0\x95\x02\xf8\x95\
+\x02\x01\x52\x04\xf8\x95\x02\xc8\x96\x02\x01\x57\x04\xc8\x96\x02\xd0\x96\x02\
+\x01\x52\x04\xd0\x96\x02\xa0\x97\x02\x01\x57\x04\xa0\x97\x02\xa8\x97\x02\x01\
+\x52\x04\xa8\x97\x02\xf8\x97\x02\x01\x57\x04\xf8\x97\x02\x80\x98\x02\x01\x52\
+\x04\x80\x98\x02\xd0\x98\x02\x01\x57\x04\xd0\x98\x02\xd8\x98\x02\x01\x52\x04\
+\xd8\x98\x02\xa8\x99\x02\x01\x57\x04\xa8\x99\x02\xb0\x99\x02\x01\x52\x04\xb0\
+\x99\x02\x80\x9a\x02\x01\x57\x04\x80\x9a\x02\x88\x9a\x02\x01\x52\x04\x88\x9a\
+\x02\xd8\x9a\x02\x01\x57\x04\xd8\x9a\x02\xe0\x9a\x02\x01\x52\x04\xe0\x9a\x02\
+\xb0\x9b\x02\x01\x57\x04\xb0\x9b\x02\xb8\x9b\x02\x01\x52\x04\xb8\x9b\x02\x88\
+\x9c\x02\x01\x57\x04\x88\x9c\x02\x90\x9c\x02\x01\x52\x04\x90\x9c\x02\xe0\x9c\
+\x02\x01\x57\x04\xe0\x9c\x02\xe8\x9c\x02\x01\x52\x04\xe8\x9c\x02\xb8\x9d\x02\
+\x01\x57\x04\xb8\x9d\x02\xc0\x9d\x02\x01\x52\x04\xc0\x9d\x02\x90\x9e\x02\x01\
+\x57\x04\x90\x9e\x02\x98\x9e\x02\x01\x52\x04\x98\x9e\x02\xe8\x9e\x02\x01\x57\
+\x04\xe8\x9e\x02\xf0\x9e\x02\x01\x52\x04\xf0\x9e\x02\xc0\x9f\x02\x01\x57\x04\
+\xc0\x9f\x02\xc8\x9f\x02\x01\x52\x04\xc8\x9f\x02\x98\xa0\x02\x01\x57\x04\x98\
+\xa0\x02\xa0\xa0\x02\x01\x52\x04\xa0\xa0\x02\xe8\xa0\x02\x01\x57\x04\xe8\xa0\
+\x02\xf0\xa0\x02\x01\x51\0\x04\xd0\xe0\x01\xe8\xe0\x01\x03\x7a\xc8\0\x04\xe8\
+\xe0\x01\xb0\xf6\x01\x01\x54\0\x04\xc0\xea\x03\x98\xeb\x03\x0d\x71\0\xa8\xab\
+\x80\x80\0\xa8\xaf\x80\x80\0\x9f\0\x04\x98\xa1\x02\xb0\xa1\x02\x02\x30\x9f\x04\
+\xf8\xe4\x03\xf0\xe5\x03\x02\x30\x9f\x04\xf0\xe5\x03\xa0\xe7\x03\x02\x31\x9f\
+\x04\xa0\xe7\x03\xf0\xe8\x03\x02\x32\x9f\x04\xf0\xe8\x03\xc0\xea\x03\x02\x33\
+\x9f\x04\xc0\xea\x03\x98\xeb\x03\x02\x34\x9f\0\x04\x98\xa1\x02\xb0\xa1\x02\x02\
+\x7a\x38\x04\xf8\xe4\x03\xc8\xeb\x03\x02\x7a\x38\0\x04\xb0\xa1\x02\xe0\xa1\x02\
+\x0d\x71\0\xa8\xab\x80\x80\0\xa8\xb3\x80\x80\0\x9f\0\x04\xb0\xa1\x02\xf8\xe4\
+\x03\x03\x11\0\x9f\0\x04\x98\xa2\x02\xf0\xa2\x02\x02\x31\x9f\x04\xf0\xa2\x02\
+\xd8\xa3\x02\x02\x32\x9f\x04\xd8\xa3\x02\xc8\xa4\x02\x02\x33\x9f\x04\xc8\xa4\
+\x02\xb0\xa5\x02\x02\x34\x9f\x04\xb0\xa5\x02\x90\xa6\x02\x02\x35\x9f\x04\x90\
+\xa6\x02\xf0\xa6\x02\x02\x36\x9f\x04\xf0\xa6\x02\xd0\xa7\x02\x02\x37\x9f\x04\
+\xd0\xa7\x02\xb0\xa8\x02\x02\x38\x9f\x04\xb0\xa8\x02\x90\xa9\x02\x02\x39\x9f\
+\x04\x90\xa9\x02\xf0\xa9\x02\x02\x3a\x9f\x04\xf0\xa9\x02\xd0\xaa\x02\x02\x3b\
+\x9f\x04\xd0\xaa\x02\xb0\xab\x02\x02\x3c\x9f\x04\xb0\xab\x02\x90\xac\x02\x02\
+\x3d\x9f\x04\x90\xac\x02\xf0\xac\x02\x02\x3e\x9f\x04\xf0\xac\x02\xd0\xad\x02\
+\x02\x3f\x9f\x04\xd0\xad\x02\xb0\xae\x02\x02\x40\x9f\x04\xb0\xae\x02\x90\xaf\
+\x02\x02\x41\x9f\x04\x90\xaf\x02\xf0\xaf\x02\x02\x42\x9f\x04\xf0\xaf\x02\xd0\
+\xb0\x02\x02\x43\x9f\x04\xd0\xb0\x02\xb0\xb1\x02\x02\x44\x9f\x04\xb0\xb1\x02\
+\x90\xb2\x02\x02\x45\x9f\x04\x90\xb2\x02\xf0\xb2\x02\x02\x46\x9f\x04\xf0\xb2\
+\x02\xd0\xb3\x02\x02\x47\x9f\x04\xd0\xb3\x02\xb0\xb4\x02\x02\x48\x9f\x04\xb0\
+\xb4\x02\x90\xb5\x02\x02\x49\x9f\x04\x90\xb5\x02\xf0\xb5\x02\x02\x4a\x9f\x04\
+\xf0\xb5\x02\xd0\xb6\x02\x02\x4b\x9f\x04\xd0\xb6\x02\xb0\xb7\x02\x02\x4c\x9f\
+\x04\xb0\xb7\x02\x90\xb8\x02\x02\x4d\x9f\x04\x90\xb8\x02\xf0\xb8\x02\x02\x4e\
+\x9f\x04\xf0\xb8\x02\xc8\xb9\x02\x02\x4f\x9f\x04\xc8\xb9\x02\xe0\xb9\x02\x02\
+\x30\x9f\x04\xe0\xb9\x02\xb8\xba\x02\x02\x31\x9f\x04\xb8\xba\x02\x90\xbb\x02\
+\x02\x32\x9f\x04\x90\xbb\x02\xe8\xbb\x02\x02\x33\x9f\x04\xe8\xbb\x02\xc0\xbc\
+\x02\x02\x34\x9f\x04\xc0\xbc\x02\x98\xbd\x02\x02\x35\x9f\x04\x98\xbd\x02\xf0\
+\xbd\x02\x02\x36\x9f\x04\xf0\xbd\x02\xc8\xbe\x02\x02\x37\x9f\x04\xc8\xbe\x02\
+\xa0\xbf\x02\x02\x38\x9f\x04\xa0\xbf\x02\xf8\xbf\x02\x02\x39\x9f\x04\xf8\xbf\
+\x02\xd0\xc0\x02\x02\x3a\x9f\x04\xd0\xc0\x02\xa8\xc1\x02\x02\x3b\x9f\x04\xa8\
+\xc1\x02\x80\xc2\x02\x02\x3c\x9f\x04\x80\xc2\x02\xd8\xc2\x02\x02\x3d\x9f\x04\
+\xd8\xc2\x02\xb0\xc3\x02\x02\x3e\x9f\x04\xb0\xc3\x02\x88\xc4\x02\x02\x3f\x9f\
+\x04\x88\xc4\x02\xe0\xc4\x02\x02\x40\x9f\x04\xe0\xc4\x02\xb8\xc5\x02\x02\x41\
+\x9f\x04\xb8\xc5\x02\x90\xc6\x02\x02\x42\x9f\x04\x90\xc6\x02\xe8\xc6\x02\x02\
+\x43\x9f\x04\xe8\xc6\x02\xc0\xc7\x02\x02\x44\x9f\x04\xc0\xc7\x02\x98\xc8\x02\
+\x02\x45\x9f\x04\x98\xc8\x02\xf0\xc8\x02\x02\x46\x9f\x04\xf0\xc8\x02\xc8\xc9\
+\x02\x02\x47\x9f\x04\xc8\xc9\x02\xa0\xca\x02\x02\x48\x9f\x04\xa0\xca\x02\xf8\
+\xca\x02\x02\x49\x9f\x04\xf8\xca\x02\xd0\xcb\x02\x02\x4a\x9f\x04\xd0\xcb\x02\
+\xa8\xcc\x02\x02\x4b\x9f\x04\xa8\xcc\x02\x80\xcd\x02\x02\x4c\x9f\x04\x80\xcd\
+\x02\xd8\xcd\x02\x02\x4d\x9f\x04\xd8\xcd\x02\xb0\xce\x02\x02\x4e\x9f\x04\xb0\
+\xce\x02\x80\xcf\x02\x02\x4f\x9f\x04\x80\xcf\x02\x90\xcf\x02\x02\x30\x9f\x04\
+\x90\xcf\x02\xe8\xcf\x02\x02\x31\x9f\x04\xe8\xcf\x02\xc0\xd0\x02\x02\x32\x9f\
+\x04\xc0\xd0\x02\x98\xd1\x02\x02\x33\x9f\x04\x98\xd1\x02\xf0\xd1\x02\x02\x34\
+\x9f\x04\xf0\xd1\x02\xc8\xd2\x02\x02\x35\x9f\x04\xc8\xd2\x02\xa0\xd3\x02\x02\
+\x36\x9f\x04\xa0\xd3\x02\xf8\xd3\x02\x02\x37\x9f\x04\xf8\xd3\x02\xd0\xd4\x02\
+\x02\x38\x9f\x04\xd0\xd4\x02\xa8\xd5\x02\x02\x39\x9f\x04\xa8\xd5\x02\x80\xd6\
+\x02\x02\x3a\x9f\x04\x80\xd6\x02\xd8\xd6\x02\x02\x3b\x9f\x04\xd8\xd6\x02\xb0\
+\xd7\x02\x02\x3c\x9f\x04\xb0\xd7\x02\x88\xd8\x02\x02\x3d\x9f\x04\x88\xd8\x02\
+\xe0\xd8\x02\x02\x3e\x9f\x04\xe0\xd8\x02\xb8\xd9\x02\x02\x3f\x9f\x04\xb8\xd9\
+\x02\x90\xda\x02\x02\x40\x9f\x04\x90\xda\x02\xe8\xda\x02\x02\x41\x9f\x04\xe8\
+\xda\x02\xc0\xdb\x02\x02\x42\x9f\x04\xc0\xdb\x02\x98\xdc\x02\x02\x43\x9f\x04\
+\x98\xdc\x02\xf0\xdc\x02\x02\x44\x9f\x04\xf0\xdc\x02\xc8\xdd\x02\x02\x45\x9f\
+\x04\xc8\xdd\x02\xa0\xde\x02\x02\x46\x9f\x04\xa0\xde\x02\xf8\xde\x02\x02\x47\
+\x9f\x04\xf8\xde\x02\xd0\xdf\x02\x02\x48\x9f\x04\xd0\xdf\x02\xa8\xe0\x02\x02\
+\x49\x9f\x04\xa8\xe0\x02\x80\xe1\x02\x02\x4a\x9f\x04\x80\xe1\x02\xd8\xe1\x02\
+\x02\x4b\x9f\x04\xd8\xe1\x02\xb0\xe2\x02\x02\x4c\x9f\x04\xb0\xe2\x02\x88\xe3\
+\x02\x02\x4d\x9f\x04\x88\xe3\x02\xe0\xe3\x02\x02\x4e\x9f\x04\xe0\xe3\x02\xb8\
+\xe4\x02\x02\x4f\x9f\x04\xb8\xe4\x02\xc8\xe4\x02\x02\x30\x9f\x04\xc8\xe4\x02\
+\xa0\xe5\x02\x02\x31\x9f\x04\xa0\xe5\x02\xf8\xe5\x02\x02\x32\x9f\x04\xf8\xe5\
+\x02\xd0\xe6\x02\x02\x33\x9f\x04\xd0\xe6\x02\xa8\xe7\x02\x02\x34\x9f\x04\xa8\
+\xe7\x02\x80\xe8\x02\x02\x35\x9f\x04\x80\xe8\x02\xd8\xe8\x02\x02\x36\x9f\x04\
+\xd8\xe8\x02\xb0\xe9\x02\x02\x37\x9f\x04\xb0\xe9\x02\x88\xea\x02\x02\x38\x9f\
+\x04\x88\xea\x02\xe0\xea\x02\x02\x39\x9f\x04\xe0\xea\x02\xb8\xeb\x02\x02\x3a\
+\x9f\x04\xb8\xeb\x02\x90\xec\x02\x02\x3b\x9f\x04\x90\xec\x02\xe8\xec\x02\x02\
+\x3c\x9f\x04\xe8\xec\x02\xc0\xed\x02\x02\x3d\x9f\x04\xc0\xed\x02\x98\xee\x02\
+\x02\x3e\x9f\x04\x98\xee\x02\xf0\xee\x02\x02\x3f\x9f\x04\xf0\xee\x02\xc8\xef\
+\x02\x02\x40\x9f\x04\xc8\xef\x02\xa0\xf0\x02\x02\x41\x9f\x04\xa0\xf0\x02\xf8\
+\xf0\x02\x02\x42\x9f\x04\xf8\xf0\x02\xd0\xf1\x02\x02\x43\x9f\x04\xd0\xf1\x02\
+\xa8\xf2\x02\x02\x44\x9f\x04\xa8\xf2\x02\x80\xf3\x02\x02\x45\x9f\x04\x80\xf3\
+\x02\xd8\xf3\x02\x02\x46\x9f\x04\xd8\xf3\x02\xb0\xf4\x02\x02\x47\x9f\x04\xb0\
+\xf4\x02\x88\xf5\x02\x02\x48\x9f\x04\x88\xf5\x02\xe0\xf5\x02\x02\x49\x9f\x04\
+\xe0\xf5\x02\xb8\xf6\x02\x02\x4a\x9f\x04\xb8\xf6\x02\x90\xf7\x02\x02\x4b\x9f\
+\x04\x90\xf7\x02\xe8\xf7\x02\x02\x4c\x9f\x04\xe8\xf7\x02\xc0\xf8\x02\x02\x4d\
+\x9f\x04\xc0\xf8\x02\x98\xf9\x02\x02\x4e\x9f\x04\x98\xf9\x02\xf0\xf9\x02\x02\
+\x4f\x9f\x04\xf0\xf9\x02\x80\xfa\x02\x02\x30\x9f\x04\x80\xfa\x02\xd8\xfa\x02\
+\x02\x31\x9f\x04\xd8\xfa\x02\xb0\xfb\x02\x02\x32\x9f\x04\xb0\xfb\x02\x88\xfc\
+\x02\x02\x33\x9f\x04\x88\xfc\x02\xe0\xfc\x02\x02\x34\x9f\x04\xe0\xfc\x02\xb8\
+\xfd\x02\x02\x35\x9f\x04\xb8\xfd\x02\x90\xfe\x02\x02\x36\x9f\x04\x90\xfe\x02\
+\xe8\xfe\x02\x02\x37\x9f\x04\xe8\xfe\x02\xc0\xff\x02\x02\x38\x9f\x04\xc0\xff\
+\x02\x98\x80\x03\x02\x39\x9f\x04\x98\x80\x03\xf0\x80\x03\x02\x3a\x9f\x04\xf0\
+\x80\x03\xc8\x81\x03\x02\x3b\x9f\x04\xc8\x81\x03\xa0\x82\x03\x02\x3c\x9f\x04\
+\xa0\x82\x03\xf8\x82\x03\x02\x3d\x9f\x04\xf8\x82\x03\xd0\x83\x03\x02\x3e\x9f\
+\x04\xd0\x83\x03\xa8\x84\x03\x02\x3f\x9f\x04\xa8\x84\x03\x80\x85\x03\x02\x40\
+\x9f\x04\x80\x85\x03\xd8\x85\x03\x02\x41\x9f\x04\xd8\x85\x03\xb0\x86\x03\x02\
+\x42\x9f\x04\xb0\x86\x03\x88\x87\x03\x02\x43\x9f\x04\x88\x87\x03\xe0\x87\x03\
+\x02\x44\x9f\x04\xe0\x87\x03\xb8\x88\x03\x02\x45\x9f\x04\xb8\x88\x03\x90\x89\
+\x03\x02\x46\x9f\x04\x90\x89\x03\xe8\x89\x03\x02\x47\x9f\x04\xe8\x89\x03\xc0\
+\x8a\x03\x02\x48\x9f\x04\xc0\x8a\x03\x98\x8b\x03\x02\x49\x9f\x04\x98\x8b\x03\
+\xf0\x8b\x03\x02\x4a\x9f\x04\xf0\x8b\x03\xc8\x8c\x03\x02\x4b\x9f\x04\xc8\x8c\
+\x03\xa0\x8d\x03\x02\x4c\x9f\x04\xa0\x8d\x03\xf8\x8d\x03\x02\x4d\x9f\x04\xf8\
+\x8d\x03\xd0\x8e\x03\x02\x4e\x9f\x04\xd0\x8e\x03\xa0\x8f\x03\x02\x4f\x9f\x04\
+\xa0\x8f\x03\xb0\x8f\x03\x02\x30\x9f\x04\xb0\x8f\x03\x88\x90\x03\x02\x31\x9f\
+\x04\x88\x90\x03\xe8\x90\x03\x02\x32\x9f\x04\xe8\x90\x03\xc0\x91\x03\x02\x33\
+\x9f\x04\xc0\x91\x03\x98\x92\x03\x02\x34\x9f\x04\x98\x92\x03\xf0\x92\x03\x02\
+\x35\x9f\x04\xf0\x92\x03\xc8\x93\x03\x02\x36\x9f\x04\xc8\x93\x03\xa0\x94\x03\
+\x02\x37\x9f\x04\xa0\x94\x03\xf8\x94\x03\x02\x38\x9f\x04\xf8\x94\x03\xd0\x95\
+\x03\x02\x39\x9f\x04\xd0\x95\x03\xa8\x96\x03\x02\x3a\x9f\x04\xa8\x96\x03\x80\
+\x97\x03\x02\x3b\x9f\x04\x80\x97\x03\xd8\x97\x03\x02\x3c\x9f\x04\xd8\x97\x03\
+\xb0\x98\x03\x02\x3d\x9f\x04\xb0\x98\x03\x88\x99\x03\x02\x3e\x9f\x04\x88\x99\
+\x03\xe0\x99\x03\x02\x3f\x9f\x04\xe0\x99\x03\xb8\x9a\x03\x02\x40\x9f\x04\xb8\
+\x9a\x03\x90\x9b\x03\x02\x41\x9f\x04\x90\x9b\x03\xe8\x9b\x03\x02\x42\x9f\x04\
+\xe8\x9b\x03\xc0\x9c\x03\x02\x43\x9f\x04\xc0\x9c\x03\x98\x9d\x03\x02\x44\x9f\
+\x04\x98\x9d\x03\xf0\x9d\x03\x02\x45\x9f\x04\xf0\x9d\x03\xc8\x9e\x03\x02\x46\
+\x9f\x04\xc8\x9e\x03\xa0\x9f\x03\x02\x47\x9f\x04\xa0\x9f\x03\xf8\x9f\x03\x02\
+\x48\x9f\x04\xf8\x9f\x03\xd0\xa0\x03\x02\x49\x9f\x04\xd0\xa0\x03\xa8\xa1\x03\
+\x02\x4a\x9f\x04\xa8\xa1\x03\x80\xa2\x03\x02\x4b\x9f\x04\x80\xa2\x03\xd8\xa2\
+\x03\x02\x4c\x9f\x04\xd8\xa2\x03\xb0\xa3\x03\x02\x4d\x9f\x04\xb0\xa3\x03\x88\
+\xa4\x03\x02\x4e\x9f\x04\x88\xa4\x03\xd8\xa4\x03\x02\x4f\x9f\x04\xd8\xa4\x03\
+\xe8\xa4\x03\x02\x30\x9f\x04\xe8\xa4\x03\xc0\xa5\x03\x02\x31\x9f\x04\xc0\xa5\
+\x03\x98\xa6\x03\x02\x32\x9f\x04\x98\xa6\x03\xf0\xa6\x03\x02\x33\x9f\x04\xf0\
+\xa6\x03\xc8\xa7\x03\x02\x34\x9f\x04\xc8\xa7\x03\xa0\xa8\x03\x02\x35\x9f\x04\
+\xa0\xa8\x03\xf8\xa8\x03\x02\x36\x9f\x04\xf8\xa8\x03\xd0\xa9\x03\x02\x37\x9f\
+\x04\xd0\xa9\x03\xa8\xaa\x03\x02\x38\x9f\x04\xa8\xaa\x03\x80\xab\x03\x02\x39\
+\x9f\x04\x80\xab\x03\xd8\xab\x03\x02\x3a\x9f\x04\xd8\xab\x03\xb0\xac\x03\x02\
+\x3b\x9f\x04\xb0\xac\x03\x88\xad\x03\x02\x3c\x9f\x04\x88\xad\x03\xe0\xad\x03\
+\x02\x3d\x9f\x04\xe0\xad\x03\xb8\xae\x03\x02\x3e\x9f\x04\xb8\xae\x03\x90\xaf\
+\x03\x02\x3f\x9f\x04\x90\xaf\x03\xe8\xaf\x03\x02\x40\x9f\x04\xe8\xaf\x03\xc0\
+\xb0\x03\x02\x41\x9f\x04\xc0\xb0\x03\x98\xb1\x03\x02\x42\x9f\x04\x98\xb1\x03\
+\xf0\xb1\x03\x02\x43\x9f\x04\xf0\xb1\x03\xc8\xb2\x03\x02\x44\x9f\x04\xc8\xb2\
+\x03\xa0\xb3\x03\x02\x45\x9f\x04\xa0\xb3\x03\xf8\xb3\x03\x02\x46\x9f\x04\xf8\
+\xb3\x03\xd0\xb4\x03\x02\x47\x9f\x04\xd0\xb4\x03\xa8\xb5\x03\x02\x48\x9f\x04\
+\xa8\xb5\x03\x80\xb6\x03\x02\x49\x9f\x04\x80\xb6\x03\xd8\xb6\x03\x02\x4a\x9f\
+\x04\xd8\xb6\x03\xb0\xb7\x03\x02\x4b\x9f\x04\xb0\xb7\x03\x88\xb8\x03\x02\x4c\
+\x9f\x04\x88\xb8\x03\xe0\xb8\x03\x02\x4d\x9f\x04\xe0\xb8\x03\xb8\xb9\x03\x02\
+\x4e\x9f\x04\xb8\xb9\x03\x88\xba\x03\x02\x4f\x9f\x04\x88\xba\x03\x98\xba\x03\
+\x02\x30\x9f\x04\x98\xba\x03\xf0\xba\x03\x02\x31\x9f\x04\xf0\xba\x03\xc8\xbb\
+\x03\x02\x32\x9f\x04\xc8\xbb\x03\xa0\xbc\x03\x02\x33\x9f\x04\xa0\xbc\x03\xf8\
+\xbc\x03\x02\x34\x9f\x04\xf8\xbc\x03\xd0\xbd\x03\x02\x35\x9f\x04\xd0\xbd\x03\
+\xa8\xbe\x03\x02\x36\x9f\x04\xa8\xbe\x03\x80\xbf\x03\x02\x37\x9f\x04\x80\xbf\
+\x03\xd8\xbf\x03\x02\x38\x9f\x04\xd8\xbf\x03\xb0\xc0\x03\x02\x39\x9f\x04\xb0\
+\xc0\x03\x88\xc1\x03\x02\x3a\x9f\x04\x88\xc1\x03\xe0\xc1\x03\x02\x3b\x9f\x04\
+\xe0\xc1\x03\xb8\xc2\x03\x02\x3c\x9f\x04\xb8\xc2\x03\x90\xc3\x03\x02\x3d\x9f\
+\x04\x90\xc3\x03\xe8\xc3\x03\x02\x3e\x9f\x04\xe8\xc3\x03\xc0\xc4\x03\x02\x3f\
+\x9f\x04\xc0\xc4\x03\x98\xc5\x03\x02\x40\x9f\x04\x98\xc5\x03\xf0\xc5\x03\x02\
+\x41\x9f\x04\xf0\xc5\x03\xc8\xc6\x03\x02\x42\x9f\x04\xc8\xc6\x03\xa0\xc7\x03\
+\x02\x43\x9f\x04\xa0\xc7\x03\xf8\xc7\x03\x02\x44\x9f\x04\xf8\xc7\x03\xd0\xc8\
+\x03\x02\x45\x9f\x04\xd0\xc8\x03\xa8\xc9\x03\x02\x46\x9f\x04\xa8\xc9\x03\x80\
+\xca\x03\x02\x47\x9f\x04\x80\xca\x03\xd8\xca\x03\x02\x48\x9f\x04\xd8\xca\x03\
+\xb0\xcb\x03\x02\x49\x9f\x04\xb0\xcb\x03\x88\xcc\x03\x02\x4a\x9f\x04\x88\xcc\
+\x03\xe0\xcc\x03\x02\x4b\x9f\x04\xe8\xcc\x03\xc0\xcd\x03\x02\x4c\x9f\x04\xd0\
+\xcd\x03\xa8\xce\x03\x02\x4d\x9f\x04\xb0\xce\x03\x88\xcf\x03\x02\x4e\x9f\x04\
+\x90\xcf\x03\xe0\xcf\x03\x02\x4f\x9f\x04\xe0\xcf\x03\xe8\xcf\x03\x02\x30\x9f\
+\x04\xe8\xcf\x03\xc0\xd0\x03\x02\x31\x9f\x04\xc0\xd0\x03\x98\xd1\x03\x02\x32\
+\x9f\x04\x98\xd1\x03\xf0\xd1\x03\x02\x33\x9f\x04\xf0\xd1\x03\xc8\xd2\x03\x02\
+\x34\x9f\x04\xc8\xd2\x03\xa0\xd3\x03\x02\x35\x9f\x04\xa0\xd3\x03\xf8\xd3\x03\
+\x02\x36\x9f\x04\xf8\xd3\x03\xd0\xd4\x03\x02\x37\x9f\x04\xd0\xd4\x03\xa8\xd5\
+\x03\x02\x38\x9f\x04\xa8\xd5\x03\x80\xd6\x03\x02\x39\x9f\x04\x80\xd6\x03\xd8\
+\xd6\x03\x02\x3a\x9f\x04\xd8\xd6\x03\xb0\xd7\x03\x02\x3b\x9f\x04\xb0\xd7\x03\
+\x88\xd8\x03\x02\x3c\x9f\x04\x88\xd8\x03\xe0\xd8\x03\x02\x3d\x9f\x04\xe0\xd8\
+\x03\xb8\xd9\x03\x02\x3e\x9f\x04\xb8\xd9\x03\x90\xda\x03\x02\x3f\x9f\x04\x90\
+\xda\x03\xe8\xda\x03\x02\x40\x9f\x04\xe8\xda\x03\xc0\xdb\x03\x02\x41\x9f\x04\
+\xc0\xdb\x03\x98\xdc\x03\x02\x42\x9f\x04\x98\xdc\x03\xf0\xdc\x03\x02\x43\x9f\
+\x04\xf0\xdc\x03\xc8\xdd\x03\x02\x44\x9f\x04\xc8\xdd\x03\xa0\xde\x03\x02\x45\
+\x9f\x04\xa0\xde\x03\xf8\xde\x03\x02\x46\x9f\x04\xf8\xde\x03\xd0\xdf\x03\x02\
+\x47\x9f\x04\xd0\xdf\x03\xa8\xe0\x03\x02\x48\x9f\x04\xa8\xe0\x03\x80\xe1\x03\
+\x02\x49\x9f\x04\x80\xe1\x03\xd8\xe1\x03\x02\x4a\x9f\x04\xd8\xe1\x03\xb0\xe2\
+\x03\x02\x4b\x9f\x04\xb0\xe2\x03\x88\xe3\x03\x02\x4c\x9f\x04\x88\xe3\x03\xe0\
+\xe3\x03\x02\x4d\x9f\x04\xe0\xe3\x03\xb8\xe4\x03\x02\x4e\x9f\x04\xb8\xe4\x03\
+\xf8\xe4\x03\x02\x4f\x9f\0\x04\x98\xa2\x02\xc8\xb9\x02\x02\x30\x9f\x04\xc8\xb9\
+\x02\x80\xcf\x02\x02\x31\x9f\x04\x80\xcf\x02\xb8\xe4\x02\x02\x32\x9f\x04\xb8\
+\xe4\x02\xf0\xf9\x02\x02\x33\x9f\x04\xf0\xf9\x02\xa0\x8f\x03\x02\x34\x9f\x04\
+\xa0\x8f\x03\xd8\xa4\x03\x02\x35\x9f\x04\xd8\xa4\x03\x88\xba\x03\x02\x36\x9f\
+\x04\x88\xba\x03\xe0\xcf\x03\x02\x37\x9f\x04\xe0\xcf\x03\xf8\xe4\x03\x02\x38\
+\x9f\0\x04\x98\xa2\x02\xf0\xa2\x02\x02\x30\x9f\x04\xf0\xa2\x02\xd0\xa3\x02\x01\
+\x58\x04\xd0\xa3\x02\xd8\xa3\x02\x01\x51\x04\xd8\xa3\x02\xc0\xa4\x02\x01\x58\
+\x04\xc0\xa4\x02\xc8\xa4\x02\x01\x51\x04\xc8\xa4\x02\xa8\xa5\x02\x01\x58\x04\
+\xa8\xa5\x02\xb0\xa5\x02\x01\x51\x04\xb0\xa5\x02\x88\xa6\x02\x01\x58\x04\x88\
+\xa6\x02\x90\xa6\x02\x01\x51\x04\x90\xa6\x02\xe8\xa6\x02\x01\x58\x04\xe8\xa6\
+\x02\xf0\xa6\x02\x01\x51\x04\xf0\xa6\x02\xc8\xa7\x02\x01\x58\x04\xc8\xa7\x02\
+\xd0\xa7\x02\x01\x51\x04\xd0\xa7\x02\xa8\xa8\x02\x01\x58\x04\xa8\xa8\x02\xb0\
+\xa8\x02\x01\x51\x04\xb0\xa8\x02\x88\xa9\x02\x01\x58\x04\x88\xa9\x02\x90\xa9\
+\x02\x01\x51\x04\x90\xa9\x02\xe8\xa9\x02\x01\x58\x04\xe8\xa9\x02\xf0\xa9\x02\
+\x01\x51\x04\xf0\xa9\x02\xc8\xaa\x02\x01\x58\x04\xc8\xaa\x02\xd0\xaa\x02\x01\
+\x51\x04\xd0\xaa\x02\xa8\xab\x02\x01\x58\x04\xa8\xab\x02\xb0\xab\x02\x01\x51\
+\x04\xb0\xab\x02\x88\xac\x02\x01\x58\x04\x88\xac\x02\x90\xac\x02\x01\x51\x04\
+\x90\xac\x02\xe8\xac\x02\x01\x58\x04\xe8\xac\x02\xf0\xac\x02\x01\x51\x04\xf0\
+\xac\x02\xc8\xad\x02\x01\x58\x04\xc8\xad\x02\xd0\xad\x02\x01\x51\x04\xd0\xad\
+\x02\xa8\xae\x02\x01\x58\x04\xa8\xae\x02\xb0\xae\x02\x01\x51\x04\xb0\xae\x02\
+\x88\xaf\x02\x01\x58\x04\x88\xaf\x02\x90\xaf\x02\x01\x51\x04\x90\xaf\x02\xe8\
+\xaf\x02\x01\x58\x04\xe8\xaf\x02\xf0\xaf\x02\x01\x51\x04\xf0\xaf\x02\xc8\xb0\
+\x02\x01\x58\x04\xc8\xb0\x02\xd0\xb0\x02\x01\x51\x04\xd0\xb0\x02\xa8\xb1\x02\
+\x01\x58\x04\xa8\xb1\x02\xb0\xb1\x02\x01\x51\x04\xb0\xb1\x02\x88\xb2\x02\x01\
+\x58\x04\x88\xb2\x02\x90\xb2\x02\x01\x51\x04\x90\xb2\x02\xe8\xb2\x02\x01\x58\
+\x04\xe8\xb2\x02\xf0\xb2\x02\x01\x51\x04\xf0\xb2\x02\xc8\xb3\x02\x01\x58\x04\
+\xc8\xb3\x02\xd0\xb3\x02\x01\x51\x04\xd0\xb3\x02\xa8\xb4\x02\x01\x58\x04\xa8\
+\xb4\x02\xb0\xb4\x02\x01\x51\x04\xb0\xb4\x02\x88\xb5\x02\x01\x58\x04\x88\xb5\
+\x02\x90\xb5\x02\x01\x51\x04\x90\xb5\x02\xe8\xb5\x02\x01\x58\x04\xe8\xb5\x02\
+\xf0\xb5\x02\x01\x51\x04\xf0\xb5\x02\xc8\xb6\x02\x01\x58\x04\xc8\xb6\x02\xd0\
+\xb6\x02\x01\x51\x04\xd0\xb6\x02\xa8\xb7\x02\x01\x58\x04\xa8\xb7\x02\xb0\xb7\
+\x02\x01\x51\x04\xb0\xb7\x02\x88\xb8\x02\x01\x58\x04\x88\xb8\x02\x90\xb8\x02\
+\x01\x51\x04\x90\xb8\x02\xe8\xb8\x02\x01\x58\x04\xe8\xb8\x02\xf0\xb8\x02\x01\
+\x51\x04\xf0\xb8\x02\xc0\xb9\x02\x01\x58\x04\xc0\xb9\x02\xc8\xb9\x02\x01\x51\
+\x04\xc8\xb9\x02\xb0\xba\x02\x01\x58\x04\xb0\xba\x02\xb8\xba\x02\x01\x53\x04\
+\xb8\xba\x02\x88\xbb\x02\x01\x58\x04\x88\xbb\x02\x90\xbb\x02\x01\x53\x04\x90\
+\xbb\x02\xe0\xbb\x02\x01\x58\x04\xe0\xbb\x02\xe8\xbb\x02\x01\x53\x04\xe8\xbb\
+\x02\xb8\xbc\x02\x01\x58\x04\xb8\xbc\x02\xc0\xbc\x02\x01\x53\x04\xc0\xbc\x02\
+\x90\xbd\x02\x01\x58\x04\x90\xbd\x02\x98\xbd\x02\x01\x53\x04\x98\xbd\x02\xe8\
+\xbd\x02\x01\x58\x04\xe8\xbd\x02\xf0\xbd\x02\x01\x53\x04\xf0\xbd\x02\xc0\xbe\
+\x02\x01\x58\x04\xc0\xbe\x02\xc8\xbe\x02\x01\x53\x04\xc8\xbe\x02\x98\xbf\x02\
+\x01\x58\x04\x98\xbf\x02\xa0\xbf\x02\x01\x53\x04\xa0\xbf\x02\xf0\xbf\x02\x01\
+\x58\x04\xf0\xbf\x02\xf8\xbf\x02\x01\x53\x04\xf8\xbf\x02\xc8\xc0\x02\x01\x58\
+\x04\xc8\xc0\x02\xd0\xc0\x02\x01\x53\x04\xd0\xc0\x02\xa0\xc1\x02\x01\x58\x04\
+\xa0\xc1\x02\xa8\xc1\x02\x01\x53\x04\xa8\xc1\x02\xf8\xc1\x02\x01\x58\x04\xf8\
+\xc1\x02\x80\xc2\x02\x01\x53\x04\x80\xc2\x02\xd0\xc2\x02\x01\x58\x04\xd0\xc2\
+\x02\xd8\xc2\x02\x01\x53\x04\xd8\xc2\x02\xa8\xc3\x02\x01\x58\x04\xa8\xc3\x02\
+\xb0\xc3\x02\x01\x53\x04\xb0\xc3\x02\x80\xc4\x02\x01\x58\x04\x80\xc4\x02\x88\
+\xc4\x02\x01\x53\x04\x88\xc4\x02\xd8\xc4\x02\x01\x58\x04\xd8\xc4\x02\xe0\xc4\
+\x02\x01\x53\x04\xe0\xc4\x02\xb0\xc5\x02\x01\x58\x04\xb0\xc5\x02\xb8\xc5\x02\
+\x01\x53\x04\xb8\xc5\x02\x88\xc6\x02\x01\x58\x04\x88\xc6\x02\x90\xc6\x02\x01\
+\x53\x04\x90\xc6\x02\xe0\xc6\x02\x01\x58\x04\xe0\xc6\x02\xe8\xc6\x02\x01\x53\
+\x04\xe8\xc6\x02\xb8\xc7\x02\x01\x58\x04\xb8\xc7\x02\xc0\xc7\x02\x01\x53\x04\
+\xc0\xc7\x02\x90\xc8\x02\x01\x58\x04\x90\xc8\x02\x98\xc8\x02\x01\x53\x04\x98\
+\xc8\x02\xe8\xc8\x02\x01\x58\x04\xe8\xc8\x02\xf0\xc8\x02\x01\x53\x04\xf0\xc8\
+\x02\xc0\xc9\x02\x01\x58\x04\xc0\xc9\x02\xc8\xc9\x02\x01\x53\x04\xc8\xc9\x02\
+\x98\xca\x02\x01\x58\x04\x98\xca\x02\xa0\xca\x02\x01\x53\x04\xa0\xca\x02\xf0\
+\xca\x02\x01\x58\x04\xf0\xca\x02\xf8\xca\x02\x01\x53\x04\xf8\xca\x02\xc8\xcb\
+\x02\x01\x58\x04\xc8\xcb\x02\xd0\xcb\x02\x01\x53\x04\xd0\xcb\x02\xa0\xcc\x02\
+\x01\x58\x04\xa0\xcc\x02\xa8\xcc\x02\x01\x53\x04\xa8\xcc\x02\xf8\xcc\x02\x01\
+\x58\x04\xf8\xcc\x02\x80\xcd\x02\x01\x53\x04\x80\xcd\x02\xd0\xcd\x02\x01\x58\
+\x04\xd0\xcd\x02\xd8\xcd\x02\x01\x53\x04\xd8\xcd\x02\xa8\xce\x02\x01\x58\x04\
+\xa8\xce\x02\xb0\xce\x02\x01\x53\x04\xb0\xce\x02\xf8\xce\x02\x01\x58\x04\xf8\
+\xce\x02\x80\xcf\x02\x01\x52\x04\x80\xcf\x02\xe0\xcf\x02\x01\x58\x04\xe0\xcf\
+\x02\xe8\xcf\x02\x01\x53\x04\xe8\xcf\x02\xb8\xd0\x02\x01\x58\x04\xb8\xd0\x02\
+\xc0\xd0\x02\x01\x53\x04\xc0\xd0\x02\x90\xd1\x02\x01\x58\x04\x90\xd1\x02\x98\
+\xd1\x02\x01\x53\x04\x98\xd1\x02\xe8\xd1\x02\x01\x58\x04\xe8\xd1\x02\xf0\xd1\
+\x02\x01\x53\x04\xf0\xd1\x02\xc0\xd2\x02\x01\x58\x04\xc0\xd2\x02\xc8\xd2\x02\
+\x01\x53\x04\xc8\xd2\x02\x98\xd3\x02\x01\x58\x04\x98\xd3\x02\xa0\xd3\x02\x01\
+\x53\x04\xa0\xd3\x02\xf0\xd3\x02\x01\x58\x04\xf0\xd3\x02\xf8\xd3\x02\x01\x53\
+\x04\xf8\xd3\x02\xc8\xd4\x02\x01\x58\x04\xc8\xd4\x02\xd0\xd4\x02\x01\x53\x04\
+\xd0\xd4\x02\xa0\xd5\x02\x01\x58\x04\xa0\xd5\x02\xa8\xd5\x02\x01\x53\x04\xa8\
+\xd5\x02\xf8\xd5\x02\x01\x58\x04\xf8\xd5\x02\x80\xd6\x02\x01\x53\x04\x80\xd6\
+\x02\xd0\xd6\x02\x01\x58\x04\xd0\xd6\x02\xd8\xd6\x02\x01\x53\x04\xd8\xd6\x02\
+\xa8\xd7\x02\x01\x58\x04\xa8\xd7\x02\xb0\xd7\x02\x01\x53\x04\xb0\xd7\x02\x80\
+\xd8\x02\x01\x58\x04\x80\xd8\x02\x88\xd8\x02\x01\x53\x04\x88\xd8\x02\xd8\xd8\
+\x02\x01\x58\x04\xd8\xd8\x02\xe0\xd8\x02\x01\x53\x04\xe0\xd8\x02\xb0\xd9\x02\
+\x01\x58\x04\xb0\xd9\x02\xb8\xd9\x02\x01\x53\x04\xb8\xd9\x02\x88\xda\x02\x01\
+\x58\x04\x88\xda\x02\x90\xda\x02\x01\x53\x04\x90\xda\x02\xe0\xda\x02\x01\x58\
+\x04\xe0\xda\x02\xe8\xda\x02\x01\x53\x04\xe8\xda\x02\xb8\xdb\x02\x01\x58\x04\
+\xb8\xdb\x02\xc0\xdb\x02\x01\x53\x04\xc0\xdb\x02\x90\xdc\x02\x01\x58\x04\x90\
+\xdc\x02\x98\xdc\x02\x01\x53\x04\x98\xdc\x02\xe8\xdc\x02\x01\x58\x04\xe8\xdc\
+\x02\xf0\xdc\x02\x01\x53\x04\xf0\xdc\x02\xc0\xdd\x02\x01\x58\x04\xc0\xdd\x02\
+\xc8\xdd\x02\x01\x53\x04\xc8\xdd\x02\x98\xde\x02\x01\x58\x04\x98\xde\x02\xa0\
+\xde\x02\x01\x53\x04\xa0\xde\x02\xf0\xde\x02\x01\x58\x04\xf0\xde\x02\xf8\xde\
+\x02\x01\x53\x04\xf8\xde\x02\xc8\xdf\x02\x01\x58\x04\xc8\xdf\x02\xd0\xdf\x02\
+\x01\x53\x04\xd0\xdf\x02\xa0\xe0\x02\x01\x58\x04\xa0\xe0\x02\xa8\xe0\x02\x01\
+\x53\x04\xa8\xe0\x02\xf8\xe0\x02\x01\x58\x04\xf8\xe0\x02\x80\xe1\x02\x01\x53\
+\x04\x80\xe1\x02\xd0\xe1\x02\x01\x58\x04\xd0\xe1\x02\xd8\xe1\x02\x01\x53\x04\
+\xd8\xe1\x02\xa8\xe2\x02\x01\x58\x04\xa8\xe2\x02\xb0\xe2\x02\x01\x53\x04\xb0\
+\xe2\x02\x80\xe3\x02\x01\x58\x04\x80\xe3\x02\x88\xe3\x02\x01\x53\x04\x88\xe3\
+\x02\xd8\xe3\x02\x01\x58\x04\xd8\xe3\x02\xe0\xe3\x02\x01\x53\x04\xe0\xe3\x02\
+\xb0\xe4\x02\x01\x58\x04\xb0\xe4\x02\xb8\xe4\x02\x01\x51\x04\xb8\xe4\x02\x98\
+\xe5\x02\x01\x58\x04\x98\xe5\x02\xa0\xe5\x02\x01\x53\x04\xa0\xe5\x02\xf0\xe5\
+\x02\x01\x58\x04\xf0\xe5\x02\xf8\xe5\x02\x01\x53\x04\xf8\xe5\x02\xc8\xe6\x02\
+\x01\x58\x04\xc8\xe6\x02\xd0\xe6\x02\x01\x53\x04\xd0\xe6\x02\xa0\xe7\x02\x01\
+\x58\x04\xa0\xe7\x02\xa8\xe7\x02\x01\x53\x04\xa8\xe7\x02\xf8\xe7\x02\x01\x58\
+\x04\xf8\xe7\x02\x80\xe8\x02\x01\x53\x04\x80\xe8\x02\xd0\xe8\x02\x01\x58\x04\
+\xd0\xe8\x02\xd8\xe8\x02\x01\x53\x04\xd8\xe8\x02\xa8\xe9\x02\x01\x58\x04\xa8\
+\xe9\x02\xb0\xe9\x02\x01\x53\x04\xb0\xe9\x02\x80\xea\x02\x01\x58\x04\x80\xea\
+\x02\x88\xea\x02\x01\x53\x04\x88\xea\x02\xd8\xea\x02\x01\x58\x04\xd8\xea\x02\
+\xe0\xea\x02\x01\x53\x04\xe0\xea\x02\xb0\xeb\x02\x01\x58\x04\xb0\xeb\x02\xb8\
+\xeb\x02\x01\x53\x04\xb8\xeb\x02\x88\xec\x02\x01\x58\x04\x88\xec\x02\x90\xec\
+\x02\x01\x53\x04\x90\xec\x02\xe0\xec\x02\x01\x58\x04\xe0\xec\x02\xe8\xec\x02\
+\x01\x53\x04\xe8\xec\x02\xb8\xed\x02\x01\x58\x04\xb8\xed\x02\xc0\xed\x02\x01\
+\x53\x04\xc0\xed\x02\x90\xee\x02\x01\x58\x04\x90\xee\x02\x98\xee\x02\x01\x53\
+\x04\x98\xee\x02\xe8\xee\x02\x01\x58\x04\xe8\xee\x02\xf0\xee\x02\x01\x53\x04\
+\xf0\xee\x02\xc0\xef\x02\x01\x58\x04\xc0\xef\x02\xc8\xef\x02\x01\x53\x04\xc8\
+\xef\x02\x98\xf0\x02\x01\x58\x04\x98\xf0\x02\xa0\xf0\x02\x01\x53\x04\xa0\xf0\
+\x02\xf0\xf0\x02\x01\x58\x04\xf0\xf0\x02\xf8\xf0\x02\x01\x53\x04\xf8\xf0\x02\
+\xc8\xf1\x02\x01\x58\x04\xc8\xf1\x02\xd0\xf1\x02\x01\x53\x04\xd0\xf1\x02\xa0\
+\xf2\x02\x01\x58\x04\xa0\xf2\x02\xa8\xf2\x02\x01\x53\x04\xa8\xf2\x02\xf8\xf2\
+\x02\x01\x58\x04\xf8\xf2\x02\x80\xf3\x02\x01\x53\x04\x80\xf3\x02\xd0\xf3\x02\
+\x01\x58\x04\xd0\xf3\x02\xd8\xf3\x02\x01\x53\x04\xd8\xf3\x02\xa8\xf4\x02\x01\
+\x58\x04\xa8\xf4\x02\xb0\xf4\x02\x01\x53\x04\xb0\xf4\x02\x80\xf5\x02\x01\x58\
+\x04\x80\xf5\x02\x88\xf5\x02\x01\x53\x04\x88\xf5\x02\xd8\xf5\x02\x01\x58\x04\
+\xd8\xf5\x02\xe0\xf5\x02\x01\x53\x04\xe0\xf5\x02\xb0\xf6\x02\x01\x58\x04\xb0\
+\xf6\x02\xb8\xf6\x02\x01\x53\x04\xb8\xf6\x02\x88\xf7\x02\x01\x58\x04\x88\xf7\
+\x02\x90\xf7\x02\x01\x53\x04\x90\xf7\x02\xe0\xf7\x02\x01\x58\x04\xe0\xf7\x02\
+\xe8\xf7\x02\x01\x53\x04\xe8\xf7\x02\xb8\xf8\x02\x01\x58\x04\xb8\xf8\x02\xc0\
+\xf8\x02\x01\x53\x04\xc0\xf8\x02\x90\xf9\x02\x01\x58\x04\x90\xf9\x02\x98\xf9\
+\x02\x01\x53\x04\x98\xf9\x02\xe8\xf9\x02\x01\x58\x04\xe8\xf9\x02\xf0\xf9\x02\
+\x01\x52\x04\xf0\xf9\x02\xd0\xfa\x02\x01\x58\x04\xd0\xfa\x02\xd8\xfa\x02\x01\
+\x53\x04\xd8\xfa\x02\xa8\xfb\x02\x01\x58\x04\xa8\xfb\x02\xb0\xfb\x02\x01\x53\
+\x04\xb0\xfb\x02\x80\xfc\x02\x01\x58\x04\x80\xfc\x02\x88\xfc\x02\x01\x53\x04\
+\x88\xfc\x02\xd8\xfc\x02\x01\x58\x04\xd8\xfc\x02\xe0\xfc\x02\x01\x53\x04\xe0\
+\xfc\x02\xb0\xfd\x02\x01\x58\x04\xb0\xfd\x02\xb8\xfd\x02\x01\x53\x04\xb8\xfd\
+\x02\x88\xfe\x02\x01\x58\x04\x88\xfe\x02\x90\xfe\x02\x01\x53\x04\x90\xfe\x02\
+\xe0\xfe\x02\x01\x58\x04\xe0\xfe\x02\xe8\xfe\x02\x01\x53\x04\xe8\xfe\x02\xb8\
+\xff\x02\x01\x58\x04\xb8\xff\x02\xc0\xff\x02\x01\x53\x04\xc0\xff\x02\x90\x80\
+\x03\x01\x58\x04\x90\x80\x03\x98\x80\x03\x01\x53\x04\x98\x80\x03\xe8\x80\x03\
+\x01\x58\x04\xe8\x80\x03\xf0\x80\x03\x01\x53\x04\xf0\x80\x03\xc0\x81\x03\x01\
+\x58\x04\xc0\x81\x03\xc8\x81\x03\x01\x53\x04\xc8\x81\x03\x98\x82\x03\x01\x58\
+\x04\x98\x82\x03\xa0\x82\x03\x01\x53\x04\xa0\x82\x03\xf0\x82\x03\x01\x58\x04\
+\xf0\x82\x03\xf8\x82\x03\x01\x53\x04\xf8\x82\x03\xc8\x83\x03\x01\x58\x04\xc8\
+\x83\x03\xd0\x83\x03\x01\x53\x04\xd0\x83\x03\xa0\x84\x03\x01\x58\x04\xa0\x84\
+\x03\xa8\x84\x03\x01\x53\x04\xa8\x84\x03\xf8\x84\x03\x01\x58\x04\xf8\x84\x03\
+\x80\x85\x03\x01\x53\x04\x80\x85\x03\xd0\x85\x03\x01\x58\x04\xd0\x85\x03\xd8\
+\x85\x03\x01\x53\x04\xd8\x85\x03\xa8\x86\x03\x01\x58\x04\xa8\x86\x03\xb0\x86\
+\x03\x01\x53\x04\xb0\x86\x03\x80\x87\x03\x01\x58\x04\x80\x87\x03\x88\x87\x03\
+\x01\x53\x04\x88\x87\x03\xd8\x87\x03\x01\x58\x04\xd8\x87\x03\xe0\x87\x03\x01\
+\x53\x04\xe0\x87\x03\xb0\x88\x03\x01\x58\x04\xb0\x88\x03\xb8\x88\x03\x01\x53\
+\x04\xb8\x88\x03\x88\x89\x03\x01\x58\x04\x88\x89\x03\x90\x89\x03\x01\x53\x04\
+\x90\x89\x03\xe0\x89\x03\x01\x58\x04\xe0\x89\x03\xe8\x89\x03\x01\x53\x04\xe8\
+\x89\x03\xb8\x8a\x03\x01\x58\x04\xb8\x8a\x03\xc0\x8a\x03\x01\x53\x04\xc0\x8a\
+\x03\x90\x8b\x03\x01\x58\x04\x90\x8b\x03\x98\x8b\x03\x01\x53\x04\x98\x8b\x03\
+\xe8\x8b\x03\x01\x58\x04\xe8\x8b\x03\xf0\x8b\x03\x01\x53\x04\xf0\x8b\x03\xc0\
+\x8c\x03\x01\x58\x04\xc0\x8c\x03\xc8\x8c\x03\x01\x53\x04\xc8\x8c\x03\x98\x8d\
+\x03\x01\x58\x04\x98\x8d\x03\xa0\x8d\x03\x01\x53\x04\xa0\x8d\x03\xf0\x8d\x03\
+\x01\x58\x04\xf0\x8d\x03\xf8\x8d\x03\x01\x53\x04\xf8\x8d\x03\xc8\x8e\x03\x01\
+\x58\x04\xc8\x8e\x03\xd0\x8e\x03\x01\x53\x04\xd0\x8e\x03\x98\x8f\x03\x01\x58\
+\x04\x98\x8f\x03\xa0\x8f\x03\x01\x51\x04\xa0\x8f\x03\x80\x90\x03\x01\x58\x04\
+\x80\x90\x03\x88\x90\x03\x01\x51\x04\x88\x90\x03\xe0\x90\x03\x01\x58\x04\xe0\
+\x90\x03\xe8\x90\x03\x01\x51\x04\xe8\x90\x03\xb8\x91\x03\x01\x58\x04\xb8\x91\
+\x03\xc0\x91\x03\x01\x51\x04\xc0\x91\x03\x90\x92\x03\x01\x58\x04\x90\x92\x03\
+\x98\x92\x03\x01\x51\x04\x98\x92\x03\xe8\x92\x03\x01\x58\x04\xe8\x92\x03\xf0\
+\x92\x03\x01\x51\x04\xf0\x92\x03\xc0\x93\x03\x01\x58\x04\xc0\x93\x03\xc8\x93\
+\x03\x01\x51\x04\xc8\x93\x03\x98\x94\x03\x01\x58\x04\x98\x94\x03\xa0\x94\x03\
+\x01\x51\x04\xa0\x94\x03\xf0\x94\x03\x01\x58\x04\xf0\x94\x03\xf8\x94\x03\x01\
+\x51\x04\xf8\x94\x03\xc8\x95\x03\x01\x58\x04\xc8\x95\x03\xd0\x95\x03\x01\x51\
+\x04\xd0\x95\x03\xa0\x96\x03\x01\x58\x04\xa0\x96\x03\xa8\x96\x03\x01\x51\x04\
+\xa8\x96\x03\xf8\x96\x03\x01\x58\x04\xf8\x96\x03\x80\x97\x03\x01\x51\x04\x80\
+\x97\x03\xd0\x97\x03\x01\x58\x04\xd0\x97\x03\xd8\x97\x03\x01\x51\x04\xd8\x97\
+\x03\xa8\x98\x03\x01\x58\x04\xa8\x98\x03\xb0\x98\x03\x01\x51\x04\xb0\x98\x03\
+\x80\x99\x03\x01\x58\x04\x80\x99\x03\x88\x99\x03\x01\x51\x04\x88\x99\x03\xd8\
+\x99\x03\x01\x58\x04\xd8\x99\x03\xe0\x99\x03\x01\x51\x04\xe0\x99\x03\xb0\x9a\
+\x03\x01\x58\x04\xb0\x9a\x03\xb8\x9a\x03\x01\x51\x04\xb8\x9a\x03\x88\x9b\x03\
+\x01\x58\x04\x88\x9b\x03\x90\x9b\x03\x01\x51\x04\x90\x9b\x03\xe0\x9b\x03\x01\
+\x58\x04\xe0\x9b\x03\xe8\x9b\x03\x01\x51\x04\xe8\x9b\x03\xb8\x9c\x03\x01\x58\
+\x04\xb8\x9c\x03\xc0\x9c\x03\x01\x51\x04\xc0\x9c\x03\x90\x9d\x03\x01\x58\x04\
+\x90\x9d\x03\x98\x9d\x03\x01\x51\x04\x98\x9d\x03\xe8\x9d\x03\x01\x58\x04\xe8\
+\x9d\x03\xf0\x9d\x03\x01\x51\x04\xf0\x9d\x03\xc0\x9e\x03\x01\x58\x04\xc0\x9e\
+\x03\xc8\x9e\x03\x01\x51\x04\xc8\x9e\x03\x98\x9f\x03\x01\x58\x04\x98\x9f\x03\
+\xa0\x9f\x03\x01\x51\x04\xa0\x9f\x03\xf0\x9f\x03\x01\x58\x04\xf0\x9f\x03\xf8\
+\x9f\x03\x01\x51\x04\xf8\x9f\x03\xc8\xa0\x03\x01\x58\x04\xc8\xa0\x03\xd0\xa0\
+\x03\x01\x51\x04\xd0\xa0\x03\xa0\xa1\x03\x01\x58\x04\xa0\xa1\x03\xa8\xa1\x03\
+\x01\x51\x04\xa8\xa1\x03\xf8\xa1\x03\x01\x58\x04\xf8\xa1\x03\x80\xa2\x03\x01\
+\x51\x04\x80\xa2\x03\xd0\xa2\x03\x01\x58\x04\xd0\xa2\x03\xd8\xa2\x03\x01\x51\
+\x04\xd8\xa2\x03\xa8\xa3\x03\x01\x58\x04\xa8\xa3\x03\xb0\xa3\x03\x01\x51\x04\
+\xb0\xa3\x03\x80\xa4\x03\x01\x58\x04\x80\xa4\x03\x88\xa4\x03\x01\x51\x04\x88\
+\xa4\x03\xd0\xa4\x03\x01\x58\x04\xd0\xa4\x03\xd8\xa4\x03\x01\x51\x04\xd8\xa4\
+\x03\xb8\xa5\x03\x01\x58\x04\xb8\xa5\x03\xc0\xa5\x03\x01\x52\x04\xc0\xa5\x03\
+\x90\xa6\x03\x01\x58\x04\x90\xa6\x03\x98\xa6\x03\x01\x52\x04\x98\xa6\x03\xe8\
+\xa6\x03\x01\x58\x04\xe8\xa6\x03\xf0\xa6\x03\x01\x52\x04\xf0\xa6\x03\xc0\xa7\
+\x03\x01\x58\x04\xc0\xa7\x03\xc8\xa7\x03\x01\x52\x04\xc8\xa7\x03\x98\xa8\x03\
+\x01\x58\x04\x98\xa8\x03\xa0\xa8\x03\x01\x52\x04\xa0\xa8\x03\xf0\xa8\x03\x01\
+\x58\x04\xf0\xa8\x03\xf8\xa8\x03\x01\x52\x04\xf8\xa8\x03\xc8\xa9\x03\x01\x58\
+\x04\xc8\xa9\x03\xd0\xa9\x03\x01\x52\x04\xd0\xa9\x03\xa0\xaa\x03\x01\x58\x04\
+\xa0\xaa\x03\xa8\xaa\x03\x01\x52\x04\xa8\xaa\x03\xf8\xaa\x03\x01\x58\x04\xf8\
+\xaa\x03\x80\xab\x03\x01\x52\x04\x80\xab\x03\xd0\xab\x03\x01\x58\x04\xd0\xab\
+\x03\xd8\xab\x03\x01\x52\x04\xd8\xab\x03\xa8\xac\x03\x01\x58\x04\xa8\xac\x03\
+\xb0\xac\x03\x01\x52\x04\xb0\xac\x03\x80\xad\x03\x01\x58\x04\x80\xad\x03\x88\
+\xad\x03\x01\x52\x04\x88\xad\x03\xd8\xad\x03\x01\x58\x04\xd8\xad\x03\xe0\xad\
+\x03\x01\x52\x04\xe0\xad\x03\xb0\xae\x03\x01\x58\x04\xb0\xae\x03\xb8\xae\x03\
+\x01\x52\x04\xb8\xae\x03\x88\xaf\x03\x01\x58\x04\x88\xaf\x03\x90\xaf\x03\x01\
+\x52\x04\x90\xaf\x03\xe0\xaf\x03\x01\x58\x04\xe0\xaf\x03\xe8\xaf\x03\x01\x52\
+\x04\xe8\xaf\x03\xb8\xb0\x03\x01\x58\x04\xb8\xb0\x03\xc0\xb0\x03\x01\x52\x04\
+\xc0\xb0\x03\x90\xb1\x03\x01\x58\x04\x90\xb1\x03\x98\xb1\x03\x01\x52\x04\x98\
+\xb1\x03\xe8\xb1\x03\x01\x58\x04\xe8\xb1\x03\xf0\xb1\x03\x01\x52\x04\xf0\xb1\
+\x03\xc0\xb2\x03\x01\x58\x04\xc0\xb2\x03\xc8\xb2\x03\x01\x52\x04\xc8\xb2\x03\
+\x98\xb3\x03\x01\x58\x04\x98\xb3\x03\xa0\xb3\x03\x01\x52\x04\xa0\xb3\x03\xf0\
+\xb3\x03\x01\x58\x04\xf0\xb3\x03\xf8\xb3\x03\x01\x52\x04\xf8\xb3\x03\xc8\xb4\
+\x03\x01\x58\x04\xc8\xb4\x03\xd0\xb4\x03\x01\x52\x04\xd0\xb4\x03\xa0\xb5\x03\
+\x01\x58\x04\xa0\xb5\x03\xa8\xb5\x03\x01\x52\x04\xa8\xb5\x03\xf8\xb5\x03\x01\
+\x58\x04\xf8\xb5\x03\x80\xb6\x03\x01\x52\x04\x80\xb6\x03\xd0\xb6\x03\x01\x58\
+\x04\xd0\xb6\x03\xd8\xb6\x03\x01\x52\x04\xd8\xb6\x03\xa8\xb7\x03\x01\x58\x04\
+\xa8\xb7\x03\xb0\xb7\x03\x01\x52\x04\xb0\xb7\x03\x80\xb8\x03\x01\x58\x04\x80\
+\xb8\x03\x88\xb8\x03\x01\x52\x04\x88\xb8\x03\xd8\xb8\x03\x01\x58\x04\xd8\xb8\
+\x03\xe0\xb8\x03\x01\x52\x04\xe0\xb8\x03\xb0\xb9\x03\x01\x58\x04\xb0\xb9\x03\
+\xb8\xb9\x03\x01\x52\x04\xb8\xb9\x03\x80\xba\x03\x01\x58\x04\x80\xba\x03\x88\
+\xba\x03\x01\x52\x04\x88\xba\x03\xe8\xba\x03\x01\x58\x04\xe8\xba\x03\xf0\xba\
+\x03\x01\x53\x04\xf0\xba\x03\xc0\xbb\x03\x01\x58\x04\xc0\xbb\x03\xc8\xbb\x03\
+\x01\x53\x04\xc8\xbb\x03\x98\xbc\x03\x01\x58\x04\x98\xbc\x03\xa0\xbc\x03\x01\
+\x53\x04\xa0\xbc\x03\xf0\xbc\x03\x01\x58\x04\xf0\xbc\x03\xf8\xbc\x03\x01\x53\
+\x04\xf8\xbc\x03\xc8\xbd\x03\x01\x58\x04\xc8\xbd\x03\xd0\xbd\x03\x01\x53\x04\
+\xd0\xbd\x03\xa0\xbe\x03\x01\x58\x04\xa0\xbe\x03\xa8\xbe\x03\x01\x53\x04\xa8\
+\xbe\x03\xf8\xbe\x03\x01\x58\x04\xf8\xbe\x03\x80\xbf\x03\x01\x53\x04\x80\xbf\
+\x03\xd0\xbf\x03\x01\x58\x04\xd0\xbf\x03\xd8\xbf\x03\x01\x53\x04\xd8\xbf\x03\
+\xa8\xc0\x03\x01\x58\x04\xa8\xc0\x03\xb0\xc0\x03\x01\x53\x04\xb0\xc0\x03\x80\
+\xc1\x03\x01\x58\x04\x80\xc1\x03\x88\xc1\x03\x01\x53\x04\x88\xc1\x03\xd8\xc1\
+\x03\x01\x58\x04\xd8\xc1\x03\xe0\xc1\x03\x01\x53\x04\xe0\xc1\x03\xb0\xc2\x03\
+\x01\x58\x04\xb0\xc2\x03\xb8\xc2\x03\x01\x53\x04\xb8\xc2\x03\x88\xc3\x03\x01\
+\x58\x04\x88\xc3\x03\x90\xc3\x03\x01\x53\x04\x90\xc3\x03\xe0\xc3\x03\x01\x58\
+\x04\xe0\xc3\x03\xe8\xc3\x03\x01\x53\x04\xe8\xc3\x03\xb8\xc4\x03\x01\x58\x04\
+\xb8\xc4\x03\xc0\xc4\x03\x01\x53\x04\xc0\xc4\x03\x90\xc5\x03\x01\x58\x04\x90\
+\xc5\x03\x98\xc5\x03\x01\x53\x04\x98\xc5\x03\xe8\xc5\x03\x01\x58\x04\xe8\xc5\
+\x03\xf0\xc5\x03\x01\x53\x04\xf0\xc5\x03\xc0\xc6\x03\x01\x58\x04\xc0\xc6\x03\
+\xc8\xc6\x03\x01\x53\x04\xc8\xc6\x03\x98\xc7\x03\x01\x58\x04\x98\xc7\x03\xa0\
+\xc7\x03\x01\x53\x04\xa0\xc7\x03\xf0\xc7\x03\x01\x58\x04\xf0\xc7\x03\xf8\xc7\
+\x03\x01\x53\x04\xf8\xc7\x03\xc8\xc8\x03\x01\x58\x04\xc8\xc8\x03\xd0\xc8\x03\
+\x01\x53\x04\xd0\xc8\x03\xa0\xc9\x03\x01\x58\x04\xa0\xc9\x03\xa8\xc9\x03\x01\
+\x53\x04\xa8\xc9\x03\xf8\xc9\x03\x01\x58\x04\xf8\xc9\x03\x80\xca\x03\x01\x53\
+\x04\x80\xca\x03\xd0\xca\x03\x01\x58\x04\xd0\xca\x03\xd8\xca\x03\x01\x53\x04\
+\xd8\xca\x03\xa8\xcb\x03\x01\x58\x04\xa8\xcb\x03\xb0\xcb\x03\x01\x53\x04\xb0\
+\xcb\x03\x80\xcc\x03\x01\x58\x04\x80\xcc\x03\x88\xcc\x03\x01\x53\x04\x88\xcc\
+\x03\xd8\xcc\x03\x01\x58\x04\xd8\xcc\x03\xe0\xcc\x03\x01\x53\x04\xe0\xcc\x03\
+\xb8\xcd\x03\x01\x58\x04\xb8\xcd\x03\xc0\xcd\x03\x01\x54\x04\xc0\xcd\x03\xa0\
+\xce\x03\x01\x58\x04\xa0\xce\x03\xa8\xce\x03\x01\x55\x04\xa8\xce\x03\x80\xcf\
+\x03\x01\x58\x04\x80\xcf\x03\x88\xcf\x03\x01\x54\x04\x88\xcf\x03\xd8\xcf\x03\
+\x01\x58\x04\xd8\xcf\x03\xe0\xcf\x03\x01\x51\x04\xe0\xcf\x03\xb8\xd0\x03\x01\
+\x58\x04\xb8\xd0\x03\xc0\xd0\x03\x01\x51\x04\xc0\xd0\x03\x90\xd1\x03\x01\x58\
+\x04\x90\xd1\x03\x98\xd1\x03\x01\x51\x04\x98\xd1\x03\xe8\xd1\x03\x01\x58\x04\
+\xe8\xd1\x03\xf0\xd1\x03\x01\x51\x04\xf0\xd1\x03\xc0\xd2\x03\x01\x58\x04\xc0\
+\xd2\x03\xc8\xd2\x03\x01\x51\x04\xc8\xd2\x03\x98\xd3\x03\x01\x58\x04\x98\xd3\
+\x03\xa0\xd3\x03\x01\x51\x04\xa0\xd3\x03\xf0\xd3\x03\x01\x58\x04\xf0\xd3\x03\
+\xf8\xd3\x03\x01\x51\x04\xf8\xd3\x03\xc8\xd4\x03\x01\x58\x04\xc8\xd4\x03\xd0\
+\xd4\x03\x01\x51\x04\xd0\xd4\x03\xa0\xd5\x03\x01\x58\x04\xa0\xd5\x03\xa8\xd5\
+\x03\x01\x51\x04\xa8\xd5\x03\xf8\xd5\x03\x01\x58\x04\xf8\xd5\x03\x80\xd6\x03\
+\x01\x51\x04\x80\xd6\x03\xd0\xd6\x03\x01\x58\x04\xd0\xd6\x03\xd8\xd6\x03\x01\
+\x51\x04\xd8\xd6\x03\xa8\xd7\x03\x01\x58\x04\xa8\xd7\x03\xb0\xd7\x03\x01\x51\
+\x04\xb0\xd7\x03\x80\xd8\x03\x01\x58\x04\x80\xd8\x03\x88\xd8\x03\x01\x51\x04\
+\x88\xd8\x03\xd8\xd8\x03\x01\x58\x04\xd8\xd8\x03\xe0\xd8\x03\x01\x51\x04\xe0\
+\xd8\x03\xb0\xd9\x03\x01\x58\x04\xb0\xd9\x03\xb8\xd9\x03\x01\x51\x04\xb8\xd9\
+\x03\x88\xda\x03\x01\x58\x04\x88\xda\x03\x90\xda\x03\x01\x51\x04\x90\xda\x03\
+\xe0\xda\x03\x01\x58\x04\xe0\xda\x03\xe8\xda\x03\x01\x51\x04\xe8\xda\x03\xb8\
+\xdb\x03\x01\x58\x04\xb8\xdb\x03\xc0\xdb\x03\x01\x51\x04\xc0\xdb\x03\x90\xdc\
+\x03\x01\x58\x04\x90\xdc\x03\x98\xdc\x03\x01\x51\x04\x98\xdc\x03\xe8\xdc\x03\
+\x01\x58\x04\xe8\xdc\x03\xf0\xdc\x03\x01\x51\x04\xf0\xdc\x03\xc0\xdd\x03\x01\
+\x58\x04\xc0\xdd\x03\xc8\xdd\x03\x01\x51\x04\xc8\xdd\x03\x98\xde\x03\x01\x58\
+\x04\x98\xde\x03\xa0\xde\x03\x01\x51\x04\xa0\xde\x03\xf0\xde\x03\x01\x58\x04\
+\xf0\xde\x03\xf8\xde\x03\x01\x51\x04\xf8\xde\x03\xc8\xdf\x03\x01\x58\x04\xc8\
+\xdf\x03\xd0\xdf\x03\x01\x51\x04\xd0\xdf\x03\xa0\xe0\x03\x01\x58\x04\xa0\xe0\
+\x03\xa8\xe0\x03\x01\x51\x04\xa8\xe0\x03\xf8\xe0\x03\x01\x58\x04\xf8\xe0\x03\
+\x80\xe1\x03\x01\x51\x04\x80\xe1\x03\xd0\xe1\x03\x01\x58\x04\xd0\xe1\x03\xd8\
+\xe1\x03\x01\x51\x04\xd8\xe1\x03\xa8\xe2\x03\x01\x58\x04\xa8\xe2\x03\xb0\xe2\
+\x03\x01\x51\x04\xb0\xe2\x03\x80\xe3\x03\x01\x58\x04\x80\xe3\x03\x88\xe3\x03\
+\x01\x51\x04\x88\xe3\x03\xd8\xe3\x03\x01\x58\x04\xd8\xe3\x03\xe0\xe3\x03\x01\
+\x51\x04\xe0\xe3\x03\xb0\xe4\x03\x01\x58\x04\xb0\xe4\x03\xb8\xe4\x03\x01\x51\
+\x04\xb8\xe4\x03\xc0\xe4\x03\x01\x58\x04\xc0\xe4\x03\xf8\xe4\x03\x03\x7a\xc0\0\
+\0\x01\x11\x01\x25\x25\x13\x05\x03\x25\x72\x17\x10\x17\x1b\x25\x11\x1b\x12\x06\
+\x73\x17\x74\x17\x8c\x01\x17\0\0\x02\x24\0\x03\x25\x3e\x0b\x0b\x0b\0\0\x03\x2e\
+\x01\x11\x1b\x12\x06\x40\x18\x7a\x19\x03\x25\x3a\x0b\x3b\x0b\x27\x19\x49\x13\
+\x3f\x19\0\0\x04\x34\0\x03\x25\x49\x13\x3a\x0b\x3b\x0b\x02\x18\0\0\x05\x34\0\
+\x03\x25\x49\x13\x3a\x0b\x3b\x05\x02\x18\0\0\x06\x05\0\x02\x22\x03\x25\x3a\x0b\
+\x3b\x0b\x49\x13\0\0\x07\x34\0\x02\x18\x03\x25\x3a\x0b\x3b\x0b\x49\x13\0\0\x08\
+\x34\0\x02\x22\x03\x25\x3a\x0b\x3b\x0b\x49\x13\0\0\x09\x1d\x01\x31\x13\x55\x23\
+\x58\x0b\x59\x05\x57\x0b\0\0\x0a\x05\0\x02\x22\x31\x13\0\0\x0b\x34\0\x02\x22\
+\x31\x13\0\0\x0c\x1d\x01\x31\x13\x55\x23\x58\x0b\x59\x0b\x57\x0b\0\0\x0d\x34\0\
+\x02\x18\x31\x13\0\0\x0e\x1d\x01\x31\x13\x11\x1b\x12\x06\x58\x0b\x59\x0b\x57\
+\x0b\0\0\x0f\x05\0\x02\x18\x31\x13\0\0\x10\x0b\x01\x55\x23\0\0\x11\x05\0\x1c\
+\x0f\x31\x13\0\0\x12\x0b\x01\x11\x1b\x12\x06\0\0\x13\x1d\x01\x31\x13\x11\x1b\
+\x12\x06\x58\x0b\x59\x05\x57\x0b\0\0\x14\x01\x01\x49\x13\0\0\x15\x21\0\x49\x13\
+\x37\x0b\0\0\x16\x26\0\x49\x13\0\0\x17\x24\0\x03\x25\x0b\x0b\x3e\x0b\0\0\x18\
+\x34\0\x03\x25\x49\x13\x3f\x19\x3a\x0b\x3b\x05\x02\x18\0\0\x19\x34\0\x03\x25\
+\x49\x13\x3f\x19\x3a\x0b\x3b\x0b\x02\x18\0\0\x1a\x13\x01\x0b\x0b\x3a\x0b\x3b\
+\x0b\0\0\x1b\x0d\0\x03\x25\x49\x13\x3a\x0b\x3b\x0b\x38\x0b\0\0\x1c\x0f\0\x49\
+\x13\0\0\x1d\x34\0\x03\x25\x49\x13\x3a\x0b\x3b\x0b\0\0\x1e\x15\x01\x49\x13\x27\
+\x19\0\0\x1f\x05\0\x49\x13\0\0\x20\x18\0\0\0\x21\x16\0\x49\x13\x03\x25\x3a\x0b\
+\x3b\x0b\0\0\x22\x0f\0\0\0\x23\x26\0\0\0\x24\x34\0\x03\x25\x49\x13\x3a\x0b\x3b\
+\x05\0\0\x25\x04\x01\x49\x13\x03\x25\x0b\x0b\x3a\x0b\x3b\x05\0\0\x26\x28\0\x03\
+\x25\x1c\x0f\0\0\x27\x04\x01\x49\x13\x03\x25\x0b\x0b\x3a\x0b\x3b\x0b\0\0\x28\
+\x04\x01\x49\x13\x0b\x0b\x3a\x0b\x3b\x0b\0\0\x29\x13\x01\x03\x25\x0b\x0b\x3a\
+\x0b\x3b\x0b\0\0\x2a\x0d\0\x49\x13\x3a\x0b\x3b\x0b\x38\x0b\0\0\x2b\x2e\x01\x03\
+\x25\x3a\x0b\x3b\x0b\x27\x19\x49\x13\x20\x21\x01\0\0\x2c\x05\0\x03\x25\x3a\x0b\
+\x3b\x0b\x49\x13\0\0\x2d\x34\0\x03\x25\x3a\x0b\x3b\x0b\x49\x13\0\0\x2e\x13\x01\
+\x03\x25\x0b\x0b\x3a\x0b\x3b\x05\0\0\x2f\x0d\0\x03\x25\x49\x13\x3a\x0b\x3b\x05\
+\x38\x0b\0\0\x30\x0d\0\x49\x13\x3a\x0b\x3b\x05\x88\x01\x0f\x38\x0b\0\0\x31\x17\
+\x01\x0b\x0b\x3a\x0b\x3b\x05\x88\x01\x0f\0\0\x32\x0d\0\x49\x13\x3a\x0b\x3b\x05\
+\x38\x0b\0\0\x33\x17\x01\x0b\x0b\x3a\x0b\x3b\x05\0\0\x34\x13\x01\x0b\x0b\x3a\
+\x0b\x3b\x05\0\0\x35\x0b\x01\0\0\x36\x0d\0\x03\x25\x49\x13\x3a\x0b\x3b\x0b\x0d\
+\x0b\x6b\x0b\0\0\x37\x17\x01\x0b\x0b\x3a\x0b\x3b\x0b\0\0\x38\x2e\x01\0\0\0\x7a\
+\x0b\0\0\x05\0\x01\x08\0\0\0\0\x01\0\x1d\0\x01\x08\0\0\0\0\0\0\0\x02\x05\xc8\
+\xf6\0\0\x08\0\0\0\x0c\0\0\0\x0c\0\0\0\x02\xbe\x07\x01\x02\xbd\x07\x02\x02\xbc\
+\x07\x04\x03\x05\xc8\xf6\0\0\x01\x5a\xbf\0\xf0\xaf\x02\0\0\x04\x03\x21\x02\0\0\
+\0\xfe\x02\xa1\0\x05\x03\x3a\x02\0\0\0\x03\x01\x02\xa1\x01\x05\x03\x46\x02\0\0\
+\0\x07\x01\x02\xa1\x02\x06\0\x43\0\xf0\x78\x0b\0\0\x07\x03\x91\xe0\0\xc0\0\xf3\
+\x6c\x0b\0\0\x08\x01\xc1\0\xf4\x39\x04\0\0\x08\x02\x84\0\xf2\xc1\x07\0\0\x08\
+\x06\x51\0\xf5\x0d\x03\0\0\x09\x70\x04\0\0\0\0\x02\x01\x09\x0a\x04\x78\x04\0\0\
+\x0a\x03\x80\x04\0\0\x0b\x05\x88\x04\0\0\x0c\x0d\x08\0\0\x01\0\xce\x0a\x0a\x09\
+\x15\x08\0\0\x0a\x08\x25\x08\0\0\x0d\x03\x91\x88\x01\x2d\x08\0\0\x0b\x07\x35\
+\x08\0\0\x0b\x0a\x3d\x08\0\0\x0e\x34\x09\0\0\x06\x18\x16\0\0\0\x56\x0a\x0b\x0b\
+\x54\x09\0\0\x0b\x0c\x5c\x09\0\0\x0b\x0d\x64\x09\0\0\0\x0e\xdc\x0a\0\0\x07\x10\
+\0\0\0\0\x59\x06\x0f\x04\x91\x88\x01\x9f\xe4\x0a\0\0\0\x10\x02\x0d\x03\x91\x80\
+\x01\x46\x08\0\0\x0c\x34\x09\0\0\x03\0\x66\x0a\x11\x03\x44\x09\0\0\x0a\x19\x4c\
+\x09\0\0\x0b\x16\x54\x09\0\0\x0b\x17\x5c\x09\0\0\x0b\x18\x64\x09\0\0\0\0\0\x0c\
+\x6d\x09\0\0\x04\0\xd0\x0a\x0a\x11\x75\x09\0\0\x0a\x10\x85\x09\0\0\x0d\x03\x91\
+\x88\x01\x8d\x09\0\0\x0b\x0e\x95\x09\0\0\x0b\x0f\x9d\x09\0\0\x0b\x12\xa5\x09\0\
+\0\x0b\x1d\xad\x09\0\0\x0b\x1e\xb5\x09\0\0\x0e\x34\x09\0\0\x08\x80\x55\0\0\0\
+\xad\x0a\x0b\x13\x54\x09\0\0\x0b\x14\x5c\x09\0\0\x0b\x15\x64\x09\0\0\0\x0c\xfb\
+\x0a\0\0\x05\0\xb0\x0a\x0a\x1a\x03\x0b\0\0\x0a\x1c\x0b\x0b\0\0\x0d\x03\x91\x80\
+\x01\x23\x0b\0\0\x0b\x1b\x2b\x0b\0\0\0\x12\x09\x28\0\0\0\x0d\x03\x91\x80\x01\
+\xbe\x09\0\0\0\x0c\x34\x09\0\0\x06\0\xc1\x09\x11\x09\x44\x09\0\0\x0f\x03\x91\
+\xc8\0\x4c\x09\0\0\x0b\x1f\x54\x09\0\0\x0b\x20\x5c\x09\0\0\x0b\x21\x64\x09\0\0\
+\0\0\0\x13\x53\x0b\0\0\x0a\x10\0\0\0\0\x06\x01\x18\x0f\x01\x56\x5b\x0b\0\0\0\0\
+\x14\x2d\x02\0\0\x15\x36\x02\0\0\x1b\0\x16\x32\x02\0\0\x02\x04\x06\x01\x17\x05\
+\x08\x07\x14\x2d\x02\0\0\x15\x36\x02\0\0\x09\0\x14\x2d\x02\0\0\x15\x36\x02\0\0\
+\x0a\0\x18\x06\x5e\x02\0\0\0\x0d\x01\x02\xa1\x03\x14\x32\x02\0\0\x15\x36\x02\0\
+\0\x0d\0\x19\x07\x75\x02\0\0\0\x1e\x02\xa1\x04\x1a\x20\0\x19\x1b\x08\x9e\x02\0\
+\0\0\x1a\0\x1b\x0a\xb3\x02\0\0\0\x1b\x08\x1b\x0b\xc4\x02\0\0\0\x1c\x10\x1b\x0c\
+\xd5\x02\0\0\0\x1d\x18\0\x1c\xa3\x02\0\0\x14\xaf\x02\0\0\x15\x36\x02\0\0\x01\0\
+\x02\x09\x05\x04\x1c\xb8\x02\0\0\x14\xaf\x02\0\0\x15\x36\x02\0\0\x02\0\x1c\xc9\
+\x02\0\0\x14\xaf\x02\0\0\x15\x36\x02\0\0\x70\0\x1c\xda\x02\0\0\x14\xaf\x02\0\0\
+\x15\x36\x02\0\0\x10\0\x1d\x0d\xee\x02\0\0\x02\xb1\x1c\xf3\x02\0\0\x1e\x04\x03\
+\0\0\x1f\x08\x03\0\0\x1f\x0d\x03\0\0\x20\0\x02\x0e\x05\x08\x1c\x2d\x02\0\0\x21\
+\x15\x03\0\0\x10\x01\x1b\x02\x0f\x07\x04\x1d\x11\x21\x03\0\0\x02\x38\x1c\x26\
+\x03\0\0\x1e\x36\x03\0\0\x1f\x36\x03\0\0\x1f\x37\x03\0\0\0\x22\x1c\x3c\x03\0\0\
+\x23\x24\x12\x46\x03\0\0\x02\x17\x07\x1c\x4b\x03\0\0\x1e\x04\x03\0\0\x1f\x37\
+\x03\0\0\x1f\x0d\x03\0\0\x1f\x36\x03\0\0\x1f\x0d\x03\0\0\x1f\x0d\x03\0\0\0\x25\
+\x15\x03\0\0\x15\x04\x03\x4e\x17\x26\x13\0\x26\x14\x01\0\x27\x15\x03\0\0\x1a\
+\x04\x04\x16\x26\x16\0\x26\x17\x01\x26\x18\x02\x26\x19\x03\0\x28\x15\x03\0\0\
+\x04\x05\x1d\x26\x1b\0\x26\x1c\x01\x26\x1d\x02\x26\x1e\x04\x26\x1f\x06\x26\x20\
+\x08\x26\x21\x0c\x26\x22\x11\x26\x23\x16\x26\x24\x1d\x26\x25\x21\x26\x26\x29\
+\x26\x27\x2e\x26\x28\x2f\x26\x29\x32\x26\x2a\x33\x26\x2b\x5c\x26\x2c\x5e\x26\
+\x2d\x62\x26\x2e\x67\x26\x2f\x6c\x26\x30\x73\x26\x31\x84\x01\x26\x32\x88\x01\
+\x26\x33\x89\x01\x26\x34\x8f\x01\x26\x35\xff\x01\x26\x36\x86\x02\x26\x37\x87\
+\x02\0\x1c\xfd\x03\0\0\x16\x02\x04\0\0\x29\x3f\x1c\0\xdd\x2a\x0f\x04\0\0\0\xde\
+\0\x1a\x08\0\xde\x1b\x38\x15\x03\0\0\0\xdf\0\x1b\x39\x39\x04\0\0\0\xe0\x04\x1b\
+\x3c\x39\x04\0\0\0\xe1\x06\0\x1b\x3d\x45\x04\0\0\0\xe4\x08\0\x21\x41\x04\0\0\
+\x3b\x01\x18\x02\x3a\x07\x02\x14\x51\x04\0\0\x15\x36\x02\0\0\x14\0\x02\x3e\x08\
+\x01\x1c\x5a\x04\0\0\x16\x0d\x03\0\0\x1c\x0d\x03\0\0\x21\x6c\x04\0\0\x41\x01\
+\x1f\x02\x40\x07\x08\x2b\x42\0\xc9\x0d\x03\0\0\x2c\x43\0\xc9\x91\x04\0\0\x2c\
+\x84\0\xc9\xc1\x07\0\0\x2d\x86\0\xcb\x55\x04\0\0\0\x1c\x96\x04\0\0\x16\x9b\x04\
+\0\0\x2e\x83\xc0\x03\x77\x17\x2f\x44\x0d\x03\0\0\x03\x78\x17\0\x2f\x45\x0d\x03\
+\0\0\x03\x79\x17\x04\x2f\x46\x0d\x03\0\0\x03\x7a\x17\x08\x2f\x47\x0d\x03\0\0\
+\x03\x7b\x17\x0c\x2f\x48\x0d\x03\0\0\x03\x7c\x17\x10\x2f\x49\x0d\x03\0\0\x03\
+\x7d\x17\x14\x2f\x4a\x0d\x03\0\0\x03\x7e\x17\x18\x2f\x4b\x0d\x03\0\0\x03\x7f\
+\x17\x1c\x2f\x4c\x0d\x03\0\0\x03\x80\x17\x20\x2f\x4d\x0d\x03\0\0\x03\x81\x17\
+\x24\x2f\x4e\x0d\x03\0\0\x03\x82\x17\x28\x2f\x4f\x0d\x03\0\0\x03\x83\x17\x2c\
+\x2f\x50\x18\x06\0\0\x03\x84\x17\x30\x2f\x51\x0d\x03\0\0\x03\x85\x17\x44\x2f\
+\x3c\x0d\x03\0\0\x03\x86\x17\x48\x2f\x3d\x0d\x03\0\0\x03\x87\x17\x4c\x2f\x52\
+\x0d\x03\0\0\x03\x88\x17\x50\x2f\x53\x0d\x03\0\0\x03\x89\x17\x54\x2f\x54\x0d\
+\x03\0\0\x03\x8c\x17\x58\x2f\x55\x0d\x03\0\0\x03\x8d\x17\x5c\x2f\x56\x0d\x03\0\
+\0\x03\x8e\x17\x60\x2f\x57\x24\x06\0\0\x03\x8f\x17\x64\x2f\x58\x24\x06\0\0\x03\
+\x90\x17\x74\x2f\x59\x0d\x03\0\0\x03\x91\x17\x84\x2f\x5a\x0d\x03\0\0\x03\x92\
+\x17\x88\x2f\x5b\x0d\x03\0\0\x03\x95\x17\x8c\x30\xaf\x05\0\0\x03\x96\x17\x08\
+\x90\x31\x08\x03\x96\x17\x08\x2f\x5c\x30\x06\0\0\x03\x96\x17\0\0\x2f\x71\x64\
+\x04\0\0\x03\x97\x17\x98\x2f\x72\x0d\x03\0\0\x03\x98\x17\xa0\x2f\x73\x0d\x03\0\
+\0\x03\x99\x17\xa4\x30\xe8\x05\0\0\x03\x9a\x17\x08\xa8\x31\x08\x03\x9a\x17\x08\
+\x2f\x74\x21\x07\0\0\x03\x9a\x17\0\0\x2f\x80\x0d\x03\0\0\x03\x9b\x17\xb0\x2f\
+\x81\x09\x07\0\0\x03\x9c\x17\xb4\x2f\x82\x64\x04\0\0\x03\x9e\x17\xb8\0\x14\x0d\
+\x03\0\0\x15\x36\x02\0\0\x05\0\x14\x0d\x03\0\0\x15\x36\x02\0\0\x04\0\x1c\x35\
+\x06\0\0\x2e\x70\x38\x03\x2b\x1b\x2f\x5d\x39\x04\0\0\x03\x2c\x1b\0\x2f\x5e\x39\
+\x04\0\0\x03\x2d\x1b\x02\x2f\x5f\x39\x04\0\0\x03\x2e\x1b\x04\x2f\x60\x09\x07\0\
+\0\x03\x2f\x1b\x06\x2f\x62\x09\x07\0\0\x03\x30\x1b\x07\x2f\x63\x09\x07\0\0\x03\
+\x31\x1b\x08\x2f\x64\x09\x07\0\0\x03\x32\x1b\x09\x2f\x65\x11\x07\0\0\x03\x33\
+\x1b\x0a\x2f\x67\x11\x07\0\0\x03\x34\x1b\x0c\x2f\x68\x11\x07\0\0\x03\x35\x1b\
+\x0e\x32\xa8\x06\0\0\x03\x36\x1b\x10\x33\x20\x03\x36\x1b\x32\xb6\x06\0\0\x03\
+\x37\x1b\0\x34\x08\x03\x37\x1b\x2f\x69\x19\x07\0\0\x03\x38\x1b\0\x2f\x6b\x19\
+\x07\0\0\x03\x39\x1b\x04\0\x32\xd9\x06\0\0\x03\x3b\x1b\0\x34\x20\x03\x3b\x1b\
+\x2f\x6c\x24\x06\0\0\x03\x3c\x1b\0\x2f\x6d\x24\x06\0\0\x03\x3d\x1b\x10\0\0\x2f\
+\x6e\x0d\x03\0\0\x03\x40\x1b\x30\x2f\x6f\x19\x07\0\0\x03\x41\x1b\x34\0\x21\x51\
+\x04\0\0\x61\x01\x15\x21\x39\x04\0\0\x66\x06\x20\x21\x0d\x03\0\0\x6a\x06\x22\
+\x1c\x26\x07\0\0\x2e\x7f\x50\x03\xdf\x17\x2f\x75\x0d\x03\0\0\x03\xe0\x17\0\x2f\
+\x54\x0d\x03\0\0\x03\xe1\x17\x04\x2f\x08\x0d\x03\0\0\x03\xe2\x17\x08\x2f\x48\
+\x0d\x03\0\0\x03\xe3\x17\x0c\x2f\x46\x0d\x03\0\0\x03\xe4\x17\x10\x2f\x4c\x0d\
+\x03\0\0\x03\xe5\x17\x14\x2f\x76\x0d\x03\0\0\x03\xe7\x17\x18\x2f\x77\x24\x06\0\
+\0\x03\xe8\x17\x1c\x2f\x78\x0d\x03\0\0\x03\xe9\x17\x2c\x2f\x79\x11\x07\0\0\x03\
+\xea\x17\x30\x2f\x7a\x0d\x03\0\0\x03\xec\x17\x34\x2f\x7b\x24\x06\0\0\x03\xed\
+\x17\x38\x2f\x7c\x0d\x03\0\0\x03\xee\x17\x48\x2f\x7d\xb9\x07\0\0\x03\xef\x17\
+\x4c\0\x21\xaf\x02\0\0\x7e\x01\x1a\x1c\xc6\x07\0\0\x16\xcb\x07\0\0\x29\x89\x70\
+\x04\x1d\x1b\x85\x0d\x03\0\0\x04\x1e\0\x1b\x86\xf5\x07\0\0\x04\x1f\x04\x1b\x87\
+\x0d\x03\0\0\x04\x20\x2c\x1b\x88\x01\x08\0\0\x04\x21\x30\0\x14\x09\x07\0\0\x15\
+\x36\x02\0\0\x28\0\x14\x0d\x03\0\0\x15\x36\x02\0\0\x10\0\x2b\x8a\0\x42\x0d\x03\
+\0\0\x2c\x43\0\x42\x91\x04\0\0\x2c\x8b\0\x42\x0d\x03\0\0\x2c\x86\0\x42\x55\x04\
+\0\0\x2d\x8c\0\x44\x50\x08\0\0\x2d\x9a\0\x45\x0d\x03\0\0\x2d\x9b\0\x4f\xfe\x08\
+\0\0\x35\x2d\x9e\0\x5d\x28\x09\0\0\0\0\x29\x99\x14\x07\x57\x36\x8d\x09\x07\0\0\
+\x07\x59\x04\0\x36\x8e\x09\x07\0\0\x07\x5a\x04\x04\x1b\x8f\x09\x07\0\0\x07\x61\
+\x01\x1b\x90\x11\x07\0\0\x07\x62\x02\x1b\x91\x11\x07\0\0\x07\x63\x04\x1b\x92\
+\x11\x07\0\0\x07\x64\x06\x1b\x93\x09\x07\0\0\x07\x65\x08\x1b\x48\x09\x07\0\0\
+\x07\x66\x09\x1b\x94\xf5\x08\0\0\x07\x67\x0a\x2a\xb0\x08\0\0\x07\x68\x0c\x37\
+\x08\x07\x68\x2a\xbc\x08\0\0\x07\x68\0\x1a\x08\x07\x68\x1b\x96\x19\x07\0\0\x07\
+\x68\0\x1b\x97\x19\x07\0\0\x07\x68\x04\0\x1b\x98\xdc\x08\0\0\x07\x68\0\x1a\x08\
+\x07\x68\x1b\x96\x19\x07\0\0\x07\x68\0\x1b\x97\x19\x07\0\0\x07\x68\x04\0\0\0\
+\x21\x39\x04\0\0\x95\x06\x26\x38\x1a\x0c\0\x4a\x1b\x9c\x0d\x03\0\0\0\x4b\0\x1b\
+\x9d\x0d\x03\0\0\0\x4c\x04\x1b\x68\x39\x04\0\0\0\x4d\x08\x1b\x67\x39\x04\0\0\0\
+\x4e\x0a\0\0\x14\x39\x04\0\0\x15\x36\x02\0\0\x02\0\x2b\x9f\0\x26\x0d\x03\0\0\
+\x2c\xa0\0\x26\x55\x04\0\0\x2c\xa1\0\x26\x0d\x03\0\0\x2c\x86\0\x26\x55\x04\0\0\
+\x2d\xa2\0\x28\x0d\x03\0\0\x2d\xa3\0\x28\x0d\x03\0\0\x2d\x51\0\x28\x0d\x03\0\0\
+\0\x2b\xa4\0\x97\x0d\x03\0\0\x2c\x43\0\x97\x91\x04\0\0\x2c\x8b\0\x97\x0d\x03\0\
+\0\x2c\x86\0\x97\x55\x04\0\0\x2d\xa5\0\x9f\xc8\x09\0\0\x2d\x9a\0\xa0\x0d\x03\0\
+\0\x2d\xb0\0\x9e\xb2\x0a\0\0\x2d\xa3\0\xa0\x0d\x03\0\0\x2d\xb1\0\xa1\xaf\x02\0\
+\0\x2d\xb2\0\xa1\xaf\x02\0\0\x35\x2d\x9e\0\xb7\x28\x09\0\0\0\0\x29\xaf\x28\x08\
+\x76\x36\x4c\x09\x07\0\0\x08\x78\x04\0\x36\x8e\x09\x07\0\0\x08\x79\x04\x04\x1b\
+\xa6\x52\x0a\0\0\x08\x80\x01\x1b\xa7\x11\x07\0\0\x08\x82\x04\x1b\xa8\x09\x07\0\
+\0\x08\x83\x06\x1b\xa9\x09\x07\0\0\x08\x84\x07\x2a\x0d\x0a\0\0\x08\x86\x08\x37\
+\x20\x08\x86\x2a\x19\x0a\0\0\x08\x86\0\x1a\x20\x08\x86\x1b\x96\x5e\x0a\0\0\x08\
+\x86\0\x1b\x97\x5e\x0a\0\0\x08\x86\x10\0\x1b\x98\x39\x0a\0\0\x08\x86\0\x1a\x20\
+\x08\x86\x1b\x96\x5e\x0a\0\0\x08\x86\0\x1b\x97\x5e\x0a\0\0\x08\x86\x10\0\0\0\
+\x14\x09\x07\0\0\x15\x36\x02\0\0\x03\0\x29\xae\x10\x09\x21\x1b\xaa\x6c\x0a\0\0\
+\x09\x28\0\x37\x10\x09\x22\x1b\xab\x8d\x0a\0\0\x09\x23\0\x1b\xac\x99\x0a\0\0\
+\x09\x25\0\x1b\xad\xa5\x0a\0\0\x09\x26\0\0\0\x14\x09\x07\0\0\x15\x36\x02\0\0\
+\x10\0\x14\x11\x07\0\0\x15\x36\x02\0\0\x08\0\x14\x19\x07\0\0\x15\x36\x02\0\0\
+\x04\0\x38\x1a\x24\0\x99\x1b\x9c\x24\x06\0\0\0\x9a\0\x1b\x9d\x24\x06\0\0\0\x9b\
+\x10\x1b\x68\x39\x04\0\0\0\x9c\x20\x1b\x67\x39\x04\0\0\0\x9d\x22\0\0\x2b\xb3\0\
+\x39\xed\x0a\0\0\x2c\x8c\0\x39\xf1\x0a\0\0\0\x02\xb4\x02\x01\x1c\xf6\x0a\0\0\
+\x16\x50\x08\0\0\x2b\xb5\0\x6e\xaf\x02\0\0\x2c\xb1\0\x6e\x39\x04\0\0\x2c\x43\0\
+\x6e\x91\x04\0\0\x2c\x9a\0\x6e\x5f\x04\0\0\x2c\xb2\0\x6e\x34\x0b\0\0\x2d\xb6\0\
+\x73\x3a\x0b\0\0\x2d\xa2\0\x74\x15\x03\0\0\0\x1c\xaf\x02\0\0\x38\x29\xb8\x02\0\
+\x70\x1b\xb7\x09\x07\0\0\0\x71\0\x1b\x44\x09\x07\0\0\0\x72\x01\0\0\x2b\xb9\0\
+\xd7\x0d\x03\0\0\x2c\xba\0\xd7\x0d\x03\0\0\x2c\xbb\0\xd7\x0d\x03\0\0\0\x14\x32\
+\x02\0\0\x15\x36\x02\0\0\x1c\0\x1c\x9b\x04\0\0\0\xc9\0\0\0\x05\0\x08\0\x07\0\0\
+\0\x1c\0\0\0\x28\0\0\0\x3a\0\0\0\x57\0\0\0\x7b\0\0\0\x8e\0\0\0\x9d\0\0\0\x04\
+\xf8\x01\xa0\x02\x04\xe8\x02\xc8\xeb\x03\0\x04\xc0\x03\xe0\x03\x04\x90\x04\xf8\
+\x30\x04\xb0\xdf\x01\xf0\xa0\x02\0\x04\xe0\xdf\x01\xc8\x88\x02\x04\xd0\x88\x02\
+\xa8\x89\x02\x04\xb8\x89\x02\x90\x8a\x02\x04\x98\x8a\x02\xf0\xa0\x02\0\x04\xd0\
+\xe0\x01\xc8\x88\x02\x04\xd0\x88\x02\xa8\x89\x02\x04\xb8\x89\x02\x90\x8a\x02\
+\x04\x98\x8a\x02\xf0\x8a\x02\x04\xf8\x8a\x02\xf0\xa0\x02\0\x04\xe0\x31\x80\x32\
+\x04\xb0\x32\xf8\xde\x01\x04\x88\xa1\x02\xc8\xeb\x03\0\x04\x98\xa1\x02\xb0\xa1\
+\x02\x04\xf8\xe4\x03\xc8\xeb\x03\0\x04\x98\xa2\x02\xe0\xcc\x03\x04\xe8\xcc\x03\
+\xc0\xcd\x03\x04\xd0\xcd\x03\xa8\xce\x03\x04\xb0\xce\x03\x88\xcf\x03\x04\x90\
+\xcf\x03\xf8\xe4\x03\0\x0c\x03\0\0\x05\0\0\0\0\0\0\0\x21\0\0\0\x2b\0\0\0\x5f\0\
+\0\0\x67\0\0\0\x6c\0\0\0\x80\0\0\0\x89\0\0\0\x91\0\0\0\x96\0\0\0\x9a\0\0\0\xa3\
+\0\0\0\xae\0\0\0\xba\0\0\0\xcb\0\0\0\xd0\0\0\0\xdd\0\0\0\xe3\0\0\0\xf7\0\0\0\
+\x13\x01\0\0\x25\x01\0\0\x37\x01\0\0\x49\x01\0\0\x5c\x01\0\0\x72\x01\0\0\x85\
+\x01\0\0\x9b\x01\0\0\xa6\x01\0\0\xb1\x01\0\0\xbe\x01\0\0\xcb\x01\0\0\xd8\x01\0\
+\0\xe4\x01\0\0\xf0\x01\0\0\xfc\x01\0\0\x08\x02\0\0\x14\x02\0\0\x1f\x02\0\0\x2c\
+\x02\0\0\x39\x02\0\0\x46\x02\0\0\x52\x02\0\0\x5e\x02\0\0\x69\x02\0\0\x75\x02\0\
+\0\x84\x02\0\0\x92\x02\0\0\x9e\x02\0\0\xab\x02\0\0\xb8\x02\0\0\xc5\x02\0\0\xd5\
+\x02\0\0\xe2\x02\0\0\xf3\x02\0\0\xff\x02\0\0\x0d\x03\0\0\x19\x03\0\0\x21\x03\0\
+\0\x39\x03\0\0\x48\x03\0\0\x4e\x03\0\0\x59\x03\0\0\x5e\x03\0\0\x6c\x03\0\0\x79\
+\x03\0\0\x8c\x03\0\0\x92\x03\0\0\xa5\x03\0\0\xa9\x03\0\0\xad\x03\0\0\xb6\x03\0\
+\0\xbb\x03\0\0\xc9\x03\0\0\xd2\x03\0\0\xdf\x03\0\0\xe8\x03\0\0\xf3\x03\0\0\xfc\
+\x03\0\0\x0c\x04\0\0\x14\x04\0\0\x1d\x04\0\0\x20\x04\0\0\x25\x04\0\0\x2e\x04\0\
+\0\x36\x04\0\0\x3d\x04\0\0\x48\x04\0\0\x52\x04\0\0\x5d\x04\0\0\x67\x04\0\0\x73\
+\x04\0\0\x7e\x04\0\0\x88\x04\0\0\x92\x04\0\0\x98\x04\0\0\x9e\x04\0\0\xa9\x04\0\
+\0\xb1\x04\0\0\xb6\x04\0\0\xc4\x04\0\0\xcd\x04\0\0\xd6\x04\0\0\xde\x04\0\0\xe5\
+\x04\0\0\xeb\x04\0\0\xf1\x04\0\0\xfa\x04\0\0\x01\x05\0\0\x0a\x05\0\0\x13\x05\0\
+\0\x1c\x05\0\0\x22\x05\0\0\x2d\x05\0\0\x3b\x05\0\0\x42\x05\0\0\x4b\x05\0\0\x54\
+\x05\0\0\x57\x05\0\0\x64\x05\0\0\x6c\x05\0\0\x74\x05\0\0\x7d\x05\0\0\x86\x05\0\
+\0\x8e\x05\0\0\x96\x05\0\0\x9c\x05\0\0\xad\x05\0\0\xb3\x05\0\0\xbc\x05\0\0\xc5\
+\x05\0\0\xd1\x05\0\0\xda\x05\0\0\xe4\x05\0\0\xeb\x05\0\0\xf7\x05\0\0\xfb\x05\0\
+\0\x05\x06\0\0\x0c\x06\0\0\x14\x06\0\0\x1f\x06\0\0\x29\x06\0\0\x2d\x06\0\0\x31\
+\x06\0\0\x39\x06\0\0\x3d\x06\0\0\x45\x06\0\0\x48\x06\0\0\x51\x06\0\0\x55\x06\0\
+\0\x5b\x06\0\0\x63\x06\0\0\x69\x06\0\0\x6f\x06\0\0\x75\x06\0\0\x7b\x06\0\0\x7f\
+\x06\0\0\x88\x06\0\0\x91\x06\0\0\x9a\x06\0\0\xa7\x06\0\0\xb2\x06\0\0\xbe\x06\0\
+\0\xc8\x06\0\0\xca\x06\0\0\xcc\x06\0\0\xd7\x06\0\0\xdc\x06\0\0\xe5\x06\0\0\xf1\
+\x06\0\0\xf9\x06\0\0\x03\x07\0\0\x09\x07\0\0\x12\x07\0\0\x1c\x07\0\0\x26\x07\0\
+\0\x2f\x07\0\0\x37\x07\0\0\x40\x07\0\0\x46\x07\0\0\x4b\x07\0\0\x5c\x07\0\0\x62\
+\x07\0\0\x6f\x07\0\0\x72\x07\0\0\x7b\x07\0\0\x83\x07\0\0\x94\x07\0\0\x98\x07\0\
+\0\x9a\x07\0\0\xad\x07\0\0\xc0\x07\0\0\xd2\x07\0\0\xe2\x07\0\0\xe6\x07\0\0\x44\
+\x65\x62\x69\x61\x6e\x20\x63\x6c\x61\x6e\x67\x20\x76\x65\x72\x73\x69\x6f\x6e\
+\x20\x31\x36\x2e\x30\x2e\x36\x20\x28\x31\x39\x29\0\x74\x61\x70\x5f\x72\x73\x73\
+\x2e\x63\0\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x65\x6d\x6d\x69\x6e\x67\x65\x72\x2f\
+\x44\x50\x44\x4b\x2f\x74\x61\x70\x2f\x66\x69\x78\x69\x74\x2f\x64\x72\x69\x76\
+\x65\x72\x73\x2f\x6e\x65\x74\x2f\x74\x61\x70\x2f\x62\x70\x66\0\x5f\x5f\x5f\x5f\
+\x66\x6d\x74\0\x63\x68\x61\x72\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\
+\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x72\x73\
+\x73\x5f\x6d\x61\x70\0\x74\x79\x70\x65\0\x69\x6e\x74\0\x6b\x65\x79\x5f\x73\x69\
+\x7a\x65\0\x76\x61\x6c\x75\x65\x5f\x73\x69\x7a\x65\0\x6d\x61\x78\x5f\x65\x6e\
+\x74\x72\x69\x65\x73\0\x62\x70\x66\x5f\x74\x72\x61\x63\x65\x5f\x70\x72\x69\x6e\
+\x74\x6b\0\x6c\x6f\x6e\x67\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\
+\x5f\x5f\x75\x33\x32\0\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\
+\x5f\x65\x6c\x65\x6d\0\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\
+\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\0\x42\x50\x46\x5f\x48\x44\
+\x52\x5f\x53\x54\x41\x52\x54\x5f\x4d\x41\x43\0\x42\x50\x46\x5f\x48\x44\x52\x5f\
+\x53\x54\x41\x52\x54\x5f\x4e\x45\x54\0\x62\x70\x66\x5f\x68\x64\x72\x5f\x73\x74\
+\x61\x72\x74\x5f\x6f\x66\x66\0\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\x49\
+\x50\x56\x34\x5f\x4c\x33\0\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\x49\x50\
+\x56\x34\x5f\x4c\x33\x5f\x4c\x34\0\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\
+\x49\x50\x56\x36\x5f\x4c\x33\0\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\x49\
+\x50\x56\x36\x5f\x4c\x33\x5f\x4c\x34\0\x68\x61\x73\x68\x5f\x66\x69\x65\x6c\x64\
+\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x49\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\
+\x49\x43\x4d\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x49\x47\x4d\x50\0\x49\x50\
+\x50\x52\x4f\x54\x4f\x5f\x49\x50\x49\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x54\
+\x43\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x45\x47\x50\0\x49\x50\x50\x52\x4f\
+\x54\x4f\x5f\x50\x55\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x55\x44\x50\0\x49\
+\x50\x50\x52\x4f\x54\x4f\x5f\x49\x44\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x54\
+\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x44\x43\x43\x50\0\x49\x50\x50\x52\x4f\
+\x54\x4f\x5f\x49\x50\x56\x36\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x52\x53\x56\x50\
+\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x47\x52\x45\0\x49\x50\x50\x52\x4f\x54\x4f\
+\x5f\x45\x53\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x41\x48\0\x49\x50\x50\x52\
+\x4f\x54\x4f\x5f\x4d\x54\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x42\x45\x45\x54\
+\x50\x48\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x45\x4e\x43\x41\x50\0\x49\x50\x50\
+\x52\x4f\x54\x4f\x5f\x50\x49\x4d\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x43\x4f\x4d\
+\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x4c\x32\x54\x50\0\x49\x50\x50\x52\x4f\
+\x54\x4f\x5f\x53\x43\x54\x50\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x55\x44\x50\x4c\
+\x49\x54\x45\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x4d\x50\x4c\x53\0\x49\x50\x50\
+\x52\x4f\x54\x4f\x5f\x45\x54\x48\x45\x52\x4e\x45\x54\0\x49\x50\x50\x52\x4f\x54\
+\x4f\x5f\x52\x41\x57\0\x49\x50\x50\x52\x4f\x54\x4f\x5f\x4d\x50\x54\x43\x50\0\
+\x49\x50\x50\x52\x4f\x54\x4f\x5f\x4d\x41\x58\0\x70\x6b\x74\x5f\x6c\x65\x6e\0\
+\x73\x6c\x61\x76\x65\x5f\x64\x65\x76\x5f\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\
+\x70\x69\x6e\x67\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x73\x68\x6f\x72\x74\0\
+\x5f\x5f\x75\x31\x36\0\x74\x63\x5f\x63\x6c\x61\x73\x73\x69\x64\0\x64\x61\x74\
+\x61\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x63\x68\x61\x72\0\x71\x64\x69\x73\
+\x63\x5f\x73\x6b\x62\x5f\x63\x62\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\
+\x6e\x67\x20\x6c\x6f\x6e\x67\0\x5f\x5f\x75\x36\x34\0\x63\x61\x6c\x63\x75\x6c\
+\x61\x74\x65\x5f\x72\x73\x73\x5f\x68\x61\x73\x68\0\x73\x6b\x62\0\x6c\x65\x6e\0\
+\x70\x6b\x74\x5f\x74\x79\x70\x65\0\x6d\x61\x72\x6b\0\x71\x75\x65\x75\x65\x5f\
+\x6d\x61\x70\x70\x69\x6e\x67\0\x70\x72\x6f\x74\x6f\x63\x6f\x6c\0\x76\x6c\x61\
+\x6e\x5f\x70\x72\x65\x73\x65\x6e\x74\0\x76\x6c\x61\x6e\x5f\x74\x63\x69\0\x76\
+\x6c\x61\x6e\x5f\x70\x72\x6f\x74\x6f\0\x70\x72\x69\x6f\x72\x69\x74\x79\0\x69\
+\x6e\x67\x72\x65\x73\x73\x5f\x69\x66\x69\x6e\x64\x65\x78\0\x69\x66\x69\x6e\x64\
+\x65\x78\0\x74\x63\x5f\x69\x6e\x64\x65\x78\0\x63\x62\0\x68\x61\x73\x68\0\x64\
+\x61\x74\x61\x5f\x65\x6e\x64\0\x6e\x61\x70\x69\x5f\x69\x64\0\x66\x61\x6d\x69\
+\x6c\x79\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x34\0\x6c\x6f\x63\x61\x6c\x5f\
+\x69\x70\x34\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x36\0\x6c\x6f\x63\x61\x6c\
+\x5f\x69\x70\x36\0\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\0\x6c\x6f\x63\
+\x61\x6c\x5f\x70\x6f\x72\x74\0\x64\x61\x74\x61\x5f\x6d\x65\x74\x61\0\x66\x6c\
+\x6f\x77\x5f\x6b\x65\x79\x73\0\x6e\x68\x6f\x66\x66\0\x74\x68\x6f\x66\x66\0\x61\
+\x64\x64\x72\x5f\x70\x72\x6f\x74\x6f\0\x69\x73\x5f\x66\x72\x61\x67\0\x5f\x5f\
+\x75\x38\0\x69\x73\x5f\x66\x69\x72\x73\x74\x5f\x66\x72\x61\x67\0\x69\x73\x5f\
+\x65\x6e\x63\x61\x70\0\x69\x70\x5f\x70\x72\x6f\x74\x6f\0\x6e\x5f\x70\x72\x6f\
+\x74\x6f\0\x5f\x5f\x62\x65\x31\x36\0\x73\x70\x6f\x72\x74\0\x64\x70\x6f\x72\x74\
+\0\x69\x70\x76\x34\x5f\x73\x72\x63\0\x5f\x5f\x62\x65\x33\x32\0\x69\x70\x76\x34\
+\x5f\x64\x73\x74\0\x69\x70\x76\x36\x5f\x73\x72\x63\0\x69\x70\x76\x36\x5f\x64\
+\x73\x74\0\x66\x6c\x61\x67\x73\0\x66\x6c\x6f\x77\x5f\x6c\x61\x62\x65\x6c\0\x62\
+\x70\x66\x5f\x66\x6c\x6f\x77\x5f\x6b\x65\x79\x73\0\x74\x73\x74\x61\x6d\x70\0\
+\x77\x69\x72\x65\x5f\x6c\x65\x6e\0\x67\x73\x6f\x5f\x73\x65\x67\x73\0\x73\x6b\0\
+\x62\x6f\x75\x6e\x64\x5f\x64\x65\x76\x5f\x69\x66\0\x73\x72\x63\x5f\x69\x70\x34\
+\0\x73\x72\x63\x5f\x69\x70\x36\0\x73\x72\x63\x5f\x70\x6f\x72\x74\0\x64\x73\x74\
+\x5f\x70\x6f\x72\x74\0\x64\x73\x74\x5f\x69\x70\x34\0\x64\x73\x74\x5f\x69\x70\
+\x36\0\x73\x74\x61\x74\x65\0\x72\x78\x5f\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\
+\x70\x69\x6e\x67\0\x5f\x5f\x73\x33\x32\0\x62\x70\x66\x5f\x73\x6f\x63\x6b\0\x67\
+\x73\x6f\x5f\x73\x69\x7a\x65\0\x74\x73\x74\x61\x6d\x70\x5f\x74\x79\x70\x65\0\
+\x68\x77\x74\x73\x74\x61\x6d\x70\0\x5f\x5f\x73\x6b\x5f\x62\x75\x66\x66\0\x72\
+\x73\x73\x6b\x65\x79\0\x68\x61\x73\x68\x5f\x66\x69\x65\x6c\x64\x73\0\x6b\x65\
+\x79\0\x6e\x62\x5f\x71\x75\x65\x75\x65\x73\0\x71\x75\x65\x75\x65\x73\0\x72\x73\
+\x73\x5f\x6b\x65\x79\0\x70\x61\x72\x73\x65\x5f\x69\x70\x76\x34\0\x68\x61\x73\
+\x68\x5f\x74\x79\x70\x65\0\x69\x70\x68\0\x69\x68\x6c\0\x76\x65\x72\x73\x69\x6f\
+\x6e\0\x74\x6f\x73\0\x74\x6f\x74\x5f\x6c\x65\x6e\0\x69\x64\0\x66\x72\x61\x67\
+\x5f\x6f\x66\x66\0\x74\x74\x6c\0\x63\x68\x65\x63\x6b\0\x5f\x5f\x73\x75\x6d\x31\
+\x36\0\x73\x61\x64\x64\x72\0\x64\x61\x64\x64\x72\0\x61\x64\x64\x72\x73\0\x69\
+\x70\x68\x64\x72\0\x6f\x66\x66\0\x76\x34\x5f\x74\x75\x70\x6c\x65\0\x73\x72\x63\
+\x5f\x61\x64\x64\x72\0\x64\x73\x74\x5f\x61\x64\x64\x72\0\x73\x72\x63\x5f\x64\
+\x73\x74\x5f\x70\x6f\x72\x74\0\x73\x6f\x66\x74\x72\x73\x73\x5f\x62\x65\0\x69\
+\x6e\x70\x75\x74\x5f\x74\x75\x70\x6c\x65\0\x69\x6e\x70\x75\x74\x5f\x6c\x65\x6e\
+\0\x69\0\x6a\0\x70\x61\x72\x73\x65\x5f\x69\x70\x76\x36\0\x69\x70\x36\x68\0\x66\
+\x6c\x6f\x77\x5f\x6c\x62\x6c\0\x70\x61\x79\x6c\x6f\x61\x64\x5f\x6c\x65\x6e\0\
+\x6e\x65\x78\x74\x68\x64\x72\0\x68\x6f\x70\x5f\x6c\x69\x6d\x69\x74\0\x69\x6e\
+\x36\x5f\x75\0\x75\x36\x5f\x61\x64\x64\x72\x38\0\x75\x36\x5f\x61\x64\x64\x72\
+\x31\x36\0\x75\x36\x5f\x61\x64\x64\x72\x33\x32\0\x69\x6e\x36\x5f\x61\x64\x64\
+\x72\0\x69\x70\x76\x36\x68\x64\x72\0\x76\x36\x5f\x74\x75\x70\x6c\x65\0\x70\x72\
+\x6f\x74\x6f\0\x66\x72\x61\x67\0\x69\x73\x5f\x69\x70\x76\x34\x5f\x66\x72\x61\
+\x67\x6d\x65\x6e\x74\0\x5f\x42\x6f\x6f\x6c\0\x73\x6b\x69\x70\x5f\x69\x70\x36\
+\x5f\x65\x78\x74\0\x78\x68\0\x6e\x65\x78\x74\x5f\x68\x64\x72\0\x65\x78\x74\x5f\
+\x68\x64\x72\0\x72\x65\x63\x69\x70\x72\x6f\x63\x61\x6c\x5f\x73\x63\x61\x6c\x65\
+\0\x76\x61\x6c\0\x6e\0\x44\x57\x5f\x41\x54\x45\x5f\x75\x6e\x73\x69\x67\x6e\x65\
+\x64\x5f\x33\x32\0\x44\x57\x5f\x41\x54\x45\x5f\x75\x6e\x73\x69\x67\x6e\x65\x64\
+\x5f\x31\x36\0\x44\x57\x5f\x41\x54\x45\x5f\x75\x6e\x73\x69\x67\x6e\x65\x64\x5f\
+\x38\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\0\x66\x6d\
+\x74\0\x63\x6c\x61\x73\x73\x69\x64\0\x5c\0\0\0\x05\0\x08\0\0\0\0\0\0\0\0\0\x1b\
+\0\0\0\0\0\0\0\x24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x60\x02\0\0\0\0\0\0\xb0\x6f\0\0\0\0\0\0\xf8\x19\0\0\0\0\0\0\xd8\x90\0\0\0\0\
+\0\0\x70\xf6\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\x18\0\0\0\0\0\0\0\xcc\x04\0\0\xcc\
+\x04\0\0\xda\x09\0\0\0\0\0\0\0\0\0\x02\x03\0\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\
+\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x01\0\0\0\x05\0\0\0\
+\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\
+\0\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\
+\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x70\0\0\0\0\0\0\0\0\0\0\x02\x0a\0\0\0\0\0\0\0\
+\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x10\0\0\0\0\0\0\0\x04\0\0\x04\x20\0\0\0\
+\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x27\0\0\0\x07\0\0\0\
+\x80\0\0\0\x32\0\0\0\x09\0\0\0\xc0\0\0\0\x3e\0\0\0\0\0\0\x0e\x0b\0\0\0\x01\0\0\
+\0\0\0\0\0\0\0\0\x02\x0e\0\0\0\x46\0\0\0\x22\0\0\x04\xc0\0\0\0\x50\0\0\0\x0f\0\
+\0\0\0\0\0\0\x54\0\0\0\x0f\0\0\0\x20\0\0\0\x5d\0\0\0\x0f\0\0\0\x40\0\0\0\x62\0\
+\0\0\x0f\0\0\0\x60\0\0\0\x70\0\0\0\x0f\0\0\0\x80\0\0\0\x79\0\0\0\x0f\0\0\0\xa0\
+\0\0\0\x86\0\0\0\x0f\0\0\0\xc0\0\0\0\x8f\0\0\0\x0f\0\0\0\xe0\0\0\0\x9a\0\0\0\
+\x0f\0\0\0\0\x01\0\0\xa3\0\0\0\x0f\0\0\0\x20\x01\0\0\xb3\0\0\0\x0f\0\0\0\x40\
+\x01\0\0\xbb\0\0\0\x0f\0\0\0\x60\x01\0\0\xc4\0\0\0\x11\0\0\0\x80\x01\0\0\xc7\0\
+\0\0\x0f\0\0\0\x20\x02\0\0\xcc\0\0\0\x0f\0\0\0\x40\x02\0\0\xd7\0\0\0\x0f\0\0\0\
+\x60\x02\0\0\xdc\0\0\0\x0f\0\0\0\x80\x02\0\0\xe5\0\0\0\x0f\0\0\0\xa0\x02\0\0\
+\xed\0\0\0\x0f\0\0\0\xc0\x02\0\0\xf4\0\0\0\x0f\0\0\0\xe0\x02\0\0\xff\0\0\0\x0f\
+\0\0\0\0\x03\0\0\x09\x01\0\0\x12\0\0\0\x20\x03\0\0\x14\x01\0\0\x12\0\0\0\xa0\
+\x03\0\0\x1e\x01\0\0\x0f\0\0\0\x20\x04\0\0\x2a\x01\0\0\x0f\0\0\0\x40\x04\0\0\
+\x35\x01\0\0\x0f\0\0\0\x60\x04\0\0\0\0\0\0\x13\0\0\0\x80\x04\0\0\x3f\x01\0\0\
+\x15\0\0\0\xc0\x04\0\0\x46\x01\0\0\x0f\0\0\0\0\x05\0\0\x4f\x01\0\0\x0f\0\0\0\
+\x20\x05\0\0\0\0\0\0\x17\0\0\0\x40\x05\0\0\x58\x01\0\0\x0f\0\0\0\x80\x05\0\0\
+\x61\x01\0\0\x19\0\0\0\xa0\x05\0\0\x6d\x01\0\0\x15\0\0\0\xc0\x05\0\0\x76\x01\0\
+\0\0\0\0\x08\x10\0\0\0\x7c\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
+\x03\0\0\0\0\x0f\0\0\0\x04\0\0\0\x05\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x0f\0\0\0\
+\x04\0\0\0\x04\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\0\0\x89\x01\0\0\x14\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x02\x2a\0\0\0\x93\x01\0\0\0\0\0\x08\x16\0\0\0\x99\x01\0\0\0\0\
+\0\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\0\0\xac\x01\0\0\x18\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x02\x2b\0\0\0\xaf\x01\0\0\0\0\0\x08\x1a\0\0\0\xb4\x01\0\
+\0\0\0\0\x01\x01\0\0\0\x08\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\xc2\x01\0\0\x0d\
+\0\0\0\xc6\x01\0\0\x01\0\0\x0c\x1b\0\0\0\0\0\0\0\0\0\0\x0a\x1e\0\0\0\x53\x09\0\
+\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x1d\0\0\0\x04\0\0\
+\0\x1b\0\0\0\x58\x09\0\0\0\0\0\x0e\x1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\
+\x1d\0\0\0\x04\0\0\0\x09\0\0\0\x70\x09\0\0\0\0\0\x0e\x21\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x03\0\0\0\0\x1d\0\0\0\x04\0\0\0\x0a\0\0\0\x8a\x09\0\0\0\0\0\x0e\x23\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1e\0\0\0\x04\0\0\0\x0d\0\0\0\xa4\x09\0\0\
+\0\0\0\x0e\x25\0\0\0\x01\0\0\0\xad\x09\0\0\x01\0\0\x0f\0\0\0\0\x0c\0\0\0\0\0\0\
+\0\x20\0\0\0\xb3\x09\0\0\x03\0\0\x0f\0\0\0\0\x20\0\0\0\0\0\0\0\x1b\0\0\0\x22\0\
+\0\0\x1b\0\0\0\x09\0\0\0\x24\0\0\0\x24\0\0\0\x0a\0\0\0\xbb\x09\0\0\x01\0\0\x0f\
+\0\0\0\0\x26\0\0\0\0\0\0\0\x0d\0\0\0\xc3\x09\0\0\0\0\0\x07\0\0\0\0\xd1\x09\0\0\
+\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\
+\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6b\x65\x79\x5f\x73\x69\
+\x7a\x65\0\x76\x61\x6c\x75\x65\x5f\x73\x69\x7a\x65\0\x6d\x61\x78\x5f\x65\x6e\
+\x74\x72\x69\x65\x73\0\x72\x73\x73\x5f\x6d\x61\x70\0\x5f\x5f\x73\x6b\x5f\x62\
+\x75\x66\x66\0\x6c\x65\x6e\0\x70\x6b\x74\x5f\x74\x79\x70\x65\0\x6d\x61\x72\x6b\
+\0\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\x70\x69\x6e\x67\0\x70\x72\x6f\x74\x6f\
+\x63\x6f\x6c\0\x76\x6c\x61\x6e\x5f\x70\x72\x65\x73\x65\x6e\x74\0\x76\x6c\x61\
+\x6e\x5f\x74\x63\x69\0\x76\x6c\x61\x6e\x5f\x70\x72\x6f\x74\x6f\0\x70\x72\x69\
+\x6f\x72\x69\x74\x79\0\x69\x6e\x67\x72\x65\x73\x73\x5f\x69\x66\x69\x6e\x64\x65\
+\x78\0\x69\x66\x69\x6e\x64\x65\x78\0\x74\x63\x5f\x69\x6e\x64\x65\x78\0\x63\x62\
+\0\x68\x61\x73\x68\0\x74\x63\x5f\x63\x6c\x61\x73\x73\x69\x64\0\x64\x61\x74\x61\
+\0\x64\x61\x74\x61\x5f\x65\x6e\x64\0\x6e\x61\x70\x69\x5f\x69\x64\0\x66\x61\x6d\
+\x69\x6c\x79\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x34\0\x6c\x6f\x63\x61\x6c\
+\x5f\x69\x70\x34\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x36\0\x6c\x6f\x63\x61\
+\x6c\x5f\x69\x70\x36\0\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\0\x6c\x6f\
+\x63\x61\x6c\x5f\x70\x6f\x72\x74\0\x64\x61\x74\x61\x5f\x6d\x65\x74\x61\0\x74\
+\x73\x74\x61\x6d\x70\0\x77\x69\x72\x65\x5f\x6c\x65\x6e\0\x67\x73\x6f\x5f\x73\
+\x65\x67\x73\0\x67\x73\x6f\x5f\x73\x69\x7a\x65\0\x74\x73\x74\x61\x6d\x70\x5f\
+\x74\x79\x70\x65\0\x68\x77\x74\x73\x74\x61\x6d\x70\0\x5f\x5f\x75\x33\x32\0\x75\
+\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\x66\x6c\x6f\x77\x5f\x6b\x65\x79\
+\x73\0\x5f\x5f\x75\x36\x34\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\
+\x67\x20\x6c\x6f\x6e\x67\0\x73\x6b\0\x5f\x5f\x75\x38\0\x75\x6e\x73\x69\x67\x6e\
+\x65\x64\x20\x63\x68\x61\x72\0\x73\x6b\x62\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\
+\x5f\x61\x63\x74\x69\x6f\x6e\0\x74\x63\x2f\x69\x6e\x67\x72\x65\x73\x73\0\x2f\
+\x68\x6f\x6d\x65\x2f\x73\x68\x65\x6d\x6d\x69\x6e\x67\x65\x72\x2f\x44\x50\x44\
+\x4b\x2f\x74\x61\x70\x2f\x66\x69\x78\x69\x74\x2f\x64\x72\x69\x76\x65\x72\x73\
+\x2f\x6e\x65\x74\x2f\x74\x61\x70\x2f\x62\x70\x66\x2f\x74\x61\x70\x5f\x72\x73\
+\x73\x2e\x63\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\x28\
+\x73\x74\x72\x75\x63\x74\x20\x5f\x5f\x73\x6b\x5f\x62\x75\x66\x66\x20\x2a\x73\
+\x6b\x62\x29\0\x09\x63\x68\x61\x72\x20\x66\x6d\x74\x5b\x5d\x20\x3d\x20\x22\x72\
+\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\
+\x73\x69\x64\x3a\x25\x75\x5c\x6e\x22\x3b\0\x09\x63\x6c\x61\x73\x73\x69\x64\x20\
+\x3d\x20\x28\x28\x63\x6f\x6e\x73\x74\x20\x73\x74\x72\x75\x63\x74\x20\x71\x64\
+\x69\x73\x63\x5f\x73\x6b\x62\x5f\x63\x62\x20\x2a\x29\x73\x6b\x62\x2d\x3e\x63\
+\x62\x29\x2d\x3e\x74\x63\x5f\x63\x6c\x61\x73\x73\x69\x64\x3b\0\x09\x62\x70\x66\
+\x5f\x74\x72\x61\x63\x65\x5f\x70\x72\x69\x6e\x74\x6b\x28\x66\x6d\x74\x2c\x20\
+\x73\x69\x7a\x65\x6f\x66\x28\x66\x6d\x74\x29\x2c\x20\x63\x6c\x61\x73\x73\x69\
+\x64\x29\x3b\0\x09\x72\x73\x73\x6b\x65\x79\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\
+\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x72\x73\x73\x5f\
+\x6d\x61\x70\x2c\x20\x26\x63\x6c\x61\x73\x73\x69\x64\x29\x3b\0\x09\x69\x66\x20\
+\x28\x72\x73\x73\x6b\x65\x79\x20\x3d\x3d\x20\x4e\x55\x4c\x4c\x29\x20\x7b\0\x09\
+\x09\x62\x70\x66\x5f\x70\x72\x69\x6e\x74\x6b\x28\x22\x68\x61\x73\x68\x28\x29\
+\x3a\x20\x72\x73\x73\x20\x6e\x6f\x74\x20\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\
+\x64\x22\x29\x3b\0\x09\x63\x6f\x6e\x73\x74\x20\x5f\x5f\x75\x33\x32\x20\x2a\x6b\
+\x65\x79\x20\x3d\x20\x28\x63\x6f\x6e\x73\x74\x20\x5f\x5f\x75\x33\x32\x20\x2a\
+\x29\x72\x73\x73\x6b\x65\x79\x2d\x3e\x6b\x65\x79\x3b\0\x09\x69\x66\x20\x28\x73\
+\x6b\x62\x2d\x3e\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x3d\x20\x62\x70\x66\
+\x5f\x68\x74\x6f\x6e\x73\x28\x45\x54\x48\x5f\x50\x5f\x49\x50\x29\x29\0\x09\x62\
+\x70\x66\x5f\x70\x72\x69\x6e\x74\x6b\x28\x22\x68\x61\x73\x68\x20\x25\x75\x5c\
+\x6e\x22\x2c\x20\x68\x61\x73\x68\x29\x3b\0\x09\x09\x72\x65\x74\x75\x72\x6e\x20\
+\x70\x61\x72\x73\x65\x5f\x69\x70\x76\x34\x28\x73\x6b\x62\x2c\x20\x72\x73\x73\
+\x6b\x65\x79\x2d\x3e\x68\x61\x73\x68\x5f\x66\x69\x65\x6c\x64\x73\x2c\x20\x6b\
+\x65\x79\x29\x3b\0\x09\x69\x66\x20\x28\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\
+\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\
+\x6b\x62\x2c\x20\x6f\x66\x66\x2c\x20\x26\x69\x70\x68\x2c\x20\x73\x69\x7a\x65\
+\x6f\x66\x28\x69\x70\x68\x29\x2c\x20\x42\x50\x46\x5f\x48\x44\x52\x5f\x53\x54\
+\x41\x52\x54\x5f\x4e\x45\x54\x29\x29\0\x09\x09\x2e\x64\x73\x74\x5f\x61\x64\x64\
+\x72\x20\x3d\x20\x62\x70\x66\x5f\x6e\x74\x6f\x68\x6c\x28\x69\x70\x68\x2e\x64\
+\x61\x64\x64\x72\x29\x2c\0\x09\x09\x2e\x73\x72\x63\x5f\x61\x64\x64\x72\x20\x3d\
+\x20\x62\x70\x66\x5f\x6e\x74\x6f\x68\x6c\x28\x69\x70\x68\x2e\x73\x61\x64\x64\
+\x72\x29\x2c\0\x09\x69\x66\x20\x28\x68\x61\x73\x68\x5f\x74\x79\x70\x65\x20\x26\
+\x20\x28\x31\x20\x3c\x3c\x20\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\x49\
+\x50\x56\x34\x5f\x4c\x33\x29\x29\0\x09\x09\x09\x69\x66\x20\x28\x69\x6e\x70\x75\
+\x74\x5f\x74\x75\x70\x6c\x65\x5b\x6a\x5d\x20\x26\x20\x28\x31\x55\x20\x3c\x3c\
+\x20\x28\x33\x31\x20\x2d\x20\x69\x29\x29\x29\0\x09\x09\x09\x09\x68\x61\x73\x68\
+\x20\x5e\x3d\x20\x6b\x65\x79\x5b\x6a\x5d\x20\x3c\x3c\x20\x69\x20\x7c\x20\x6b\
+\x65\x79\x5b\x6a\x20\x2b\x20\x31\x5d\x20\x3e\x3e\x20\x28\x33\x32\x20\x2d\x20\
+\x69\x29\x3b\0\x09\x09\x72\x65\x74\x75\x72\x6e\x20\x70\x61\x72\x73\x65\x5f\x69\
+\x70\x76\x36\x28\x73\x6b\x62\x2c\x20\x72\x73\x73\x6b\x65\x79\x2d\x3e\x68\x61\
+\x73\x68\x5f\x66\x69\x65\x6c\x64\x73\x2c\x20\x6b\x65\x79\x29\x3b\0\x09\x69\x66\
+\x20\x28\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\
+\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6f\x66\x66\
+\x2c\x20\x26\x69\x70\x36\x68\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x69\x70\x36\
+\x68\x29\x2c\x20\x42\x50\x46\x5f\x48\x44\x52\x5f\x53\x54\x41\x52\x54\x5f\x4e\
+\x45\x54\x29\x29\0\x09\x09\x76\x36\x5f\x74\x75\x70\x6c\x65\x2e\x64\x73\x74\x5f\
+\x61\x64\x64\x72\x5b\x6a\x5d\x20\x3d\x20\x62\x70\x66\x5f\x6e\x74\x6f\x68\x6c\
+\x28\x69\x70\x36\x68\x2e\x64\x61\x64\x64\x72\x2e\x69\x6e\x36\x5f\x75\x2e\x75\
+\x36\x5f\x61\x64\x64\x72\x33\x32\x5b\x6a\x5d\x29\x3b\0\x09\x09\x76\x36\x5f\x74\
+\x75\x70\x6c\x65\x2e\x73\x72\x63\x5f\x61\x64\x64\x72\x5b\x6a\x5d\x20\x3d\x20\
+\x62\x70\x66\x5f\x6e\x74\x6f\x68\x6c\x28\x69\x70\x36\x68\x2e\x73\x61\x64\x64\
+\x72\x2e\x69\x6e\x36\x5f\x75\x2e\x75\x36\x5f\x61\x64\x64\x72\x33\x32\x5b\x6a\
+\x5d\x29\x3b\0\x09\x69\x66\x20\x28\x68\x61\x73\x68\x5f\x74\x79\x70\x65\x20\x26\
+\x20\x28\x31\x20\x3c\x3c\x20\x48\x41\x53\x48\x5f\x46\x49\x45\x4c\x44\x5f\x49\
+\x50\x56\x36\x5f\x4c\x33\x29\x29\0\x09\x72\x65\x74\x75\x72\x6e\x20\x28\x69\x70\
+\x68\x2d\x3e\x66\x72\x61\x67\x5f\x6f\x66\x66\x20\x26\x20\x62\x70\x66\x5f\x68\
+\x74\x6f\x6e\x73\x28\x49\x50\x5f\x4d\x46\x20\x7c\x20\x49\x50\x5f\x4f\x46\x46\
+\x53\x45\x54\x29\x29\x20\x21\x3d\x20\x30\x3b\0\x09\x69\x66\x20\x28\x69\x73\x5f\
+\x69\x70\x76\x34\x5f\x66\x72\x61\x67\x6d\x65\x6e\x74\x28\x26\x69\x70\x68\x29\
+\x20\x7c\x7c\0\x09\x20\x20\x20\x20\x21\x28\x69\x70\x68\x2e\x70\x72\x6f\x74\x6f\
+\x63\x6f\x6c\x20\x3d\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\x5f\x55\x44\x50\x20\
+\x7c\x7c\x20\x69\x70\x68\x2e\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x3d\x20\
+\x49\x50\x50\x52\x4f\x54\x4f\x5f\x54\x43\x50\x29\x29\x20\x7b\0\x09\x09\x6f\x66\
+\x66\x20\x2b\x3d\x20\x69\x70\x68\x2e\x69\x68\x6c\x20\x2a\x20\x34\x3b\0\x09\x09\
+\x69\x66\x20\x28\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\
+\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6f\
+\x66\x66\x2c\0\x09\x70\x72\x6f\x74\x6f\x20\x3d\x20\x73\x6b\x69\x70\x5f\x69\x70\
+\x36\x5f\x65\x78\x74\x28\x69\x70\x36\x68\x2e\x6e\x65\x78\x74\x68\x64\x72\x2c\
+\x20\x73\x6b\x62\x2c\x20\x26\x6f\x66\x66\x2c\x20\x26\x66\x72\x61\x67\x29\x3b\0\
+\x09\x09\x73\x77\x69\x74\x63\x68\x20\x28\x70\x72\x6f\x74\x6f\x29\x20\x7b\0\x09\
+\x69\x66\x20\x28\x66\x72\x61\x67\x20\x7c\x7c\x20\x21\x28\x70\x72\x6f\x74\x6f\
+\x20\x3d\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\x5f\x55\x44\x50\x20\x7c\x7c\x20\
+\x70\x72\x6f\x74\x6f\x20\x3d\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\x5f\x54\x43\
+\x50\x29\x29\x20\x7b\0\x09\x09\x69\x66\x20\x28\x62\x70\x66\x5f\x73\x6b\x62\x5f\
+\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\
+\x28\x73\x6b\x62\x2c\x20\x6f\x66\x66\x2c\x20\x26\x73\x72\x63\x5f\x64\x73\x74\
+\x5f\x70\x6f\x72\x74\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x73\x72\x63\x5f\x64\
+\x73\x74\x5f\x70\x6f\x72\x74\x29\x2c\0\x09\x09\x09\x69\x66\x20\x28\x62\x70\x66\
+\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\
+\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x2a\x6f\x66\x66\x2c\x20\x26\x78\
+\x68\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x78\x68\x29\x2c\x20\x42\x50\x46\x5f\
+\x48\x44\x52\x5f\x53\x54\x41\x52\x54\x5f\x4e\x45\x54\x29\x29\0\x09\x09\x09\x2a\
+\x6f\x66\x66\x20\x2b\x3d\x20\x28\x78\x68\x2e\x6c\x65\x6e\x20\x2b\x20\x31\x29\
+\x20\x2a\x20\x38\x3b\0\x09\x09\x09\x70\x72\x6f\x74\x6f\x20\x3d\x20\x78\x68\x2e\
+\x6e\x65\x78\x74\x5f\x68\x64\x72\x3b\0\x09\x69\x66\x20\x28\x68\x61\x73\x68\x29\
+\x20\x7b\0\x09\x09\x73\x6b\x62\x2d\x3e\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\x70\
+\x69\x6e\x67\x20\x3d\x20\x72\x65\x63\x69\x70\x72\x6f\x63\x61\x6c\x5f\x73\x63\
+\x61\x6c\x65\x28\x68\x61\x73\x68\x2c\x20\x72\x73\x73\x6b\x65\x79\x2d\x3e\x6e\
+\x62\x5f\x71\x75\x65\x75\x65\x73\x29\x3b\0\x09\x72\x65\x74\x75\x72\x6e\x20\x28\
+\x5f\x5f\x75\x33\x32\x29\x28\x28\x28\x5f\x5f\x75\x36\x34\x29\x76\x61\x6c\x20\
+\x2a\x20\x6e\x29\x20\x3e\x3e\x20\x33\x32\x29\x3b\0\x09\x09\x62\x70\x66\x5f\x70\
+\x72\x69\x6e\x74\x6b\x28\x22\x71\x75\x65\x75\x65\x20\x25\x75\x5c\x6e\x22\x2c\
+\x20\x73\x6b\x62\x2d\x3e\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\x70\x69\x6e\x67\
+\x29\x3b\0\x7d\0\x63\x68\x61\x72\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\
+\x74\x69\x6f\x6e\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\0\x72\x73\x73\x5f\x66\x6c\x6f\
+\x77\x5f\x61\x63\x74\x69\x6f\x6e\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\x2e\x31\0\x72\
+\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\x2e\x5f\x5f\x5f\x5f\
+\x66\x6d\x74\x2e\x32\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x2e\x6d\x61\x70\x73\0\
+\x2e\x72\x6f\x64\x61\x74\x61\0\x6c\x69\x63\x65\x6e\x73\x65\0\x62\x70\x66\x5f\
+\x66\x6c\x6f\x77\x5f\x6b\x65\x79\x73\0\x62\x70\x66\x5f\x73\x6f\x63\x6b\0\0\0\
+\x9f\xeb\x01\0\x20\0\0\0\0\0\0\0\x14\0\0\0\x14\0\0\0\xfc\x2f\x01\0\x10\x30\x01\
+\0\0\0\0\0\x08\0\0\0\xd6\x01\0\0\x01\0\0\0\0\0\0\0\x1c\0\0\0\x10\0\0\0\xd6\x01\
+\0\0\xff\x12\0\0\0\0\0\0\xe1\x01\0\0\x1f\x02\0\0\0\xc0\x03\0\x10\0\0\0\xe1\x01\
+\0\0\x46\x02\0\0\x07\xcc\x03\0\x60\0\0\0\xe1\x01\0\0\x74\x02\0\0\x34\xe0\x03\0\
+\x68\0\0\0\xe1\x01\0\0\x74\x02\0\0\x0a\xe0\x03\0\x78\0\0\0\xe1\x01\0\0\0\0\0\0\
+\0\0\0\0\x80\0\0\0\xe1\x01\0\0\xb3\x02\0\0\x02\xe4\x03\0\x98\0\0\0\xe1\x01\0\0\
+\0\0\0\0\0\0\0\0\xa0\0\0\0\xe1\x01\0\0\xe1\x02\0\0\x0b\xf0\x03\0\xb8\0\0\0\xe1\
+\x01\0\0\x14\x03\0\0\x06\xf4\x03\0\xc0\0\0\0\xe1\x01\0\0\x2b\x03\0\0\x03\xf8\
+\x03\0\xf0\0\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\xf8\0\0\0\xe1\x01\0\0\x57\x03\0\0\
+\x2c\x2c\x03\0\x08\x01\0\0\xe1\x01\0\0\x87\x03\0\0\x0b\x34\x03\0\x10\x01\0\0\
+\xe1\x01\0\0\x87\x03\0\0\x06\x34\x03\0\x28\x01\0\0\xe1\x01\0\0\xb2\x03\0\0\x02\
+\x0c\x04\0\x68\x01\0\0\xe1\x01\0\0\xd2\x03\0\0\x22\x38\x03\0\xc0\x01\0\0\xe1\
+\x01\0\0\x06\x04\0\0\x06\x1c\x01\0\xd8\x01\0\0\xe1\x01\0\0\x06\x04\0\0\x06\x1c\
+\x01\0\xe0\x01\0\0\xe1\x01\0\0\xd2\x03\0\0\0\x38\x03\0\x10\x02\0\0\xe1\x01\0\0\
+\x58\x04\0\0\x0f\x44\x01\0\x20\x02\0\0\xe1\x01\0\0\x7c\x04\0\0\x0f\x40\x01\0\
+\x30\x02\0\0\xe1\x01\0\0\xa0\x04\0\0\x10\x54\x01\0\x38\x02\0\0\xe1\x01\0\0\xa0\
+\x04\0\0\x06\x54\x01\0\x60\x02\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x02\
+\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x78\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x0d\xbc\0\0\x88\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x02\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb0\x02\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x02\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xc8\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x02\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xe8\x02\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x03\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x0a\xbc\0\0\x10\x03\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\
+\x03\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x03\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x38\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x03\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x60\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x03\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x80\x03\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x03\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa0\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x03\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\
+\x03\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x03\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xe8\x03\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x03\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\
+\x08\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x04\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x30\x04\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x04\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x58\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x04\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\
+\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x04\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xa0\x04\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x04\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc0\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x04\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe0\x04\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x04\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x05\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x08\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x05\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x20\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\
+\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x05\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x50\x05\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x05\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x05\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x05\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x05\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\x05\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x05\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\
+\x05\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x05\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\0\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x06\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x06\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x28\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x06\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x06\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x70\x06\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x06\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x88\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\
+\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x06\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xa8\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x06\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x06\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xe0\x06\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x06\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xf8\x06\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x07\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x20\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x07\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x40\x07\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\
+\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x07\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x60\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x07\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x90\x07\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x07\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xa8\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x07\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xc8\x07\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x07\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x07\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\
+\x08\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x08\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x18\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x08\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\x08\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x60\x08\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x08\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x80\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x08\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\
+\x08\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x08\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xc8\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x08\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xe8\x08\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x09\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x10\x09\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x09\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x38\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x09\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x09\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x80\x09\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x09\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa0\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x09\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xc0\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x09\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x09\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xe8\x09\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x09\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\0\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\
+\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x0a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x30\x0a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x0a\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x58\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x0a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x68\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x0a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x0a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa0\x0a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x0a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\
+\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x0a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe0\x0a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x0a\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x0b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\
+\x08\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x0b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x20\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x0b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x50\x0b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x0b\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x68\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\
+\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x0b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x88\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x0b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x0b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc0\x0b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x0b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x0b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x0b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x0c\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x20\x0c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\
+\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x0c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x40\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x0c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x70\x0c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x0c\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x88\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x0c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xa8\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x0c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x0c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\
+\x0c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x0c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xf8\x0c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x0d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x20\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x0d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x40\x0d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x0d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x60\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x0d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x80\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\
+\x0d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x0d\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xa0\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x0d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xc0\x0d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x0d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xf0\x0d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x0e\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x10\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x0e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\
+\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x0e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x58\x0e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x0e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x70\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x0e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x90\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x0e\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb0\x0e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xb8\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x0e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\
+\x0e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x0e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xf8\x0e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x0f\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x18\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x0f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x28\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x0f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\x0f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x60\x0f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x0f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x70\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\
+\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x80\x0f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x98\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x0f\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\x0f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xc0\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x0f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd0\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x0f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x0f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\0\x10\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x10\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x08\xb8\0\0\x18\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\
+\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x10\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x30\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x10\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\x10\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x68\x10\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x10\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x78\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x10\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa0\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x10\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x10\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\
+\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x10\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xd8\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x10\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x10\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x08\x11\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x11\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x20\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x11\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x38\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x11\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x60\x11\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\
+\x11\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x78\x11\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x80\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x11\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa8\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x11\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xc8\x11\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x11\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xe0\x11\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x11\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\0\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\
+\x12\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x12\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x28\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x12\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x40\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x12\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x68\x12\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x12\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x88\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x12\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\
+\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x12\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xd0\x12\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x12\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe8\x12\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x12\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x08\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x13\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x13\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x30\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x13\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x40\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\
+\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x13\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x70\x13\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x13\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x90\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x13\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xa0\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x13\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x13\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xd8\x13\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x13\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\
+\x13\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x13\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x10\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x14\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\x14\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x38\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x14\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x48\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x14\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x78\x14\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x14\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x90\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\
+\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x14\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xa8\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x14\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x14\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xe0\x14\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x14\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xf0\x14\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x14\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x18\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x15\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x38\x15\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\
+\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x15\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x50\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x15\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x80\x15\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x15\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x98\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x15\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xb0\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x15\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\x15\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\
+\x15\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x15\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xf8\x15\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x16\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x20\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x16\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x40\x16\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x16\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x58\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x16\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x78\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\
+\x16\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x16\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xa0\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x16\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xb8\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x16\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xe0\x16\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x16\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x16\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\0\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x17\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x1b\xbc\0\0\x10\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\
+\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x17\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x48\x17\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x17\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x60\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x17\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x80\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x17\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x17\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa8\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x17\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\
+\x17\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x17\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe8\x17\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x17\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\x18\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\
+\x08\x18\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x18\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x18\x18\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x18\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x18\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x50\x18\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x18\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x60\x18\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\
+\x18\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x18\0\0\xe1\x01\0\0\x28\x05\0\
+\0\x22\x40\x03\0\xe0\x18\0\0\xe1\x01\0\0\x5c\x05\0\0\x06\x8c\x02\0\xf8\x18\0\0\
+\xe1\x01\0\0\x5c\x05\0\0\x06\x8c\x02\0\0\x19\0\0\xe1\x01\0\0\x28\x05\0\0\0\x40\
+\x03\0\x30\x19\0\0\xe1\x01\0\0\xb0\x05\0\0\x1a\xa4\x02\0\x48\x19\0\0\xe1\x01\0\
+\0\xf3\x05\0\0\x1a\xa0\x02\0\x60\x19\0\0\xe1\x01\0\0\xb0\x05\0\0\x1a\xa4\x02\0\
+\x70\x19\0\0\xe1\x01\0\0\xf3\x05\0\0\x1a\xa0\x02\0\x88\x19\0\0\xe1\x01\0\0\xb0\
+\x05\0\0\x1a\xa4\x02\0\xa0\x19\0\0\xe1\x01\0\0\xf3\x05\0\0\x1a\xa0\x02\0\xb0\
+\x19\0\0\xe1\x01\0\0\xb0\x05\0\0\x1a\xa4\x02\0\xc8\x19\0\0\xe1\x01\0\0\xf3\x05\
+\0\0\x1a\xa0\x02\0\xd8\x19\0\0\xe1\x01\0\0\x36\x06\0\0\x10\xb0\x02\0\xe0\x19\0\
+\0\xe1\x01\0\0\x36\x06\0\0\x06\xb0\x02\0\xf8\x19\0\0\xe1\x01\0\0\xcc\x04\0\0\
+\x17\xb8\0\0\x18\x1a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x1a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x30\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x1a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x50\x1a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x1a\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x78\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x1a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\
+\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x1a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xc8\x1a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x1a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe0\x1a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x1a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\0\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x1b\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x1b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x28\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x1b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x38\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\
+\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x1b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x68\x1b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x1b\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x88\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x1b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x98\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x1b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x1b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xd0\x1b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x1b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\
+\x1b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x1b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x08\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x1c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x1c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x30\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x1c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x1c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x70\x1c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x1c\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x88\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\
+\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x1c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xa0\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x1c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x1c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xd8\x1c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x1c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xe8\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x1c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x1c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x10\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x1d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x30\x1d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\
+\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x1d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x48\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x1d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x78\x1d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x1d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x90\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x1d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xa8\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x1d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x1d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\
+\x1d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x1d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xf0\x1d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x1d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\
+\x18\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x1e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x38\x1e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x1e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x50\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x1e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x70\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\
+\x1e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x1e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x98\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x1e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xb0\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x1e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd8\x1e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x1e\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xf8\x1e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x1f\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x1b\xbc\0\0\x08\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\
+\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x1f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x40\x1f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x1f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x58\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x1f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x78\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x1f\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x1f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa0\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x1f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\
+\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x1f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe0\x1f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x1f\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x1f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\0\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x20\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x10\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x20\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x20\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x48\x20\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x20\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x20\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x80\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x20\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x20\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa8\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x20\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x20\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x20\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\x20\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x20\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x21\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x21\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x21\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\x21\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x21\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x21\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x21\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x21\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x21\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x21\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x21\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\x21\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x22\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x22\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x22\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x22\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\x22\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x22\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x22\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x22\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\x22\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x22\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x22\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x22\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\x22\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x23\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x23\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x23\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\x23\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x23\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x23\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x23\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\x23\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x23\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x23\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\x23\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x24\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x24\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x24\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x24\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\x24\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x24\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x70\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x24\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x80\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x24\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x24\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc8\x24\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x24\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\
+\x24\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x24\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\0\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x25\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x25\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x30\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x25\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x25\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x70\x25\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x25\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x88\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\
+\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x25\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xa0\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x25\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x25\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xd8\x25\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x25\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xe8\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x25\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x25\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x10\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x26\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x30\x26\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\
+\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x26\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x48\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x26\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x78\x26\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x26\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x90\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x26\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xa8\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x26\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x26\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\
+\x26\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x26\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xf0\x26\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x26\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\
+\x18\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x27\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x38\x27\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x27\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x50\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x27\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x70\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\
+\x27\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x27\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x98\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x27\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xb0\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x27\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd8\x27\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x27\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xf8\x27\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x28\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x1b\xbc\0\0\x08\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\
+\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x28\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x40\x28\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x28\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x58\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x28\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x78\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x28\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x28\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa0\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x28\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\
+\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x28\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe0\x28\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x28\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x28\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\0\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x29\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x10\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x29\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x29\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x48\x29\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x29\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x29\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x80\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x29\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x29\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa8\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x29\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x29\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x29\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\x29\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x29\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x2a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x2a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x2a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\x2a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x2a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x2a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x2a\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x2a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x2a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x2a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x2a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\x2a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x2b\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x2b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x2b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x2b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\x2b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x2b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x2b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x2b\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\x2b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x2b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x2b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x2b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\x2b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x2c\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x2c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x2c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\x2c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x2c\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x2c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x2c\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\x2c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x2c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x2c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\x2c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x2d\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x2d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x2d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x2d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\x2d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x2d\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x2d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x2d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x2d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\x2d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x2d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\
+\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x2d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf8\x2d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x2e\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x2e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x20\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x2e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x30\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x2e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x60\x2e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x2e\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x78\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\
+\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x2e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x90\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x2e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x2e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc8\x2e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x2e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x2e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x2e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x2f\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x18\x2f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\
+\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x2f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x30\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x2f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x78\x2f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x2f\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x90\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x2f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xa8\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x2f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x2f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\
+\x2f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x2f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xf0\x2f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x2f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\
+\x18\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x30\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x38\x30\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x30\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x50\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x30\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x70\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\
+\x30\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x30\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x98\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x30\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xb0\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x30\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd8\x30\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x30\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xf8\x30\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x31\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x1b\xbc\0\0\x08\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\
+\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x31\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x40\x31\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x31\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x58\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x31\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x78\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x31\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x31\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa0\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x31\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\
+\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x31\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe0\x31\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x31\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x31\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\0\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x32\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x10\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x32\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x32\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x48\x32\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x32\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x32\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x80\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x32\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x32\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa8\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x32\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x32\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x32\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\x32\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x32\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x33\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x33\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x33\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\x33\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x33\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x33\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x33\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x33\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x33\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x33\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x33\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\x33\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x34\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x34\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x34\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x34\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\x34\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x34\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x34\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x34\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\x34\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x34\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x34\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x34\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\x34\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x35\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x35\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x35\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\x35\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x35\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x35\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x35\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\x35\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x35\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x35\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\x35\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x36\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x36\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x36\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x36\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\x36\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x36\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x36\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x36\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x36\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\x36\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x36\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\
+\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x36\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf8\x36\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x37\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x37\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x20\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x37\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x30\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x37\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x60\x37\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x37\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x78\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\
+\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x37\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x90\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x37\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x37\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc8\x37\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x37\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x37\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x37\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x38\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x20\x38\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\
+\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x38\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x38\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x38\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x68\x38\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x38\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x80\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x38\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x98\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x38\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x38\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\
+\x38\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x38\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xe0\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x38\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x38\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x08\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x39\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x28\x39\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x39\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x40\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x39\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x60\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\
+\x39\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x39\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x88\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x39\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xa0\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x39\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd0\x39\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x39\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe8\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x39\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x39\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\
+\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x3a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x40\x3a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x3a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x58\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x3a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x78\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x3a\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x3a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa0\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x3a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\
+\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x3a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe0\x3a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x3a\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x3a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\0\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x3b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x10\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x3b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x3b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x48\x3b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x3b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x3b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x80\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x3b\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x3b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa8\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x3b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x3b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x3b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\x3b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x3b\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x3c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x3c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x3c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\x3c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x3c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x3c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x3c\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x3c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x3c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x3c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x3c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\x3c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x3d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x3d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x3d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x3d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\x3d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x3d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x3d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x3d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\x3d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x3d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x3d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x3d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\x3d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x3e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x3e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x3e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\x3e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x3e\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x3e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x3e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\x3e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x3e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x3e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\x3e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x3f\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x3f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x3f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x3f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\x3f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x3f\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x3f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x3f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x3f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\x3f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x3f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\
+\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x3f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf8\x3f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x40\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x40\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x20\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x40\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x30\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x40\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x60\x40\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x40\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x78\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\
+\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x40\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x90\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x40\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x40\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc8\x40\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x40\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x40\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x40\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x41\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x20\x41\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\
+\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x41\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x38\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x41\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x68\x41\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x41\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x80\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x41\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x98\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x41\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x41\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\
+\x41\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x41\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xe0\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x41\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x41\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x08\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x42\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x28\x42\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x42\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x40\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x42\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x60\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\
+\x42\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x42\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x88\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x42\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xa0\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x42\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc8\x42\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x42\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe8\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x42\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x42\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\
+\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x43\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x30\x43\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x43\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x48\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x43\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x68\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x43\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x43\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x90\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x43\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\
+\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x43\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xd0\x43\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x43\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xf0\x43\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x43\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\0\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x44\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x44\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x38\x44\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x44\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\
+\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x44\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x70\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x44\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x44\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x44\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x44\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe0\x44\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x44\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x44\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\
+\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x45\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x10\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x45\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x45\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x48\x45\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x45\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x58\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x45\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x80\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x45\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x45\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\
+\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x45\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xb8\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x45\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x45\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xe8\x45\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x45\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\0\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\x46\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x18\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x46\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x46\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\
+\x46\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x46\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x60\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x46\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x88\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x46\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xa8\x46\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\x46\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc0\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x46\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x46\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\
+\x46\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x47\0\0\xe1\x01\0\0\xcc\x04\0\0\
+\x08\xb8\0\0\x08\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x47\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x20\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x47\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x48\x47\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\x47\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x68\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x47\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\
+\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x47\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb0\x47\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x47\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc8\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x47\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe8\x47\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\x47\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x48\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x10\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x48\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x20\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\
+\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x48\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x50\x48\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x48\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x70\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x48\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x80\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x48\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x48\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xb8\x48\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x48\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\
+\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x48\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf0\x48\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x49\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x49\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x18\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x49\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x28\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x49\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x58\x49\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x49\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x70\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\
+\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x49\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x88\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x49\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x49\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc0\x49\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x49\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd0\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x49\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf8\x49\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x4a\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x18\x4a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\
+\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x4a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x30\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x4a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x60\x4a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x4a\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x78\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x4a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x90\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x4a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x4a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\
+\x4a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x4a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd8\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x4a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x4a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x4b\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\x4b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x4b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x38\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x4b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\
+\x4b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x4b\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x80\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x4b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x98\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x4b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc0\x4b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x4b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe0\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x4b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x4b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x4c\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x28\x4c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x4c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x4c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x4c\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x4c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x88\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x4c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x4c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc8\x4c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x4c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe8\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x4c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf8\x4c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x4d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x4d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x30\x4d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x4d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x4d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x4d\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x4d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x4d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x4d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd0\x4d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x4d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\x4d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x4d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x4e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x4e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\x4e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x4e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x4e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x4e\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x90\x4e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\
+\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x4e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x4e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd8\x4e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x4e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf0\x4e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x4e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x08\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x4f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x4f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\
+\x4f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x4f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x48\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x4f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x70\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x4f\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xa0\x4f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x4f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb8\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x4f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x4f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\
+\x4f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x4f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\0\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\x50\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x18\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x50\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x40\x50\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\x50\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x60\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x50\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\
+\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x50\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xa8\x50\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\x50\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc0\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x50\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe0\x50\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x50\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x51\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x08\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x51\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x18\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\
+\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x51\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x48\x51\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\x51\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x68\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x51\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x78\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x51\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x51\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xb0\x51\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x51\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\
+\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x51\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe8\x51\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\x51\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x52\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x10\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x52\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x20\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x52\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x50\x52\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x52\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x68\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\
+\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x52\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x80\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x52\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x52\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xb8\x52\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x52\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xc8\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x52\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf0\x52\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x53\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x10\x53\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\
+\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x53\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x28\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x53\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x58\x53\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x53\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x70\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x53\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x88\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x53\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x53\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\
+\x53\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x53\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd0\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x53\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xf8\x53\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x54\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x18\x54\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x54\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x30\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x54\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x50\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\
+\x54\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x54\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x78\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x54\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x90\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x54\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xb8\x54\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x54\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xd8\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x54\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x54\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\
+\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x55\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x20\x55\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x55\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x38\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x55\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x58\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x55\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x55\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x80\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x55\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x90\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\
+\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x55\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc0\x55\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x55\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe0\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x55\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf0\x55\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x56\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x56\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x28\x56\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x56\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\
+\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x56\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x60\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x56\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x56\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x88\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x56\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x98\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x56\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xc8\x56\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x56\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\
+\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x56\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xf8\x56\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x57\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x57\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x30\x57\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x57\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x40\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x57\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x68\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x57\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x88\x57\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\
+\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x57\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa0\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x57\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd0\x57\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x57\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xe8\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x57\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x57\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\0\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x58\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x0a\xbc\0\0\x28\x58\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\
+\x58\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x58\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x48\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x58\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x70\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x58\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x90\x58\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x58\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa8\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x58\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\
+\x58\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x58\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf0\x58\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x58\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\
+\x08\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x59\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x30\x59\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x59\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x50\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x59\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\
+\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x59\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x98\x59\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x59\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb0\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\x59\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd0\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x59\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x59\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xf0\x59\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x59\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\0\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\
+\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x5a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x40\x5a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\x5a\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x60\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x5a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x70\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x5a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x5a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xb0\x5a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x5a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\
+\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x5a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe8\x5a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\x5a\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\x5b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x10\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x5b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x20\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x5b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x50\x5b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x5b\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x68\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\
+\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x5b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x80\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x5b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x5b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xb8\x5b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x5b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xc8\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x5b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf0\x5b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x5c\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x10\x5c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\
+\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x5c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x28\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x5c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x58\x5c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x5c\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x70\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x5c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x88\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x5c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x5c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\
+\x5c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x5c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd0\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x5c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xf8\x5c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x5d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x18\x5d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x5d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x30\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x5d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x50\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\
+\x5d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x5d\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x78\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x5d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x90\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x5d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xb8\x5d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x5d\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xd8\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x5d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x5d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\
+\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x5e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x20\x5e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x5e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x38\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x5e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x58\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x5e\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x5e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x80\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x5e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x90\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\
+\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x5e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc0\x5e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x5e\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe0\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x5e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf0\x5e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x5f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x5f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x28\x5f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x5f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\
+\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x5f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x60\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x5f\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x5f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x88\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x5f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x98\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x5f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xc8\x5f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x5f\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\
+\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x5f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xf8\x5f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x60\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\x60\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x30\x60\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x60\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x40\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x60\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x68\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x60\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x88\x60\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\
+\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x60\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa0\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x60\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd0\x60\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x60\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xe8\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x60\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x60\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\0\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x61\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x0a\xbc\0\0\x28\x61\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\
+\x61\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x61\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x48\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x61\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x70\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x61\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x90\x61\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x61\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa8\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x61\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\
+\x61\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x61\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf0\x61\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x61\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\
+\x08\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x62\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x30\x62\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x62\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x50\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x62\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\
+\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x62\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x98\x62\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x62\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb0\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\x62\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd0\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x62\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x62\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xf8\x62\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\x63\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x08\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\
+\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x63\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x38\x63\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\x63\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x58\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x63\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x68\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x63\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x63\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa0\x63\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x63\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\
+\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x63\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xd8\x63\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\x63\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x63\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\0\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\x64\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x10\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\x64\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x40\x64\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\x64\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x58\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\
+\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x64\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x70\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x64\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x64\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xa0\x64\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x64\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xb0\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x64\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xd8\x64\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x64\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\0\x65\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\
+\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x65\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x18\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x65\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x48\x65\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\x65\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x60\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\x65\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x78\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x65\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x65\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb0\
+\x65\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x65\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xc0\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x65\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe8\x65\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\x65\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x08\x66\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\x66\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x20\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x66\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x40\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\
+\x66\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x66\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x68\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\x66\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x80\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x66\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xa8\x66\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\x66\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xc8\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x66\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\
+\x66\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x67\0\0\xe1\x01\0\0\xcc\x04\0\0\
+\x17\xb8\0\0\x10\x67\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\x67\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x28\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x67\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x48\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\x67\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x67\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x70\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x67\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x80\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\
+\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x67\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xb0\x67\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x67\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xd0\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x67\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xe0\x67\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x67\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x68\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x18\x68\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x68\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x28\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\
+\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x68\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x50\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\x68\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\x68\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x78\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x68\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x88\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\x68\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xb8\x68\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x68\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xd0\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\
+\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x68\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xe8\x68\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x69\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x69\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x20\x69\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x69\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x30\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x69\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x58\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x69\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x78\x69\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\
+\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x69\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x90\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x69\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xc0\x69\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x69\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xd8\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x69\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xf0\x69\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x6a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x18\x6a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\
+\x6a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x6a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x38\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x6a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x60\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x6a\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x80\x6a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x6a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x98\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x6a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\
+\x6a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x6a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xe0\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\x6a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xf8\x6a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x6b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x20\x6b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\x6b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x40\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x6b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x50\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\
+\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x6b\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x88\x6b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\x6b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa0\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x6b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xc0\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x6b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x6b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xe8\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x6b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x6b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\
+\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x6c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x28\x6c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\x6c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x48\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x6c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x58\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x6c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x6c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x90\x6c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x6c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\
+\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x6c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc8\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\x6c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x6c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xf0\x6c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x6c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\0\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x6d\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x30\x6d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x6d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x48\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\
+\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x6d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x60\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x6d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x6d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x98\x6d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x6d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xa8\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x6d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xd0\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x6d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x6d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\
+\x6d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x19\xbc\0\0\x08\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\x6e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x38\x6e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\x6e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x50\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x6e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x68\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x6e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x6e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\
+\x6e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x6e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xb0\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x6e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd8\x6e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\x6e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xf8\x6e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\x6f\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\x6f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x10\x6f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\x6f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x30\x6f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\
+\x6f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\x6f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x60\x6f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\x6f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x6f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x78\x6f\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\xb0\x6f\0\0\xe1\x01\0\0\x62\x06\0\0\
+\x0f\xec\0\0\xb8\x6f\0\0\xe1\x01\0\0\x62\x06\0\0\x18\xec\0\0\xc0\x6f\0\0\xe1\
+\x01\0\0\x9f\x06\0\0\x1d\x64\x01\0\xc8\x6f\0\0\xe1\x01\0\0\xbe\x06\0\0\x24\x68\
+\x01\0\xe0\x6f\0\0\xe1\x01\0\0\x04\x07\0\0\x0e\x7c\x01\0\xe8\x6f\0\0\xe1\x01\0\
+\0\x04\x07\0\0\x12\x7c\x01\0\0\x70\0\0\xe1\x01\0\0\x04\x07\0\0\x0e\x7c\x01\0\
+\x08\x70\0\0\xe1\x01\0\0\x1a\x07\0\0\x07\x80\x01\0\x30\x70\0\0\xe1\x01\0\0\x1a\
+\x07\0\0\x07\x80\x01\0\x50\x70\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x70\
+\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x0d\xbc\0\0\x78\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x70\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa8\x70\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\x70\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xc0\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\x70\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xd8\x70\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x70\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\0\x71\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\
+\x71\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\x71\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x20\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x71\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x48\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\x71\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x68\x71\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x71\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x80\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x71\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\
+\x71\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x71\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xc8\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x71\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xe0\x71\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x71\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x08\x72\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x72\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x28\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x72\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\
+\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\x72\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x70\x72\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x78\x72\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x88\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\x72\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa8\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x72\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x72\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xd0\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x72\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\
+\x72\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x0a\xbc\0\0\x10\x73\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x73\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x30\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x73\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x40\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x73\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x73\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x78\x73\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\x73\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\
+\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x73\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xb0\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x73\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x73\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xd8\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x73\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe8\x73\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x73\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x18\x74\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x74\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x30\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\
+\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x74\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x48\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x74\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x74\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x80\x74\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x74\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x90\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x74\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb8\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x74\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x74\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\
+\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\x74\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf0\x74\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x74\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x20\x75\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\x75\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x38\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x75\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x50\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x75\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x78\x75\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\
+\x75\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\x75\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x98\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x75\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc0\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x75\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xe0\x75\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x75\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf8\x75\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x76\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x18\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\
+\x76\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\x76\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x40\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x76\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x58\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x76\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x80\x76\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x76\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xa0\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x76\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\
+\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\x76\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xe8\x76\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x76\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x76\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x77\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x20\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x77\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x77\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x48\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x77\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\
+\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x77\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x88\x77\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x77\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xa8\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x77\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xb8\x77\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x77\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x77\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xf0\x77\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x77\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\0\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\x78\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x28\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x78\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\x78\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x50\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x78\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x78\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x90\x78\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x78\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\
+\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x78\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xc0\x78\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x78\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\x78\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xf8\x78\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\x79\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x08\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x79\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x30\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x79\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x50\x79\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\
+\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\x79\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x79\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x98\x79\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x79\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xb0\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x79\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xc8\x79\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x79\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x79\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\
+\x7a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x7a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x10\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x7a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x38\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x7a\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x58\x7a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x7a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x7a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x90\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\
+\x7a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x7a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xb0\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x7a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xc8\x7a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x7a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\0\x7b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\x7b\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x20\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x7b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\x7b\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x68\x7b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\x7b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x80\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x7b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x7b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x7b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xc8\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\x7b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\
+\x7b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x7b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x08\x7c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\x7c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x28\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x7c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x38\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x7c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\x7c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x70\x7c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x78\x7c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\
+\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\x7c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\x7c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x7c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xd0\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x7c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe0\x7c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x7c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x10\x7d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x7d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x28\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\
+\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x7d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x40\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x7d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x7d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x78\x7d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\x7d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x88\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x7d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb0\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\x7d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x7d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\
+\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x7d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe8\x7d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\x7d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x18\x7e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x7e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x30\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x7e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x48\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x7e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x7e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\
+\x7e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x7e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x90\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x7e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb8\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x7e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xd8\x7e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\x7e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf0\x7e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\x7e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x10\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\
+\x7f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\x7f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x38\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\x7f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x50\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x7f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x78\x7f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x7f\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x98\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x7f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\
+\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x7f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xe0\x7f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x7f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xf8\x7f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\0\x80\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x18\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\x80\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\x80\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x40\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x48\x80\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x50\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\
+\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x80\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x80\x80\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\x80\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xa0\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x80\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xb0\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x80\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\x80\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xe8\x80\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf0\x80\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x80\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\
+\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x81\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x20\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x81\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x81\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x48\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\x81\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x58\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\x81\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x88\x81\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\x81\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\
+\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x81\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xb8\x81\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x81\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x81\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xf0\x81\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x81\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\0\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x82\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x28\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x82\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x48\x82\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\
+\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x82\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x60\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x82\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x90\x82\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x82\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xa8\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x82\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xc0\x82\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x82\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\x82\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\
+\x82\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x0d\xbc\0\0\x08\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x83\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x30\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x83\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x50\x83\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x83\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x68\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x83\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x88\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\
+\x83\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x83\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xb0\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x83\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xc8\x83\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x83\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xf0\x83\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x84\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x10\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x84\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\
+\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x84\0\0\xe1\x01\0\0\0\0\0\0\0\
+\0\0\0\x50\x84\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x84\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x08\xb8\0\0\x68\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\
+\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x84\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x80\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x84\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\x84\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\xb8\
+\x84\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x84\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xd0\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x84\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xe8\x84\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x85\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x10\x85\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\x18\x85\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x85\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x30\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x85\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x85\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x70\x85\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\x78\x85\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x80\x85\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x85\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x98\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x85\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\
+\x85\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x85\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xe8\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\x85\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x85\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\0\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x86\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x28\x86\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\x86\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x48\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x86\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\
+\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\x86\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x90\x86\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\x86\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa8\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\x86\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xc8\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\x86\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\x86\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xf0\x86\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x86\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\0\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\
+\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x87\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x30\x87\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x87\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x50\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\x87\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x60\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\x87\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x87\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x98\x87\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\x87\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\
+\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\x87\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xd0\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\x87\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x87\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xf8\x87\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\x88\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x08\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\x88\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x38\x88\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\x88\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x50\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\
+\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x88\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x68\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x88\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x88\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xa0\x88\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x88\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xb0\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x88\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xd8\x88\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\x88\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x88\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\
+\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\x89\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x10\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\x89\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x40\x89\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\x89\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x58\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\x89\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x70\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\x89\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x89\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa8\
+\x89\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\x89\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xb8\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x89\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe0\x89\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x89\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\0\x8a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x8a\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x18\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x8a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x38\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\
+\x8a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\x8a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x60\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\x8a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x78\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\x8a\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xa0\x8a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb0\x8a\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xc0\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x8a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\
+\x8a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\x8a\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x08\x8b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\x8b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x20\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x8b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\x8b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x8b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x68\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\x8b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x78\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x80\
+\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\x8b\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xa8\x8b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\x8b\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xc8\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\x8b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xd8\x8b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x8b\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\x8c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x10\x8c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\x8c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x20\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\
+\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\x8c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x48\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\x8c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\x8c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x70\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x8c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x80\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x8c\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xb0\x8c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x8c\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\
+\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x8c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xe0\x8c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\x8c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\x8d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x18\x8d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\x8d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x28\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x8d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x50\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\x8d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x70\x8d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x78\
+\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\x8d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x88\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\x8d\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xb8\x8d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\x8d\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xd0\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x8d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xe8\x8d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x8e\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x0a\xbc\0\0\x10\x8e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\
+\x8e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x8e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x30\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x8e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x58\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\x8e\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x78\x8e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\x8e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x90\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\x8e\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xb0\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\
+\x8e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\x8e\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xd8\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe0\x8e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xf0\x8e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x8f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x18\x8f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x8f\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x38\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x8f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x8f\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x80\x8f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x8f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x98\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\x8f\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc8\x8f\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\x8f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xe0\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\x8f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xf0\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\
+\x8f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x90\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x20\x90\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x28\x90\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\x90\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x38\x90\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x90\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x48\x90\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x90\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\x90\0\0\xe1\x01\0\0\x46\x07\0\0\x1c\
+\xc0\x02\0\x98\x90\0\0\xe1\x01\0\0\x7d\x07\0\0\x03\xec\x01\0\xb0\x90\0\0\xe1\
+\x01\0\0\x90\x07\0\0\x25\xd0\x02\0\xd0\x90\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\xd8\
+\x90\0\0\xe1\x01\0\0\xd0\x07\0\0\x07\xe4\x02\0\xf8\x90\0\0\xe1\x01\0\0\xd0\x07\
+\0\0\x07\xe4\x02\0\x18\x91\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\x91\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x48\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\x91\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x58\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\
+\x91\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\x91\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x90\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\x91\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xb0\x91\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\x91\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd8\x91\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x91\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x10\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x92\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x20\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\
+\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x92\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x60\x92\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x92\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x80\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x92\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x92\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x92\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xc8\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x92\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\
+\x92\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x0a\xbc\0\0\x10\x93\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x93\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x38\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x93\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x48\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x93\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x93\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x80\x93\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x93\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\
+\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x93\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x93\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x93\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xe8\x93\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x93\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\0\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x94\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x30\x94\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x94\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x48\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\
+\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x94\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x68\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x94\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x94\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xa0\x94\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x94\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xb8\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x94\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xe0\x94\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x94\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\0\x95\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\
+\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x95\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x20\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x95\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x50\x95\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x95\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x68\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x95\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x88\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x95\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x95\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\
+\x95\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x95\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd8\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x95\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x95\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x96\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\x96\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x96\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x40\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x96\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x60\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\
+\x96\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\x96\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x88\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\x96\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xa8\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x96\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xd0\x96\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x96\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xf8\x96\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x97\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x1b\xbc\0\0\x08\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\
+\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\x97\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x40\x97\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\x97\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x60\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x97\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x80\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x97\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x97\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xa8\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x97\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\
+\x97\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x97\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xf0\x97\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x98\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x18\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x98\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x28\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x98\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\x98\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x60\x98\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\x98\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\
+\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\x98\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa0\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\x98\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x98\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xc8\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd8\x98\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe0\x98\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x98\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x10\x99\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x20\x99\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x28\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\
+\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\x99\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x48\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x99\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x99\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x80\x99\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\x99\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x98\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x99\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc0\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\x99\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xe0\x99\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\
+\x99\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\x99\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\0\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\x9a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x30\x9a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\x9a\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x48\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x9a\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x68\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x9a\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x9a\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\
+\x9a\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\x9a\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xb8\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\x9a\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe0\x9a\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\x9a\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\0\x9b\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\x9b\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x20\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\x9b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x40\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\
+\x9b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\x9b\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x68\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\x9b\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x88\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\x9b\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xb0\x9b\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\x9b\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xd8\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x9b\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\x9b\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\
+\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\x9c\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x20\x9c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\x9c\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\x9c\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\x9c\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\x9c\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x80\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\x9c\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\x9c\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xe0\x9c\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\x9c\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xf8\x9c\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\0\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\x9d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x10\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\x9d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x38\x9d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x48\x9d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\x9d\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x58\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\
+\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x68\x9d\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x80\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\x9d\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa0\x9d\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa8\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\x9d\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb8\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\x9d\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\x9d\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\x9d\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\x9d\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\x9e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\x9e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\x9e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\x9e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\x9e\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\x9e\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\x9e\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\x9e\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\x9e\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\x9e\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\x9e\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\x9e\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\x9f\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\x9f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\x9f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\x9f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\x9f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\x9f\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\x9f\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\x9f\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\x9f\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\x9f\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\x9f\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\x9f\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\x9f\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\xa0\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xa0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xa0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\xa0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xa0\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xa0\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\xa0\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\xa0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xa0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xa0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\xa0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xa1\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\xa1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xa1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xa1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\xa1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xa1\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xa1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xa1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xa1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\xa1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xa1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\
+\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xa1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf8\xa1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xa2\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\xa2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x20\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xa2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x30\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xa2\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x60\xa2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xa2\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x78\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\
+\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xa2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x90\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xa2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\xa2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc8\xa2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\xa2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xa2\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\xa2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\xa3\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x20\xa3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\
+\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xa3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x38\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xa3\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x68\xa3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xa3\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x80\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xa3\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x98\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xa3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\xa3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\
+\xa3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xa3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xe0\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xa3\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xa3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x08\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xa4\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x28\xa4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xa4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x40\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xa4\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x60\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\
+\xa4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xa4\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x88\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xa4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xa0\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xa4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc8\xa4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xa4\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe8\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xa4\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\xa4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\
+\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xa5\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x30\xa5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xa5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x48\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xa5\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x68\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xa5\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xa5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x90\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xa5\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\
+\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xa5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xd0\xa5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xa5\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xf0\xa5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xa5\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\0\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xa6\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xa6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x38\xa6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xa6\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x48\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\
+\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xa6\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x70\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xa6\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\xa6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x98\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xa6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa8\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xa6\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd8\xa6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xa6\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xf0\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\
+\xa6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x1b\xbc\0\0\x08\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xa7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xa7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\xa7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xa7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xa7\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xa7\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa0\xa7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\
+\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\xa7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xb8\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xa7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xa7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xe8\xa7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xa7\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\0\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xa8\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x18\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xa8\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x40\xa8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\
+\xa8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xa8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x60\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xa8\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x88\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xa8\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xa8\xa8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xa8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc0\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xa8\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xa8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\
+\xa8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\xa9\0\0\xe1\x01\0\0\xcc\x04\0\0\
+\x08\xb8\0\0\x08\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xa9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x20\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\xa9\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x48\xa9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xa9\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x68\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xa9\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x78\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\
+\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xa9\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb0\xa9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xa9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc8\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xa9\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe8\xa9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xa9\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\xaa\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x10\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xaa\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x20\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\
+\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xaa\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x50\xaa\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xaa\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x70\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xaa\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x80\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xaa\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\xaa\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xb8\xaa\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xaa\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\
+\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xaa\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf0\xaa\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xab\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\xab\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x18\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xab\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x28\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xab\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x58\xab\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xab\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x70\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\
+\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xab\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x88\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xab\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xab\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc0\xab\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xab\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd0\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xab\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf8\xab\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xac\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x18\xac\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\
+\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xac\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x30\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xac\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x60\xac\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xac\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x78\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\xac\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x90\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xac\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\xac\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\
+\xac\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\xac\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd8\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xac\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\xac\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\xad\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\xad\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\xad\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x38\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xad\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\
+\xad\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xad\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x80\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xad\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x98\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xad\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc0\xad\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\xad\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe0\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xad\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xad\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xae\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x28\xae\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xae\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xae\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xae\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xae\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x88\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xae\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xae\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc8\xae\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xae\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe8\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xae\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf8\xae\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xaf\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xaf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x30\xaf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xaf\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xaf\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xaf\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xaf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xaf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xaf\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd0\xaf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xaf\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\xaf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xaf\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xb0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xb0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\xb0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xb0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xb0\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xb0\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x90\xb0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\
+\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xb0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xb0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd8\xb0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xb0\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf0\xb0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xb0\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x08\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xb1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xb1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\
+\xb1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xb1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x50\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xb1\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x78\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xb1\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x98\xb1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xb1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb0\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xb1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\
+\xb1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xb1\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf8\xb1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xb2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x10\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xb2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x48\xb2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xb2\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x68\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xb2\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x78\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\
+\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xb2\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb0\xb2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xb2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xc8\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xb2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xe8\xb2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xb2\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\xb3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x10\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xb3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x20\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\
+\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xb3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x50\xb3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xb3\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x70\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xb3\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x80\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xb3\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\xb3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xb8\xb3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xb3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\
+\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xb3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf0\xb3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xb4\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\xb4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x18\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xb4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x28\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xb4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x58\xb4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xb4\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x70\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\
+\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xb4\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x88\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xb4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xb4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc0\xb4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xb4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd0\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xb4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf8\xb4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xb5\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x18\xb5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\
+\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xb5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x30\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xb5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x60\xb5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xb5\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x78\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\xb5\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x90\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xb5\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\xb5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\
+\xb5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\xb5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd8\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xb5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\xb5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\xb6\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\xb6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\xb6\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x38\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xb6\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\
+\xb6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xb6\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x80\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xb6\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x98\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xb6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc0\xb6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\xb6\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe0\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xb6\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xb6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xb7\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x28\xb7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xb7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xb7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xb7\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xb7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x88\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xb7\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xb7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc8\xb7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xb7\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe8\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xb7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf8\xb7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xb8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xb8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x30\xb8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xb8\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xb8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xb8\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xb8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xb8\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xb8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd0\xb8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xb8\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\xb8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xb8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xb9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xb9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\xb9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xb9\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xb9\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xb9\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x90\xb9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\
+\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xb9\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xb9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd8\xb9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xb9\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf0\xb9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xb9\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x08\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xba\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xba\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\
+\xba\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xba\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x50\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xba\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x78\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xba\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x98\xba\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xba\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb0\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xba\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\
+\xba\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xba\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf8\xba\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xbb\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x10\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xbb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x38\xbb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\xbb\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x58\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\xbb\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x68\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\
+\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xbb\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xa0\xbb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\xbb\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb8\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xbb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd8\xbb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\xbb\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xbb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\0\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xbc\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x10\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\
+\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xbc\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x40\xbc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\xbc\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x60\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xbc\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x70\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xbc\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xbc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa8\xbc\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xbc\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\
+\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xbc\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe0\xbc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xbd\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\xbd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x18\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xbd\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x28\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xbd\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x58\xbd\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xbd\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x70\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\
+\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xbd\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x88\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xbd\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xbd\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc0\xbd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xbd\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd0\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xbd\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xf8\xbd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xbe\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x18\xbe\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\
+\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xbe\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x30\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xbe\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x60\xbe\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xbe\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x78\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\xbe\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x90\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xbe\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\xbe\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc8\
+\xbe\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\xbe\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd8\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xbe\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\xbe\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\0\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\xbf\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\xbf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\xbf\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x38\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xbf\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\
+\xbf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xbf\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x80\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xbf\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x98\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xbf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc0\xbf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\xbf\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe0\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xbf\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xbf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xc0\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x28\xc0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xc0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xc0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xc0\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xc0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x88\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xc0\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xc0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc8\xc0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xc0\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe8\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xc0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf8\xc0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xc1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xc1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x30\xc1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xc1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xc1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xc1\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xc1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xc1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xc1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd0\xc1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xc1\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\xc1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xc1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xc2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xc2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\xc2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xc2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xc2\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xc2\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x90\xc2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\
+\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xc2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xc2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd8\xc2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xc2\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf0\xc2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xc2\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x08\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xc3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xc3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\
+\xc3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xc3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x50\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xc3\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x78\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xc3\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x98\xc3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xc3\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb0\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xc3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\
+\xc3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xc3\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf8\xc3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xc4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x10\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xc4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x38\xc4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\xc4\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x58\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\xc4\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x68\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\
+\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xc4\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xa0\xc4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\xc4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb8\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xc4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd8\xc4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\xc4\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xc4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\0\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xc5\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x10\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\
+\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xc5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x40\xc5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\xc5\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x60\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xc5\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x70\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xc5\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xc5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa8\xc5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xc5\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\
+\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xc5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe0\xc5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\xc5\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\xc6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\
+\x08\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xc6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x18\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\xc6\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x48\xc6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xc6\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x60\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\
+\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xc6\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x78\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xc6\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xc6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xb0\xc6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xc6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xc0\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xc6\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xe8\xc6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xc6\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x08\xc7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\
+\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xc7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x20\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\xc7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x50\xc7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xc7\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x60\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\xc7\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x78\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xc7\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xc7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\
+\xc7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xc7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xd0\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xc7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xf8\xc7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xc8\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x20\xc8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\xc8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x38\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xc8\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x58\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\
+\xc8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xc8\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x80\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xc8\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x98\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xc8\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc0\xc8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\xc8\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe0\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xc8\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xc8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\
+\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xc9\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x28\xc9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xc9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x40\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xc9\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x60\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xc9\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xc9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x88\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xc9\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x98\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\
+\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xc9\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc8\xc9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xc9\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe8\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xc9\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf8\xc9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xca\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xca\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x30\xca\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xca\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\
+\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xca\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x68\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xca\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xca\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x90\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xca\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa0\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xca\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd0\xca\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xca\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\xca\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xca\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xcb\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xcb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x38\xcb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xcb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x48\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xcb\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x70\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xcb\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x90\xcb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\
+\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xcb\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa8\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xcb\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd8\xcb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xcb\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf0\xcb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xcb\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x08\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xcc\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xcc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\
+\xcc\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xcc\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x50\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xcc\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x78\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xcc\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x98\xcc\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xcc\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xb0\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xcc\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\
+\xcc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xcc\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf8\xcc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xcd\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x10\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xcd\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x38\xcd\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\xcd\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x58\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\xcd\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x68\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\
+\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xcd\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xa0\xcd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\xcd\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb8\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xcd\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd8\xcd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\xcd\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xcd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\0\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xce\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x10\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\
+\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xce\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x40\xce\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\xce\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x60\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xce\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x70\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xce\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xce\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa8\xce\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xce\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\
+\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xce\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xe0\xce\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\xce\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\xcf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\
+\x08\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xcf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x18\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\xcf\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x48\xcf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xcf\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x60\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\
+\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xcf\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x78\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xcf\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xcf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xb0\xcf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xcf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xc0\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xcf\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xe8\xcf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xcf\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x08\xd0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\
+\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xd0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x20\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\xd0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x50\xd0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xd0\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x68\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\xd0\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x80\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xd0\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\xd0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\
+\xd0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xd0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xc8\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xd0\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xf0\xd0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xd1\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x10\xd1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\xd1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x28\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xd1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x48\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\
+\xd1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xd1\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x70\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\xd1\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x88\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xd1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xb0\xd1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\xd1\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xd0\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xd1\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\
+\xd1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xd2\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x10\xd2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\xd2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x28\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xd2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x48\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x68\xd2\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xd2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x80\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xd2\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x90\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x98\
+\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xd2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xc0\xd2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\xd2\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xe0\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xd2\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xf0\xd2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xd3\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xd3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x28\xd3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xd3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\
+\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xd3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x60\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xd3\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xd3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x88\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xd3\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x98\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\xd3\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xc8\xd3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xd3\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\
+\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xd3\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xf8\xd3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xd4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xd4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x30\xd4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xd4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x40\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xd4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x68\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xd4\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x88\xd4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\
+\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xd4\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xa0\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xd4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xd0\xd4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xd4\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xe8\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\xd4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xd4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\0\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xd5\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x0a\xbc\0\0\x28\xd5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\
+\xd5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xd5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x48\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xd5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x70\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xd5\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x90\xd5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\xd5\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa8\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xd5\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\
+\xd5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xd5\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xf0\xd5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xd5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\
+\x08\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xd6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x30\xd6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\xd6\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x50\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xd6\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\
+\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xd6\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x98\xd6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xd6\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xb0\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xd6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xd0\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\xd6\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xd6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xf8\xd6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xd7\0\0\xe1\x01\0\0\
+\xf6\x04\0\0\x19\xbc\0\0\x08\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\
+\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xd7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x38\xd7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\xd7\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x50\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x58\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\xd7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x68\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xd7\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xd7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xa0\xd7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\xd7\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xb0\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\
+\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xd7\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xd8\xd7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\xd7\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xd7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\0\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xd8\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x10\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\xd8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x40\xd8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\xd8\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x58\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\
+\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xd8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x70\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xd8\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xd8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xa8\xd8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xd8\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xb8\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xd8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xe0\xd8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\xd8\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\0\xd9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\
+\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xd9\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x18\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\xd9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x48\xd9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xd9\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x60\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\xd9\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x78\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xd9\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xd9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb0\
+\xd9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xd9\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xc0\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xd9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe8\xd9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xd9\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x08\xda\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\xda\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x20\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\xda\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x40\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\
+\xda\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xda\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x68\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\xda\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x80\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xda\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xa8\xda\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\xda\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xc8\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xda\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\
+\xda\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xdb\0\0\xe1\x01\0\0\xcc\x04\0\0\
+\x17\xb8\0\0\x10\xdb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\xdb\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x28\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xdb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x48\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\xdb\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xdb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x70\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\xdb\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x80\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\
+\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xdb\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xb0\xdb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\xdb\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xd0\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xdb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xe0\xdb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xdb\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xdc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x18\xdc\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\xdc\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\
+\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xdc\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x50\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\xdc\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xdc\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x78\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\xdc\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x88\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x90\xdc\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xb8\xdc\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\xdc\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\
+\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xdc\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xe0\xdc\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xdc\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xdd\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x28\xdd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xdd\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x38\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xdd\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x60\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\xdd\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x80\xdd\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x88\
+\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xdd\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x98\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa0\xdd\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xc8\xdd\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xdd\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xe0\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xe8\xdd\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\xf8\xdd\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xde\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xde\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x30\
+\xde\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xde\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x40\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xde\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x68\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xde\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x88\xde\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x90\xde\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xa0\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\xde\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd0\
+\xde\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xde\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\xe8\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\xde\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xde\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\0\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xdf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x28\xdf\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x38\xdf\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x48\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xdf\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\
+\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xdf\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x90\xdf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x98\xdf\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xa8\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xdf\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xc8\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xd8\xdf\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xdf\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\xf0\xdf\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\xdf\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\0\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x08\
+\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xe0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x30\xe0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\xe0\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x50\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xe0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x60\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xe0\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xe0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x98\xe0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\xe0\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\
+\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xe0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xd0\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe0\xe0\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xe0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xf8\xe0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xe1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x08\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x10\xe1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x38\xe1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x48\xe1\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x50\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x58\
+\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x60\xe1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x68\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xe1\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x90\xe1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xa0\xe1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa8\xe1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xb0\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xe1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc0\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xd8\xe1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xe8\xe1\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xe1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\0\
+\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\xe2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x10\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x18\xe2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x40\xe2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\xe2\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x58\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x60\xe2\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x70\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xe2\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xe2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xa8\
+\xe2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\xe2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xb8\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xe2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xe0\xe2\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf0\xe2\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\0\xe3\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x08\xe3\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x18\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x20\xe3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x38\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x48\
+\xe3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\xe3\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x60\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x68\xe3\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x78\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xe3\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xa0\xe3\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb0\xe3\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xc0\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xe3\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\
+\xe3\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\xe3\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x08\xe4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x10\xe4\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x20\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x28\xe4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x40\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x50\xe4\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xe4\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x68\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x70\xe4\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x78\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x80\
+\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xe4\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xa8\xe4\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xb8\xe4\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xc8\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xe4\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\xd8\xe4\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xe4\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xe5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x10\xe5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x18\xe5\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\
+\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\xe5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x48\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x58\xe5\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xe5\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x70\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x78\xe5\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x80\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x88\xe5\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xb0\xe5\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xc0\xe5\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\
+\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\xe5\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\xe0\xe5\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xe5\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xe6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x18\xe6\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x20\xe6\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x28\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xe6\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x50\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x60\xe6\0\0\xe1\x01\0\
+\0\0\0\0\0\0\0\0\0\x68\xe6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xe6\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x80\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x88\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xe6\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x98\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\
+\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\xe6\0\0\xe1\x01\0\0\0\0\0\0\0\
+\0\0\0\xd0\xe6\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xe6\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x08\xb8\0\0\xe8\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf0\
+\xe6\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xe6\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\0\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xe7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xe7\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\x30\
+\xe7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x40\xe7\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x48\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x50\xe7\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x60\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xe7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x88\xe7\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\x90\xe7\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x98\xe7\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\xa0\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xe7\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xb0\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xe7\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xe7\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xe8\xe7\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf8\xe7\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\0\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x08\
+\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\xe8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x18\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x30\xe8\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x40\xe8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x50\xe8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xe8\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x60\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xe8\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x70\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x88\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x98\xe8\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\xa8\xe8\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb0\
+\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xb8\xe8\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xc0\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xc8\xe8\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xe8\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xf0\xe8\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\0\xe9\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x08\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x10\xe9\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x20\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x38\xe9\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\xe9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x58\
+\xe9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x60\xe9\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x68\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x70\xe9\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x90\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa0\xe9\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\xb0\xe9\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xb8\xe9\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc0\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\xc8\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd0\xe9\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xe9\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xf8\
+\xe9\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x08\xea\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x10\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x18\xea\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\x28\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x40\xea\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\x50\xea\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x60\xea\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x68\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\x70\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x78\xea\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\x80\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\
+\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xa8\xea\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\xb8\xea\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc0\xea\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xc8\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\xd0\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xd8\xea\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xf0\xea\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\0\xeb\0\0\
+\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x10\xeb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x18\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x20\xeb\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x28\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x30\
+\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x48\xeb\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\x58\xeb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x68\xeb\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x70\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\x78\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x80\xeb\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\x88\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xeb\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb0\xeb\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\xc0\xeb\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xc8\xeb\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\xd0\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd8\
+\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe0\xeb\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xf8\xeb\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x08\xec\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x18\xec\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x20\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x28\xec\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x30\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x38\xec\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\x60\xec\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x70\xec\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\x78\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x80\
+\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x88\xec\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x1b\xbc\0\0\x90\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xa8\xec\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\xb8\xec\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\xc8\xec\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd0\xec\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\xd8\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe0\xec\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xe8\xec\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\0\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x10\xed\0\0\xe1\x01\0\0\
+\xcc\x04\0\0\x17\xb8\0\0\x20\xed\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x28\
+\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x30\xed\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x38\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x40\xed\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\x68\xed\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x78\xed\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\x80\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x88\xed\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x90\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x98\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb0\xed\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\xc0\xed\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd0\
+\xed\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xd8\xed\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\xe0\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xe8\xed\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xf0\xed\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x08\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x18\xee\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x17\xb8\0\0\x28\xee\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x30\xee\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x38\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x40\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x48\xee\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\x60\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x70\
+\xee\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x80\xee\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x08\xb8\0\0\x88\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x90\xee\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x98\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\
+\0\xa0\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xb8\xee\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0a\xbc\0\0\xc8\xee\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xd8\xee\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe0\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\
+\xbc\0\0\xe8\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf0\xee\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x1b\xbc\0\0\xf8\xee\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x10\
+\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x20\xef\0\0\xe1\x01\0\0\xcc\x04\0\
+\0\x17\xb8\0\0\x30\xef\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x38\xef\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x40\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\
+\0\x48\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x50\xef\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\x68\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x78\xef\0\
+\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x88\xef\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\
+\xb8\0\0\x90\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\x98\xef\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x19\xbc\0\0\xa0\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xa8\
+\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc0\xef\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0a\xbc\0\0\xd0\xef\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe0\xef\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xe8\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\
+\0\xf0\xef\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xf8\xef\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x1b\xbc\0\0\0\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x18\xf0\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x28\xf0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\
+\xb8\0\0\x38\xf0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x40\xf0\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0d\xbc\0\0\x48\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x50\
+\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x58\xf0\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\x70\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x80\xf0\0\0\xe1\
+\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x90\xf0\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\
+\0\x98\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa0\xf0\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x19\xbc\0\0\xa8\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb0\xf0\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xc8\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\
+\xbc\0\0\xd8\xf0\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xe8\xf0\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x08\xb8\0\0\xf0\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xf8\
+\xf0\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\0\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\
+\x1b\xbc\0\0\x08\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x20\xf1\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x30\xf1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\
+\0\x40\xf1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x48\xf1\0\0\xe1\x01\0\0\xf6\
+\x04\0\0\x0d\xbc\0\0\x50\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x58\xf1\0\
+\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x60\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\
+\xbc\0\0\x78\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\0\x88\xf1\0\0\xe1\x01\0\
+\0\xcc\x04\0\0\x17\xb8\0\0\x98\xf1\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\xa0\
+\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\xa8\xf1\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x19\xbc\0\0\xb0\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\xb8\xf1\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\xd0\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0a\xbc\0\
+\0\xe0\xf1\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\xf0\xf1\0\0\xe1\x01\0\0\xcc\
+\x04\0\0\x08\xb8\0\0\xf8\xf1\0\0\xe1\x01\0\0\xf6\x04\0\0\x0d\xbc\0\0\0\xf2\0\0\
+\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x08\xf2\0\0\xe1\x01\0\0\xf6\x04\0\0\x1b\
+\xbc\0\0\x10\xf2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x28\xf2\0\0\xe1\x01\0\
+\0\xf6\x04\0\0\x0a\xbc\0\0\x48\xf2\0\0\xe1\x01\0\0\xcc\x04\0\0\x17\xb8\0\0\x50\
+\xf2\0\0\xe1\x01\0\0\xcc\x04\0\0\x08\xb8\0\0\x58\xf2\0\0\xe1\x01\0\0\xf6\x04\0\
+\0\x0d\xbc\0\0\x60\xf2\0\0\xe1\x01\0\0\xf6\x04\0\0\x19\xbc\0\0\x68\xf2\0\0\xe1\
+\x01\0\0\xf6\x04\0\0\x1b\xbc\0\0\x78\xf2\0\0\xe1\x01\0\0\x7d\x07\0\0\x03\xec\
+\x01\0\x98\xf2\0\0\xe1\x01\0\0\x21\x08\0\0\x08\xfc\x01\0\xc0\xf2\0\0\xe1\x01\0\
+\0\x21\x08\0\0\x08\xfc\x01\0\xc8\xf2\0\0\xe1\x01\0\0\x74\x08\0\0\x10\x08\x02\0\
+\xd0\xf2\0\0\xe1\x01\0\0\x74\x08\0\0\x19\x08\x02\0\xd8\xf2\0\0\xe1\x01\0\0\x74\
+\x08\0\0\x09\x08\x02\0\xe8\xf2\0\0\xe1\x01\0\0\x91\x08\0\0\x0f\x0c\x02\0\xf0\
+\xf2\0\0\xe1\x01\0\0\x7d\x07\0\0\x03\xec\x01\0\x40\xf3\0\0\xe1\x01\0\0\x21\x08\
+\0\0\x08\xfc\x01\0\x68\xf3\0\0\xe1\x01\0\0\x21\x08\0\0\x08\xfc\x01\0\x70\xf3\0\
+\0\xe1\x01\0\0\x74\x08\0\0\x10\x08\x02\0\x78\xf3\0\0\xe1\x01\0\0\x74\x08\0\0\
+\x19\x08\x02\0\x90\xf3\0\0\xe1\x01\0\0\x74\x08\0\0\x09\x08\x02\0\x98\xf3\0\0\
+\xe1\x01\0\0\x91\x08\0\0\x0f\x0c\x02\0\xa0\xf3\0\0\xe1\x01\0\0\x7d\x07\0\0\x03\
+\xec\x01\0\0\xf4\0\0\xe1\x01\0\0\x21\x08\0\0\x08\xfc\x01\0\x38\xf4\0\0\xe1\x01\
+\0\0\x21\x08\0\0\x08\xfc\x01\0\x40\xf4\0\0\xe1\x01\0\0\x74\x08\0\0\x10\x08\x02\
+\0\x48\xf4\0\0\xe1\x01\0\0\x74\x08\0\0\x19\x08\x02\0\x60\xf4\0\0\xe1\x01\0\0\
+\x74\x08\0\0\x09\x08\x02\0\x68\xf4\0\0\xe1\x01\0\0\x91\x08\0\0\x0f\x0c\x02\0\
+\x70\xf4\0\0\xe1\x01\0\0\x7d\x07\0\0\x03\xec\x01\0\xd0\xf4\0\0\xe1\x01\0\0\x21\
+\x08\0\0\x08\xfc\x01\0\x08\xf5\0\0\xe1\x01\0\0\x21\x08\0\0\x08\xfc\x01\0\x10\
+\xf5\0\0\xe1\x01\0\0\x74\x08\0\0\x10\x08\x02\0\x18\xf5\0\0\xe1\x01\0\0\x74\x08\
+\0\0\x19\x08\x02\0\x30\xf5\0\0\xe1\x01\0\0\x74\x08\0\0\x09\x08\x02\0\x38\xf5\0\
+\0\xe1\x01\0\0\x91\x08\0\0\x0f\x0c\x02\0\x50\xf5\0\0\xe1\x01\0\0\x7d\x07\0\0\
+\x03\xec\x01\0\xa0\xf5\0\0\xe1\x01\0\0\0\0\0\0\0\0\0\0\xc8\xf5\0\0\xe1\x01\0\0\
+\xb2\x03\0\0\x02\x0c\x04\0\x10\xf6\0\0\xe1\x01\0\0\xa9\x08\0\0\x06\x10\x04\0\
+\x20\xf6\0\0\xe1\x01\0\0\xb6\x08\0\0\x37\x18\x04\0\x70\xf6\0\0\xe1\x01\0\0\xf8\
+\x08\0\0\x1d\x64\x03\0\x78\xf6\0\0\xe1\x01\0\0\xf8\x08\0\0\x22\x64\x03\0\x80\
+\xf6\0\0\xe1\x01\0\0\xb6\x08\0\0\x16\x18\x04\0\x90\xf6\0\0\xe1\x01\0\0\x21\x09\
+\0\0\x03\x1c\x04\0\xb8\xf6\0\0\xe1\x01\0\0\x51\x09\0\0\x01\x2c\x04\0\0\0\0\0\
+\x0c\0\0\0\xff\xff\xff\xff\x04\0\x08\0\x08\x7c\x0b\0\x14\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\xc8\xf6\0\0\0\0\0\0\x42\x53\0\0\x05\0\x08\0\x04\x01\0\0\x08\x01\x01\
+\xfb\x0e\x0d\0\x01\x01\x01\x01\0\0\0\x01\0\0\x01\x01\x01\x1f\x05\0\0\0\0\x34\0\
+\0\0\x4d\0\0\0\x5e\0\0\0\x71\0\0\0\x03\x01\x1f\x02\x0f\x05\x1e\x0a\x76\0\0\0\0\
+\x7d\x90\x07\x95\xdc\xc9\x67\x4f\xcf\xbb\x6f\x3f\x2b\xd2\xe8\xc8\x80\0\0\0\x01\
+\xb8\x10\xf2\x70\x73\x3e\x10\x63\x19\xb6\x7e\xf5\x12\xc6\x24\x6e\x8b\0\0\0\x02\
+\x09\xcf\xcd\x71\x69\xc2\x4b\xec\x44\x8f\x30\x58\x2e\x8c\x6d\xb9\x9d\0\0\0\x03\
+\x45\xef\x27\x66\x4f\x0d\x65\x59\xb5\x38\x8d\xb0\x30\x2c\xf8\xe1\xa3\0\0\0\x04\
+\x66\xf9\xea\x68\xa9\x45\xdb\x13\xa1\xc0\x2a\xae\xb4\x07\x1f\x55\xad\0\0\0\x03\
+\xfc\xee\x41\x5b\xb1\x9d\xb8\xac\xb9\x68\xee\xda\x6f\x02\xfa\x29\xb2\0\0\0\x03\
+\xbf\x9f\xbc\x0e\x8f\x60\x92\x7f\xef\x9d\x89\x17\x53\x53\x75\xa6\xba\0\0\0\x03\
+\x14\x97\x78\xac\xe3\x0a\x1f\xf2\x08\xad\xc8\x78\x3f\xd0\x4b\x29\xbf\0\0\0\x03\
+\xd2\x88\xe3\x08\xe1\x42\xe5\x1c\x48\xe7\x42\x2f\x4f\xbb\xaa\x3f\xc6\0\0\0\x03\
+\x8b\xeb\xb7\x80\xb4\x5d\x3f\xe9\x32\xcc\x1d\x93\x4f\xa5\xf5\xfe\x04\0\0\x09\
+\x02\0\0\0\0\0\0\0\0\x03\xf0\x01\x01\x05\x07\x0a\x30\x05\x34\xa3\x05\x0a\x06\
+\x20\x05\0\x03\x88\x7e\x2e\x05\x02\x06\x03\xf9\x01\x20\x06\x03\x87\x7e\x2e\x05\
+\x0b\x06\x03\xfc\x01\x2e\x05\x06\x3d\x05\x03\x21\x06\x03\x82\x7e\x4a\x05\x2c\
+\x06\x03\xcb\x01\x3c\x05\x0b\x30\x05\x06\x06\x20\x03\xb3\x7e\x2e\x05\x02\x06\
+\x03\x83\x02\x20\x06\x03\xfd\x7d\x58\x05\x22\x06\x03\xce\x01\x3c\x06\x03\xb2\
+\x7e\x66\x03\xce\x01\x3c\x05\x06\x06\x03\xf9\x7e\x2e\x06\x3c\x05\0\x06\x03\x87\
+\x01\x20\x05\x0f\x03\x83\x7f\x66\x2d\x05\x10\x33\x05\x06\x06\x20\x03\xab\x7f\
+\x20\x05\x17\x06\x03\x2e\x4a\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\
+\x05\x1b\x20\x05\x19\x20\x05\x17\x06\x3b\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x03\x51\x2e\x05\x22\x06\x03\xd0\x01\x2e\x06\x03\xb0\x7e\x66\x03\xd0\x01\
+\x3c\x05\x06\x06\x03\x53\x2e\x06\x3c\x05\0\x06\x03\x2d\x20\x05\x1a\x03\x59\x66\
+\x06\x03\xd7\x7e\x2e\x06\x03\xa8\x01\x20\x06\x03\xd8\x7e\x2e\x06\x03\xa9\x01\
+\x20\x2d\x06\x03\xd8\x7e\x2e\x06\x03\xa9\x01\x20\x06\x03\xd7\x7e\x2e\x06\x03\
+\xa8\x01\x20\x2f\x06\x03\xd7\x7e\x2e\x06\x03\xa8\x01\x20\x05\x10\x32\x05\x06\
+\x06\x20\x03\xd4\x7e\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x4a\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x17\x06\x3b\x05\x08\x06\x3c\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x3c\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x3c\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x4a\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x3c\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x3c\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\0\x03\x51\x20\x05\x0f\x06\x03\x3b\x74\x05\x18\x06\x20\x05\x1d\x06\x03\x1e\
+\x20\x05\x24\x21\x05\x0e\x41\x05\x12\x06\x20\x05\x0e\x3c\x05\x07\x06\x21\x06\
+\x03\xa0\x7f\x4a\x03\xe0\0\x20\x03\xa0\x7f\x20\x05\x17\x06\x03\x2e\x3c\x05\x08\
+\x06\x3c\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x03\x51\x3c\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x1c\x06\x03\xb0\x01\x4a\x06\x03\xd0\x7e\x20\x05\x03\
+\x06\x03\xfb\0\x20\x05\x25\x03\x39\x3c\x06\x03\xcc\x7e\x2e\x05\x07\x06\x03\xb9\
+\x01\x3c\x06\x4a\x03\xc7\x7e\x20\x05\x17\x06\x03\x2e\x3c\x05\x08\x06\x3c\x05\
+\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x17\x06\x3b\x05\x08\
+\x06\x3c\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x4a\x05\x0d\x06\x21\x05\x19\
+\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x3c\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\
+\x06\x21\x05\x19\x06\x2e\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x4a\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x3c\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x3c\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x3c\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x2e\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x2e\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\
+\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\
+\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\
+\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\
+\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\
+\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\
+\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\
+\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\
+\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\
+\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\
+\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\
+\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\
+\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\
+\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\
+\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\
+\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\
+\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\
+\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\
+\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\
+\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\
+\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\
+\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\
+\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\
+\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\
+\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\
+\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\
+\x2e\x20\x05\x08\x06\x2e\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\
+\x20\x05\x0a\x3c\x03\x51\x20\x05\x17\x06\x03\x2e\x20\x05\x08\x06\x2e\x05\x0d\
+\x06\x21\x05\x19\x06\x20\x05\x1b\x20\x05\x19\x20\x05\x0a\x3c\x03\x51\x20\x05\
+\x17\x06\x03\x2e\x3c\x05\x08\x06\x20\x05\x0d\x06\x21\x05\x19\x06\x20\x05\x1b\
+\x20\x05\x03\x06\x03\xcc\0\x2e\x06\x03\x85\x7f\x2e\x05\x08\x06\x03\xff\0\x2e\
+\x06\x58\x05\x10\x06\x23\x05\x19\x06\x20\x05\x09\x20\x05\x0f\x06\x2f\x05\x03\
+\x03\x78\x20\x06\x03\x85\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\x3c\x03\xfb\0\x20\
+\x03\x85\x7f\x2e\x05\x08\x06\x03\xff\0\x2e\x06\x58\x05\x10\x06\x23\x05\x19\x06\
+\x20\x05\x09\x3c\x05\x0f\x06\x21\x05\x03\x03\x78\x20\x06\x03\x85\x7f\x20\x03\
+\xfb\0\x20\x03\x85\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\x2e\x03\xfb\0\x2e\x03\x85\
+\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\x20\x05\x08\x06\x03\xff\0\x20\x06\x74\x05\
+\x10\x06\x23\x05\x19\x06\x20\x05\x09\x3c\x05\x0f\x06\x21\x05\x03\x03\x78\x20\
+\x06\x03\x85\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\
+\x2e\x03\xfb\0\x2e\x03\x85\x7f\x20\x03\xfb\0\x20\x03\x85\x7f\x20\x05\x08\x06\
+\x03\xff\0\x20\x06\x74\x05\x10\x06\x23\x05\x19\x06\x20\x05\x09\x3c\x05\x0f\x06\
+\x21\x06\x03\xfd\x7e\x20\x05\x03\x06\x03\xfb\0\x2e\x06\x03\x85\x7f\x20\x05\x02\
+\x06\x03\x83\x02\xd6\x06\x03\xfd\x7d\x66\x03\x83\x02\x20\x05\x06\x06\x2f\x06\
+\x03\xfc\x7d\x20\x05\x37\x06\x03\x86\x02\x20\x05\x1d\x03\x53\x9e\x05\x22\x06\
+\x20\x05\x16\x06\x03\x2d\x20\x05\x03\x2f\x06\x03\xf9\x7d\x4a\x05\x01\x06\x03\
+\x8b\x02\x20\x02\x02\0\x01\x01\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x65\x6d\x6d\x69\
+\x6e\x67\x65\x72\x2f\x44\x50\x44\x4b\x2f\x74\x61\x70\x2f\x66\x69\x78\x69\x74\
+\x2f\x64\x72\x69\x76\x65\x72\x73\x2f\x6e\x65\x74\x2f\x74\x61\x70\x2f\x62\x70\
+\x66\0\x2f\x75\x73\x72\x2f\x69\x6e\x63\x6c\x75\x64\x65\x2f\x61\x73\x6d\x2d\x67\
+\x65\x6e\x65\x72\x69\x63\0\x2f\x75\x73\x72\x2f\x69\x6e\x63\x6c\x75\x64\x65\x2f\
+\x62\x70\x66\0\x2f\x75\x73\x72\x2f\x69\x6e\x63\x6c\x75\x64\x65\x2f\x6c\x69\x6e\
+\x75\x78\0\x2e\x2f\x2e\x2e\0\x74\x61\x70\x5f\x72\x73\x73\x2e\x63\0\x69\x6e\x74\
+\x2d\x6c\x6c\x36\x34\x2e\x68\0\x62\x70\x66\x5f\x68\x65\x6c\x70\x65\x72\x5f\x64\
+\x65\x66\x73\x2e\x68\0\x62\x70\x66\x2e\x68\0\x74\x61\x70\x5f\x72\x73\x73\x2e\
+\x68\0\x69\x6e\x2e\x68\0\x74\x79\x70\x65\x73\x2e\x68\0\x69\x70\x2e\x68\0\x69\
+\x70\x76\x36\x2e\x68\0\x69\x6e\x36\x2e\x68\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x11\x01\0\0\x04\0\xf1\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x73\x11\0\0\0\0\x03\
+\0\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x22\0\0\0\x01\0\x07\0\0\0\0\0\0\0\0\0\x1b\
+\0\0\0\0\0\0\0\x6a\x16\0\0\0\0\x03\0\xb8\xf6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x49\
+\x0b\0\0\0\0\x03\0\x58\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x53\x0f\0\0\0\0\x03\0\
+\x78\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\x16\0\0\x01\0\x07\0\x1b\0\0\0\0\0\0\0\
+\x09\0\0\0\0\0\0\0\x1c\x14\0\0\0\0\x03\0\xc8\xf5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x09\x11\0\0\0\0\x03\0\xb0\x6f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3c\x01\0\0\0\0\x03\
+\0\xb0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x62\x16\0\0\0\0\x03\0\x10\x03\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x35\x11\0\0\0\0\x03\0\x70\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x29\x0c\0\0\0\0\x03\0\xd0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x28\x07\0\0\0\0\x03\
+\0\x30\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x25\x02\0\0\0\0\x03\0\x90\x04\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x3f\x16\0\0\0\0\x03\0\xf0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x12\x11\0\0\0\0\x03\0\x50\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\x0c\0\0\0\0\x03\
+\0\xb0\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x05\x07\0\0\0\0\x03\0\x10\x06\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x0b\x02\0\0\0\0\x03\0\x70\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x1c\x16\0\0\0\0\x03\0\xd0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xef\x10\0\0\0\0\x03\
+\0\x30\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf5\x0b\0\0\0\0\x03\0\x90\x07\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xeb\x06\0\0\0\0\x03\0\xf0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xe8\x01\0\0\0\0\x03\0\x50\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x16\0\0\0\0\x03\
+\0\xb0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcc\x10\0\0\0\0\x03\0\x10\x09\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xd2\x0b\0\0\0\0\x03\0\x70\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xd1\x06\0\0\0\0\x03\0\xd0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc5\x01\0\0\0\0\x03\
+\0\x30\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdf\x15\0\0\0\0\x03\0\x90\x0a\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xb2\x10\0\0\0\0\x03\0\xf0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xb8\x0b\0\0\0\0\x03\0\x50\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\x06\0\0\0\0\x03\
+\0\xb0\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xab\x01\0\0\0\0\x03\0\x10\x0c\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xc5\x15\0\0\0\0\x03\0\x70\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x98\x10\0\0\0\0\x03\0\xd0\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9e\x0b\0\0\0\0\x03\
+\0\x30\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9d\x06\0\0\0\0\x03\0\x90\x0d\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x91\x01\0\0\0\0\x03\0\xe8\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xab\x15\0\0\0\0\x03\0\x48\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7e\x10\0\0\0\0\x03\
+\0\xa0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x0b\0\0\0\0\x03\0\xf8\x0e\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x83\x06\0\0\0\0\x03\0\x50\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x77\x01\0\0\0\0\x03\0\xa8\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x15\0\0\0\0\x03\
+\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\x10\0\0\0\0\x03\0\x58\x10\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x6a\x0b\0\0\0\0\x03\0\xb0\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x69\
+\x06\0\0\0\0\x03\0\x08\x11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5d\x01\0\0\0\0\x03\0\
+\x60\x11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x77\x15\0\0\0\0\x03\0\xb8\x11\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x4a\x10\0\0\0\0\x03\0\x10\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x50\
+\x0b\0\0\0\0\x03\0\x68\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4f\x06\0\0\0\0\x03\0\
+\xc0\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x43\x01\0\0\0\0\x03\0\x18\x13\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xa1\x16\0\0\0\0\x03\0\x70\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6a\
+\x11\0\0\0\0\x03\0\xc8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5e\x0c\0\0\0\0\x03\0\
+\x20\x14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5d\x07\0\0\0\0\x03\0\x78\x14\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x5a\x02\0\0\0\0\x03\0\xd0\x14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86\
+\x16\0\0\0\0\x03\0\x28\x15\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4f\x11\0\0\0\0\x03\0\
+\x80\x15\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x43\x0c\0\0\0\0\x03\0\xd8\x15\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x42\x07\0\0\0\0\x03\0\x30\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\
+\x02\0\0\0\0\x03\0\x88\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x59\x16\0\0\0\0\x03\0\
+\xe0\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2c\x11\0\0\0\0\x03\0\x38\x17\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x20\x0c\0\0\0\0\x03\0\x90\x17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1f\
+\x07\0\0\0\0\x03\0\xe8\x17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1c\x02\0\0\0\0\x03\0\
+\x40\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x36\x16\0\0\0\0\x03\0\x78\x6f\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x42\x14\0\0\0\0\x03\0\x80\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\
+\x05\0\0\0\0\x03\0\x50\x1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x19\0\0\0\0\x03\0\
+\xb0\x1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\x13\0\0\0\0\x03\0\x10\x1b\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xf5\x0e\0\0\0\0\x03\0\x68\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf4\
+\x09\0\0\0\0\x03\0\xc0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfa\x04\0\0\0\0\x03\0\
+\x18\x1c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfa\x18\0\0\0\0\x03\0\x70\x1c\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xa1\x13\0\0\0\0\x03\0\xc8\x1c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x97\
+\x0e\0\0\0\0\x03\0\x20\x1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96\x09\0\0\0\0\x03\0\
+\x78\x1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9c\x04\0\0\0\0\x03\0\xd0\x1d\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x9c\x18\0\0\0\0\x03\0\x28\x1e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x43\
+\x13\0\0\0\0\x03\0\x80\x1e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x39\x0e\0\0\0\0\x03\0\
+\xd8\x1e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x38\x09\0\0\0\0\x03\0\x30\x1f\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x35\x04\0\0\0\0\x03\0\x88\x1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3e\
+\x18\0\0\0\0\x03\0\xe0\x1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe5\x12\0\0\0\0\x03\0\
+\x38\x20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd2\x0d\0\0\0\0\x03\0\x90\x20\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xd1\x08\0\0\0\0\x03\0\xe8\x20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xce\
+\x03\0\0\0\0\x03\0\x40\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd7\x17\0\0\0\0\x03\0\
+\x98\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7e\x12\0\0\0\0\x03\0\xf0\x21\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x6b\x0d\0\0\0\0\x03\0\x48\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6a\
+\x08\0\0\0\0\x03\0\xa0\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x67\x03\0\0\0\0\x03\0\
+\xf8\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\x17\0\0\0\0\x03\0\x50\x23\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x17\x12\0\0\0\0\x03\0\xa8\x23\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\
+\x0d\0\0\0\0\x03\0\0\x24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\x08\0\0\0\0\x03\0\x58\
+\x24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x03\0\xa8\x24\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\x09\x17\0\0\0\0\x03\0\x10\x25\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb0\x11\0\
+\0\0\0\x03\0\x70\x25\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9d\x0c\0\0\0\0\x03\0\xc8\x25\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9c\x07\0\0\0\0\x03\0\x20\x26\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\x99\x02\0\0\0\0\x03\0\x78\x26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x72\x1a\0\0\
+\0\0\x03\0\xd0\x26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x22\x15\0\0\0\0\x03\0\x28\x27\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x0f\x10\0\0\0\0\x03\0\x80\x27\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x0e\x0b\0\0\0\0\x03\0\xd8\x27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14\x06\0\0\0\
+\0\x03\0\x30\x28\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14\x1a\0\0\0\0\x03\0\x88\x28\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\xc4\x14\0\0\0\0\x03\0\xe0\x28\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\xb1\x0f\0\0\0\0\x03\0\x38\x29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb0\x0a\0\0\0\0\
+\x03\0\x90\x29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb6\x05\0\0\0\0\x03\0\xe8\x29\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xb6\x19\0\0\0\0\x03\0\x40\x2a\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x66\x14\0\0\0\0\x03\0\x98\x2a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4a\x0f\0\0\0\0\
+\x03\0\xf0\x2a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x52\x0a\0\0\0\0\x03\0\x48\x2b\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x4f\x05\0\0\0\0\x03\0\xa0\x2b\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x4f\x19\0\0\0\0\x03\0\xf8\x2b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf6\x13\0\0\0\0\
+\x03\0\x50\x2c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xec\x0e\0\0\0\0\x03\0\xa8\x2c\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xeb\x09\0\0\0\0\x03\0\0\x2d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xf1\x04\0\0\0\0\x03\0\x58\x2d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf1\x18\0\0\0\0\x03\
+\0\xb0\x2d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x13\0\0\0\0\x03\0\x08\x2e\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x8e\x0e\0\0\0\0\x03\0\x60\x2e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x8d\x09\0\0\0\0\x03\0\xb8\x2e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x04\0\0\0\0\x03\
+\0\x10\x2f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x18\0\0\0\0\x03\0\x60\x2f\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x3a\x13\0\0\0\0\x03\0\xd0\x2f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x30\x0e\0\0\0\0\x03\0\x28\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2f\x09\0\0\0\0\x03\
+\0\x80\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2c\x04\0\0\0\0\x03\0\xd8\x30\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x35\x18\0\0\0\0\x03\0\x30\x31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xdc\x12\0\0\0\0\x03\0\x88\x31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc9\x0d\0\0\0\0\x03\
+\0\xe0\x31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc8\x08\0\0\0\0\x03\0\x38\x32\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xc5\x03\0\0\0\0\x03\0\x90\x32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xce\x17\0\0\0\0\x03\0\xe8\x32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x75\x12\0\0\0\0\x03\
+\0\x40\x33\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x62\x0d\0\0\0\0\x03\0\x98\x33\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x61\x08\0\0\0\0\x03\0\xf0\x33\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x5e\x03\0\0\0\0\x03\0\x48\x34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x67\x17\0\0\0\0\x03\
+\0\xa0\x34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0e\x12\0\0\0\0\x03\0\xf8\x34\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xfb\x0c\0\0\0\0\x03\0\x50\x35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xfa\x07\0\0\0\0\x03\0\xa8\x35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf7\x02\0\0\0\0\x03\
+\0\0\x36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\0\0\0\0\x03\0\x58\x36\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\xa7\x11\0\0\0\0\x03\0\xb0\x36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\
+\x0c\0\0\0\0\x03\0\x08\x37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x07\0\0\0\0\x03\0\
+\x60\x37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x02\0\0\0\0\x03\0\xb8\x37\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x69\x1a\0\0\0\0\x03\0\x10\x38\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x19\
+\x15\0\0\0\0\x03\0\x68\x38\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\x10\0\0\0\0\x03\0\
+\xc0\x38\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x05\x0b\0\0\0\0\x03\0\x18\x39\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x0b\x06\0\0\0\0\x03\0\x70\x39\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0b\
+\x1a\0\0\0\0\x03\0\xc8\x39\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbb\x14\0\0\0\0\x03\0\
+\x20\x3a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa8\x0f\0\0\0\0\x03\0\x88\x3a\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xa7\x0a\0\0\0\0\x03\0\xe0\x3a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xad\
+\x05\0\0\0\0\x03\0\x38\x3b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xad\x19\0\0\0\0\x03\0\
+\x90\x3b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5d\x14\0\0\0\0\x03\0\xe8\x3b\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x41\x0f\0\0\0\0\x03\0\x40\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x49\
+\x0a\0\0\0\0\x03\0\x98\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x46\x05\0\0\0\0\x03\0\
+\xf0\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x46\x19\0\0\0\0\x03\0\x48\x3d\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xed\x13\0\0\0\0\x03\0\xa0\x3d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe3\
+\x0e\0\0\0\0\x03\0\xf8\x3d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe2\x09\0\0\0\0\x03\0\
+\x50\x3e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe8\x04\0\0\0\0\x03\0\xa8\x3e\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xe8\x18\0\0\0\0\x03\0\0\x3f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8f\
+\x13\0\0\0\0\x03\0\x58\x3f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\x0e\0\0\0\0\x03\0\
+\xb0\x3f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x09\0\0\0\0\x03\0\x08\x40\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x8a\x04\0\0\0\0\x03\0\x60\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8a\
+\x18\0\0\0\0\x03\0\xb8\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x31\x13\0\0\0\0\x03\0\
+\x10\x41\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x27\x0e\0\0\0\0\x03\0\x68\x41\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x26\x09\0\0\0\0\x03\0\xc0\x41\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x23\
+\x04\0\0\0\0\x03\0\x18\x42\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2c\x18\0\0\0\0\x03\0\
+\x70\x42\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\x12\0\0\0\0\x03\0\xc8\x42\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xc0\x0d\0\0\0\0\x03\0\x20\x43\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbf\
+\x08\0\0\0\0\x03\0\x78\x43\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x03\0\0\0\0\x03\0\
+\xd0\x43\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc5\x17\0\0\0\0\x03\0\x28\x44\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x6c\x12\0\0\0\0\x03\0\x80\x44\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x59\
+\x0d\0\0\0\0\x03\0\xd0\x44\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x08\0\0\0\0\x03\0\
+\x38\x45\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x55\x03\0\0\0\0\x03\0\x90\x45\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x5e\x17\0\0\0\0\x03\0\xe8\x45\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x05\
+\x12\0\0\0\0\x03\0\x40\x46\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf2\x0c\0\0\0\0\x03\0\
+\x98\x46\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf1\x07\0\0\0\0\x03\0\xf0\x46\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xee\x02\0\0\0\0\x03\0\x48\x47\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf7\
+\x16\0\0\0\0\x03\0\xa0\x47\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9e\x11\0\0\0\0\x03\0\
+\xf8\x47\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\x0c\0\0\0\0\x03\0\x50\x48\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x8a\x07\0\0\0\0\x03\0\xa8\x48\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87\
+\x02\0\0\0\0\x03\0\0\x49\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x1a\0\0\0\0\x03\0\x58\
+\x49\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\x15\0\0\0\0\x03\0\xb0\x49\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xfd\x0f\0\0\0\0\x03\0\x08\x4a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfc\x0a\
+\0\0\0\0\x03\0\x60\x4a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x06\0\0\0\0\x03\0\xb8\
+\x4a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x1a\0\0\0\0\x03\0\x10\x4b\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xb2\x14\0\0\0\0\x03\0\x68\x4b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\x0f\
+\0\0\0\0\x03\0\xc0\x4b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9e\x0a\0\0\0\0\x03\0\x18\
+\x4c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa4\x05\0\0\0\0\x03\0\x70\x4c\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xa4\x19\0\0\0\0\x03\0\xc8\x4c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x14\
+\0\0\0\0\x03\0\x20\x4d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\0\0\x03\0\x78\
+\x4d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\x0a\0\0\0\0\x03\0\xd0\x4d\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x3d\x05\0\0\0\0\x03\0\x28\x4e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3d\x19\
+\0\0\0\0\x03\0\x80\x4e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe4\x13\0\0\0\0\x03\0\xd8\
+\x4e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xda\x0e\0\0\0\0\x03\0\x30\x4f\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xd9\x09\0\0\0\0\x03\0\x80\x4f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdf\x04\
+\0\0\0\0\x03\0\xe8\x4f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdf\x18\0\0\0\0\x03\0\x40\
+\x50\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86\x13\0\0\0\0\x03\0\x98\x50\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x7c\x0e\0\0\0\0\x03\0\xf0\x50\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7b\x09\
+\0\0\0\0\x03\0\x48\x51\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x04\0\0\0\0\x03\0\xa0\
+\x51\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x18\0\0\0\0\x03\0\xf8\x51\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x28\x13\0\0\0\0\x03\0\x50\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1e\x0e\
+\0\0\0\0\x03\0\xa8\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1d\x09\0\0\0\0\x03\0\0\x53\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\x04\0\0\0\0\x03\0\x58\x53\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\x23\x18\0\0\0\0\x03\0\xb0\x53\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xca\x12\0\0\
+\0\0\x03\0\x08\x54\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\x0d\0\0\0\0\x03\0\x60\x54\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\xb6\x08\0\0\0\0\x03\0\xb8\x54\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\xb3\x03\0\0\0\0\x03\0\x10\x55\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x17\0\0\0\
+\0\x03\0\x68\x55\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x12\0\0\0\0\x03\0\xc0\x55\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x50\x0d\0\0\0\0\x03\0\x18\x56\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\x4f\x08\0\0\0\0\x03\0\x70\x56\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4c\x03\0\0\0\0\
+\x03\0\xc8\x56\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x55\x17\0\0\0\0\x03\0\x20\x57\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xfc\x11\0\0\0\0\x03\0\x78\x57\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\xe9\x0c\0\0\0\0\x03\0\xd0\x57\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe8\x07\0\0\0\0\
+\x03\0\x28\x58\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe5\x02\0\0\0\0\x03\0\x80\x58\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xee\x16\0\0\0\0\x03\0\xd8\x58\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x95\x11\0\0\0\0\x03\0\x30\x59\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x0c\0\0\0\0\
+\x03\0\x88\x59\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x07\0\0\0\0\x03\0\xe0\x59\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x7e\x02\0\0\0\0\x03\0\x30\x5a\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x57\x1a\0\0\0\0\x03\0\x98\x5a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x07\x15\0\0\0\0\
+\x03\0\xf8\x5a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf4\x0f\0\0\0\0\x03\0\x50\x5b\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xf3\x0a\0\0\0\0\x03\0\xa8\x5b\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\xf9\x05\0\0\0\0\x03\0\0\x5c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf9\x19\0\0\0\0\x03\
+\0\x58\x5c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa9\x14\0\0\0\0\x03\0\xb0\x5c\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x96\x0f\0\0\0\0\x03\0\x08\x5d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x95\x0a\0\0\0\0\x03\0\x60\x5d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\x05\0\0\0\0\x03\
+\0\xb8\x5d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\x19\0\0\0\0\x03\0\x10\x5e\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x4b\x14\0\0\0\0\x03\0\x68\x5e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x2f\x0f\0\0\0\0\x03\0\xc0\x5e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x37\x0a\0\0\0\0\x03\
+\0\x18\x5f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x34\x05\0\0\0\0\x03\0\x70\x5f\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x34\x19\0\0\0\0\x03\0\xc8\x5f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xdb\x13\0\0\0\0\x03\0\x20\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd1\x0e\0\0\0\0\x03\
+\0\x78\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd0\x09\0\0\0\0\x03\0\xd0\x60\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xd6\x04\0\0\0\0\x03\0\x28\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xd6\x18\0\0\0\0\x03\0\x80\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7d\x13\0\0\0\0\x03\
+\0\xd8\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x73\x0e\0\0\0\0\x03\0\x30\x62\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x72\x09\0\0\0\0\x03\0\x88\x62\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x78\x04\0\0\0\0\x03\0\xe0\x62\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\x18\0\0\0\0\x03\
+\0\x38\x63\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1f\x13\0\0\0\0\x03\0\x90\x63\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x15\x0e\0\0\0\0\x03\0\xe8\x63\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x14\x09\0\0\0\0\x03\0\x40\x64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x11\x04\0\0\0\0\x03\
+\0\x98\x64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\x18\0\0\0\0\x03\0\xe8\x64\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xc1\x12\0\0\0\0\x03\0\x48\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xae\x0d\0\0\0\0\x03\0\xa0\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xad\x08\0\0\0\0\x03\
+\0\xf8\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\x03\0\0\0\0\x03\0\x50\x66\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xb3\x17\0\0\0\0\x03\0\xa8\x66\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x5a\x12\0\0\0\0\x03\0\0\x67\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x0d\0\0\0\0\x03\0\
+\x58\x67\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x46\x08\0\0\0\0\x03\0\xb0\x67\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x43\x03\0\0\0\0\x03\0\x08\x68\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4c\
+\x17\0\0\0\0\x03\0\x60\x68\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf3\x11\0\0\0\0\x03\0\
+\xb8\x68\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe0\x0c\0\0\0\0\x03\0\x10\x69\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xdf\x07\0\0\0\0\x03\0\x68\x69\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdc\
+\x02\0\0\0\0\x03\0\xc0\x69\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe5\x16\0\0\0\0\x03\0\
+\x18\x6a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8c\x11\0\0\0\0\x03\0\x70\x6a\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x79\x0c\0\0\0\0\x03\0\xc8\x6a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\
+\x07\0\0\0\0\x03\0\x20\x6b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x75\x02\0\0\0\0\x03\0\
+\x78\x6b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4e\x1a\0\0\0\0\x03\0\xd0\x6b\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xfe\x14\0\0\0\0\x03\0\x28\x6c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xeb\
+\x0f\0\0\0\0\x03\0\x80\x6c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\x0a\0\0\0\0\x03\0\
+\xd8\x6c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf0\x05\0\0\0\0\x03\0\x30\x6d\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xf0\x19\0\0\0\0\x03\0\x88\x6d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\
+\x14\0\0\0\0\x03\0\xe0\x6d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8d\x0f\0\0\0\0\x03\0\
+\x38\x6e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8c\x0a\0\0\0\0\x03\0\x90\x6e\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x92\x05\0\0\0\0\x03\0\xe8\x6e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92\
+\x19\0\0\0\0\x03\0\x40\x6f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x11\x0a\0\0\0\0\x03\0\
+\xe0\x6f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\x11\0\0\0\0\x03\0\x70\x90\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x02\x02\0\0\0\0\x03\0\xa8\x70\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x13\
+\x16\0\0\0\0\x03\0\0\x71\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe6\x10\0\0\0\0\x03\0\x58\
+\x71\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xec\x0b\0\0\0\0\x03\0\xb0\x71\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xe2\x06\0\0\0\0\x03\0\x08\x72\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdf\x01\
+\0\0\0\0\x03\0\x60\x72\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf9\x15\0\0\0\0\x03\0\xb8\
+\x72\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc3\x10\0\0\0\0\x03\0\x10\x73\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xc9\x0b\0\0\0\0\x03\0\x68\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc8\x06\
+\0\0\0\0\x03\0\xc0\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x01\0\0\0\0\x03\0\x18\
+\x74\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd6\x15\0\0\0\0\x03\0\x70\x74\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xa9\x10\0\0\0\0\x03\0\xc8\x74\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaf\x0b\
+\0\0\0\0\x03\0\x20\x75\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xae\x06\0\0\0\0\x03\0\x78\
+\x75\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa2\x01\0\0\0\0\x03\0\xd0\x75\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xbc\x15\0\0\0\0\x03\0\x28\x76\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8f\x10\
+\0\0\0\0\x03\0\x80\x76\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95\x0b\0\0\0\0\x03\0\xd8\
+\x76\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\x06\0\0\0\0\x03\0\x30\x77\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x88\x01\0\0\0\0\x03\0\x88\x77\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa2\x15\
+\0\0\0\0\x03\0\xe0\x77\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x75\x10\0\0\0\0\x03\0\x38\
+\x78\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7b\x0b\0\0\0\0\x03\0\x90\x78\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x7a\x06\0\0\0\0\x03\0\xe8\x78\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6e\x01\
+\0\0\0\0\x03\0\x40\x79\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x15\0\0\0\0\x03\0\x98\
+\x79\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x10\0\0\0\0\x03\0\xf0\x79\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x61\x0b\0\0\0\0\x03\0\x48\x7a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x06\
+\0\0\0\0\x03\0\xa0\x7a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x01\0\0\0\0\x03\0\xf0\
+\x7a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x16\0\0\0\0\x03\0\x58\x7b\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x61\x11\0\0\0\0\x03\0\xb0\x7b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x55\x0c\
+\0\0\0\0\x03\0\x08\x7c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x07\0\0\0\0\x03\0\x60\
+\x7c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x51\x02\0\0\0\0\x03\0\xb8\x7c\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x7d\x16\0\0\0\0\x03\0\x10\x7d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x46\x11\
+\0\0\0\0\x03\0\x68\x7d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3a\x0c\0\0\0\0\x03\0\xc0\
+\x7d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x39\x07\0\0\0\0\x03\0\x18\x7e\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x36\x02\0\0\0\0\x03\0\x70\x7e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x50\x16\
+\0\0\0\0\x03\0\xc8\x7e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x23\x11\0\0\0\0\x03\0\x20\
+\x7f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x0c\0\0\0\0\x03\0\x78\x7f\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x16\x07\0\0\0\0\x03\0\xd0\x7f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x13\x02\
+\0\0\0\0\x03\0\x28\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2d\x16\0\0\0\0\x03\0\x80\
+\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x11\0\0\0\0\x03\0\xd8\x80\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\xfd\x0b\0\0\0\0\x03\0\x30\x81\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfc\x06\0\
+\0\0\0\x03\0\x88\x81\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf9\x01\0\0\0\0\x03\0\xe0\x81\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\x16\0\0\0\0\x03\0\x38\x82\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\xdd\x10\0\0\0\0\x03\0\x90\x82\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe3\x0b\0\0\
+\0\0\x03\0\xe8\x82\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd9\x06\0\0\0\0\x03\0\x40\x83\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\xd6\x01\0\0\0\0\x03\0\x98\x83\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\xf0\x15\0\0\0\0\x03\0\xf0\x83\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xba\x10\0\0\0\
+\0\x03\0\x48\x84\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc0\x0b\0\0\0\0\x03\0\xa8\x84\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\xbf\x06\0\0\0\0\x03\0\x10\x85\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\xb3\x01\0\0\0\0\x03\0\x70\x85\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x15\0\0\0\0\
+\x03\0\xc8\x85\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x10\0\0\0\0\x03\0\x28\x86\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xa6\x0b\0\0\0\0\x03\0\x80\x86\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\xa5\x06\0\0\0\0\x03\0\xd8\x86\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x99\x01\0\0\0\0\
+\x03\0\x30\x87\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb3\x15\0\0\0\0\x03\0\x88\x87\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x86\x10\0\0\0\0\x03\0\xe0\x87\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x8c\x0b\0\0\0\0\x03\0\x38\x88\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\x06\0\0\0\0\
+\x03\0\x90\x88\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7f\x01\0\0\0\0\x03\0\xe8\x88\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x99\x15\0\0\0\0\x03\0\x40\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x6c\x10\0\0\0\0\x03\0\x98\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x72\x0b\0\0\0\0\
+\x03\0\xf0\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x71\x06\0\0\0\0\x03\0\x48\x8a\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x65\x01\0\0\0\0\x03\0\xa0\x8a\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x7f\x15\0\0\0\0\x03\0\xf8\x8a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x52\x10\0\0\0\0\
+\x03\0\x50\x8b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x0b\0\0\0\0\x03\0\xa8\x8b\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x57\x06\0\0\0\0\x03\0\0\x8c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x4b\x01\0\0\0\0\x03\0\x58\x8c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8f\x16\0\0\0\0\x03\
+\0\xb0\x8c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x11\0\0\0\0\x03\0\x08\x8d\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x4c\x0c\0\0\0\0\x03\0\x60\x8d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x4b\x07\0\0\0\0\x03\0\xb8\x8d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\x02\0\0\0\0\x03\
+\0\x10\x8e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\x16\0\0\0\0\x03\0\x68\x8e\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x3d\x11\0\0\0\0\x03\0\xc0\x8e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x31\x0c\0\0\0\0\x03\0\x18\x8f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x30\x07\0\0\0\0\x03\
+\0\x70\x8f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2d\x02\0\0\0\0\x03\0\xc8\x8f\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x47\x16\0\0\0\0\x03\0\x20\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x0e\x0c\0\0\0\0\x03\0\x78\xf2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0d\x07\0\0\0\0\x03\
+\0\x88\xf2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x01\0\0\0\0\x03\0\xb0\x90\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xe7\x15\0\0\0\0\x03\0\xc0\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x0c\x0e\0\0\0\0\x03\0\x70\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0b\x09\0\0\0\0\x03\
+\0\xd8\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\x04\0\0\0\0\x03\0\x48\x92\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x11\x18\0\0\0\0\x03\0\xb0\x92\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xb8\x12\0\0\0\0\x03\0\x10\x93\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa5\x0d\0\0\0\0\x03\
+\0\x70\x93\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa4\x08\0\0\0\0\x03\0\xd0\x93\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xa1\x03\0\0\0\0\x03\0\x30\x94\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xaa\x17\0\0\0\0\x03\0\x90\x94\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x51\x12\0\0\0\0\x03\
+\0\xf0\x94\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3e\x0d\0\0\0\0\x03\0\x50\x95\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x3d\x08\0\0\0\0\x03\0\xb0\x95\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x3a\x03\0\0\0\0\x03\0\x10\x96\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x43\x17\0\0\0\0\x03\
+\0\x70\x96\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\x11\0\0\0\0\x03\0\xd0\x96\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xd7\x0c\0\0\0\0\x03\0\x30\x97\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xd6\x07\0\0\0\0\x03\0\x90\x97\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\x02\0\0\0\0\x03\
+\0\xf0\x97\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdc\x16\0\0\0\0\x03\0\x50\x98\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x83\x11\0\0\0\0\x03\0\xb0\x98\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x70\x0c\0\0\0\0\x03\0\x10\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6f\x07\0\0\0\0\x03\
+\0\x70\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6c\x02\0\0\0\0\x03\0\xd0\x99\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x45\x1a\0\0\0\0\x03\0\x30\x9a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xf5\x14\0\0\0\0\x03\0\x90\x9a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe2\x0f\0\0\0\0\x03\
+\0\xf0\x9a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe1\x0a\0\0\0\0\x03\0\x50\x9b\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xe7\x05\0\0\0\0\x03\0\xb0\x9b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xe7\x19\0\0\0\0\x03\0\x10\x9c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x97\x14\0\0\0\0\x03\
+\0\x70\x9c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x0f\0\0\0\0\x03\0\xc8\x9c\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x83\x0a\0\0\0\0\x03\0\x38\x9d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x89\x05\0\0\0\0\x03\0\x90\x9d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x19\0\0\0\0\x03\
+\0\xe8\x9d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x39\x14\0\0\0\0\x03\0\x40\x9e\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x26\x0f\0\0\0\0\x03\0\x98\x9e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x2e\x0a\0\0\0\0\x03\0\xf0\x9e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2b\x05\0\0\0\0\x03\
+\0\x48\x9f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2b\x19\0\0\0\0\x03\0\xa0\x9f\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xd2\x13\0\0\0\0\x03\0\xf8\x9f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xc8\x0e\0\0\0\0\x03\0\x50\xa0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc7\x09\0\0\0\0\x03\
+\0\xa8\xa0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x04\0\0\0\0\x03\0\0\xa1\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xcd\x18\0\0\0\0\x03\0\x58\xa1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\
+\x13\0\0\0\0\x03\0\xb0\xa1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6a\x0e\0\0\0\0\x03\0\
+\x08\xa2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x69\x09\0\0\0\0\x03\0\x60\xa2\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x66\x04\0\0\0\0\x03\0\xb8\xa2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6f\
+\x18\0\0\0\0\x03\0\x10\xa3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x13\0\0\0\0\x03\0\
+\x68\xa3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\x0e\0\0\0\0\x03\0\xc0\xa3\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x02\x09\0\0\0\0\x03\0\x18\xa4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\
+\x03\0\0\0\0\x03\0\x70\xa4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\x18\0\0\0\0\x03\0\
+\xc8\xa4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaf\x12\0\0\0\0\x03\0\x20\xa5\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x9c\x0d\0\0\0\0\x03\0\x78\xa5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\
+\x08\0\0\0\0\x03\0\xd0\xa5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x03\0\0\0\0\x03\0\
+\x28\xa6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa1\x17\0\0\0\0\x03\0\x80\xa6\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x48\x12\0\0\0\0\x03\0\xd8\xa6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x35\
+\x0d\0\0\0\0\x03\0\x30\xa7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x34\x08\0\0\0\0\x03\0\
+\x80\xa7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x31\x03\0\0\0\0\x03\0\xe8\xa7\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x3a\x17\0\0\0\0\x03\0\x40\xa8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe1\
+\x11\0\0\0\0\x03\0\x98\xa8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xce\x0c\0\0\0\0\x03\0\
+\xf0\xa8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x07\0\0\0\0\x03\0\x48\xa9\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xca\x02\0\0\0\0\x03\0\xa0\xa9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\
+\x16\0\0\0\0\x03\0\xf8\xa9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7a\x11\0\0\0\0\x03\0\
+\x50\xaa\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x67\x0c\0\0\0\0\x03\0\xa8\xaa\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x66\x07\0\0\0\0\x03\0\0\xab\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\
+\x02\0\0\0\0\x03\0\x58\xab\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa3\x1a\0\0\0\0\x03\0\
+\xb0\xab\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x53\x15\0\0\0\0\x03\0\x08\xac\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x40\x10\0\0\0\0\x03\0\x60\xac\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\
+\x0b\0\0\0\0\x03\0\xb8\xac\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x45\x06\0\0\0\0\x03\0\
+\x10\xad\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3b\x1a\0\0\0\0\x03\0\x68\xad\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xeb\x14\0\0\0\0\x03\0\xc0\xad\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd8\
+\x0f\0\0\0\0\x03\0\x18\xae\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd7\x0a\0\0\0\0\x03\0\
+\x70\xae\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdd\x05\0\0\0\0\x03\0\xc8\xae\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xdd\x19\0\0\0\0\x03\0\x20\xaf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8d\
+\x14\0\0\0\0\x03\0\x78\xaf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7a\x0f\0\0\0\0\x03\0\
+\xd0\xaf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x79\x0a\0\0\0\0\x03\0\x28\xb0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x7f\x05\0\0\0\0\x03\0\x80\xb0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7f\
+\x19\0\0\0\0\x03\0\xd8\xb0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2f\x14\0\0\0\0\x03\0\
+\x30\xb1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1c\x0f\0\0\0\0\x03\0\x88\xb1\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x24\x0a\0\0\0\0\x03\0\xe0\xb1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x21\
+\x05\0\0\0\0\x03\0\x38\xb2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x21\x19\0\0\0\0\x03\0\
+\xa0\xb2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc8\x13\0\0\0\0\x03\0\xf8\xb2\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xbe\x0e\0\0\0\0\x03\0\x50\xb3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbd\
+\x09\0\0\0\0\x03\0\xa8\xb3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc3\x04\0\0\0\0\x03\0\0\
+\xb4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc3\x18\0\0\0\0\x03\0\x58\xb4\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x6a\x13\0\0\0\0\x03\0\xb0\xb4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x0e\
+\0\0\0\0\x03\0\x08\xb5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5f\x09\0\0\0\0\x03\0\x60\
+\xb5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5c\x04\0\0\0\0\x03\0\xb8\xb5\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x65\x18\0\0\0\0\x03\0\x10\xb6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0c\x13\
+\0\0\0\0\x03\0\x68\xb6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf9\x0d\0\0\0\0\x03\0\xc0\
+\xb6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf8\x08\0\0\0\0\x03\0\x18\xb7\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xf5\x03\0\0\0\0\x03\0\x70\xb7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfe\x17\
+\0\0\0\0\x03\0\xc8\xb7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa5\x12\0\0\0\0\x03\0\x20\
+\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92\x0d\0\0\0\0\x03\0\x78\xb8\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x91\x08\0\0\0\0\x03\0\xd0\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8e\x03\
+\0\0\0\0\x03\0\x28\xb9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x97\x17\0\0\0\0\x03\0\x80\
+\xb9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3e\x12\0\0\0\0\x03\0\xd8\xb9\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x2b\x0d\0\0\0\0\x03\0\x30\xba\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2a\x08\
+\0\0\0\0\x03\0\x88\xba\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x27\x03\0\0\0\0\x03\0\xe0\
+\xba\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x30\x17\0\0\0\0\x03\0\x38\xbb\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xd7\x11\0\0\0\0\x03\0\x90\xbb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc4\x0c\
+\0\0\0\0\x03\0\xe8\xbb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc3\x07\0\0\0\0\x03\0\x40\
+\xbc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc0\x02\0\0\0\0\x03\0\x98\xbc\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x99\x1a\0\0\0\0\x03\0\xf0\xbc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x49\x15\
+\0\0\0\0\x03\0\x58\xbd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x36\x10\0\0\0\0\x03\0\xb0\
+\xbd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x35\x0b\0\0\0\0\x03\0\x08\xbe\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x3b\x06\0\0\0\0\x03\0\x60\xbe\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x31\x1a\
+\0\0\0\0\x03\0\xb8\xbe\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe1\x14\0\0\0\0\x03\0\x10\
+\xbf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xce\x0f\0\0\0\0\x03\0\x68\xbf\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xcd\x0a\0\0\0\0\x03\0\xc0\xbf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\x05\
+\0\0\0\0\x03\0\x18\xc0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\x19\0\0\0\0\x03\0\x70\
+\xc0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83\x14\0\0\0\0\x03\0\xc8\xc0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x70\x0f\0\0\0\0\x03\0\x20\xc1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6f\x0a\
+\0\0\0\0\x03\0\x78\xc1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x75\x05\0\0\0\0\x03\0\xd0\
+\xc1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x75\x19\0\0\0\0\x03\0\x28\xc2\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x25\x14\0\0\0\0\x03\0\x80\xc2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x12\x0f\
+\0\0\0\0\x03\0\xd8\xc2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\x0a\0\0\0\0\x03\0\x30\
+\xc3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x05\0\0\0\0\x03\0\x88\xc3\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x17\x19\0\0\0\0\x03\0\xe0\xc3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbe\x13\
+\0\0\0\0\x03\0\x38\xc4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb4\x0e\0\0\0\0\x03\0\x90\
+\xc4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb3\x09\0\0\0\0\x03\0\xe8\xc4\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xb9\x04\0\0\0\0\x03\0\x40\xc5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb9\x18\
+\0\0\0\0\x03\0\x98\xc5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x13\0\0\0\0\x03\0\xf0\
+\xc5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x56\x0e\0\0\0\0\x03\0\x48\xc6\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x55\x09\0\0\0\0\x03\0\xa0\xc6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x52\x04\
+\0\0\0\0\x03\0\xf8\xc6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x18\0\0\0\0\x03\0\x50\
+\xc7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x13\0\0\0\0\x03\0\xa0\xc7\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xef\x0d\0\0\0\0\x03\0\x08\xc8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xee\x08\
+\0\0\0\0\x03\0\x68\xc8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xeb\x03\0\0\0\0\x03\0\xc0\
+\xc8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf4\x17\0\0\0\0\x03\0\x18\xc9\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x9b\x12\0\0\0\0\x03\0\x70\xc9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x0d\
+\0\0\0\0\x03\0\xc8\xc9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87\x08\0\0\0\0\x03\0\x20\
+\xca\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x03\0\0\0\0\x03\0\x78\xca\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x8d\x17\0\0\0\0\x03\0\xd0\xca\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x34\x12\
+\0\0\0\0\x03\0\x28\xcb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x21\x0d\0\0\0\0\x03\0\x80\
+\xcb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x20\x08\0\0\0\0\x03\0\xd8\xcb\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x1d\x03\0\0\0\0\x03\0\x30\xcc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x26\x17\
+\0\0\0\0\x03\0\x88\xcc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x11\0\0\0\0\x03\0\xe0\
+\xcc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xba\x0c\0\0\0\0\x03\0\x38\xcd\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xb9\x07\0\0\0\0\x03\0\x90\xcd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb6\x02\
+\0\0\0\0\x03\0\xe8\xcd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8f\x1a\0\0\0\0\x03\0\x40\
+\xce\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x15\0\0\0\0\x03\0\x98\xce\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x2c\x10\0\0\0\0\x03\0\xf0\xce\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2b\x0b\
+\0\0\0\0\x03\0\x48\xcf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x31\x06\0\0\0\0\x03\0\xa0\
+\xcf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x27\x1a\0\0\0\0\x03\0\xf8\xcf\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xd7\x14\0\0\0\0\x03\0\x50\xd0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc4\x0f\
+\0\0\0\0\x03\0\xa8\xd0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc3\x0a\0\0\0\0\x03\0\0\xd1\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc9\x05\0\0\0\0\x03\0\x58\xd1\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\xc9\x19\0\0\0\0\x03\0\xb0\xd1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x79\x14\0\0\
+\0\0\x03\0\x08\xd2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x66\x0f\0\0\0\0\x03\0\x58\xd2\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x65\x0a\0\0\0\0\x03\0\xc0\xd2\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x6b\x05\0\0\0\0\x03\0\x18\xd3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\x19\0\0\0\
+\0\x03\0\x70\xd3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x12\x14\0\0\0\0\x03\0\xc8\xd3\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x08\x0f\0\0\0\0\x03\0\x20\xd4\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\x07\x0a\0\0\0\0\x03\0\x78\xd4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0d\x05\0\0\0\0\
+\x03\0\xd0\xd4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0d\x19\0\0\0\0\x03\0\x28\xd5\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xb4\x13\0\0\0\0\x03\0\x80\xd5\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\xaa\x0e\0\0\0\0\x03\0\xd8\xd5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa9\x09\0\0\0\0\
+\x03\0\x30\xd6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaf\x04\0\0\0\0\x03\0\x88\xd6\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xaf\x18\0\0\0\0\x03\0\xe0\xd6\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x56\x13\0\0\0\0\x03\0\x38\xd7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4c\x0e\0\0\0\0\
+\x03\0\x90\xd7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4b\x09\0\0\0\0\x03\0\xe8\xd7\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x48\x04\0\0\0\0\x03\0\x40\xd8\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x51\x18\0\0\0\0\x03\0\x98\xd8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf8\x12\0\0\0\0\
+\x03\0\xf0\xd8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe5\x0d\0\0\0\0\x03\0\x48\xd9\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xe4\x08\0\0\0\0\x03\0\xa0\xd9\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\xe1\x03\0\0\0\0\x03\0\xf8\xd9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\x17\0\0\0\0\
+\x03\0\x50\xda\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x12\0\0\0\0\x03\0\xa8\xda\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x7e\x0d\0\0\0\0\x03\0\0\xdb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x7d\x08\0\0\0\0\x03\0\x58\xdb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7a\x03\0\0\0\0\x03\
+\0\xb0\xdb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83\x17\0\0\0\0\x03\0\x08\xdc\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x2a\x12\0\0\0\0\x03\0\x60\xdc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x17\x0d\0\0\0\0\x03\0\xb8\xdc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x08\0\0\0\0\x03\
+\0\x08\xdd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x13\x03\0\0\0\0\x03\0\x70\xdd\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x1c\x17\0\0\0\0\x03\0\xc8\xdd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xc3\x11\0\0\0\0\x03\0\x20\xde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb0\x0c\0\0\0\0\x03\
+\0\x78\xde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaf\x07\0\0\0\0\x03\0\xd0\xde\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xac\x02\0\0\0\0\x03\0\x28\xdf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x85\x1a\0\0\0\0\x03\0\x80\xdf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x35\x15\0\0\0\0\x03\
+\0\xd8\xdf\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x22\x10\0\0\0\0\x03\0\x30\xe0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x21\x0b\0\0\0\0\x03\0\x88\xe0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x27\x06\0\0\0\0\x03\0\xe0\xe0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1d\x1a\0\0\0\0\x03\
+\0\x38\xe1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcd\x14\0\0\0\0\x03\0\x90\xe1\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\xba\x0f\0\0\0\0\x03\0\xe8\xe1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xb9\x0a\0\0\0\0\x03\0\x40\xe2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbf\x05\0\0\0\0\x03\
+\0\x98\xe2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbf\x19\0\0\0\0\x03\0\xf0\xe2\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x6f\x14\0\0\0\0\x03\0\x48\xe3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x5c\x0f\0\0\0\0\x03\0\xa0\xe3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x0a\0\0\0\0\x03\
+\0\xf8\xe3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x05\0\0\0\0\x03\0\x50\xe4\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x61\x19\0\0\0\0\x03\0\xa8\xe4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x08\x14\0\0\0\0\x03\0\0\xe5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfe\x0e\0\0\0\0\x03\0\
+\x58\xe5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfd\x09\0\0\0\0\x03\0\xb0\xe5\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x03\x05\0\0\0\0\x03\0\x08\xe6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
+\x19\0\0\0\0\x03\0\x60\xe6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\x13\0\0\0\0\x03\0\
+\xc0\xe6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x0e\0\0\0\0\x03\0\x28\xe7\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x9f\x09\0\0\0\0\x03\0\x88\xe7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa5\
+\x04\0\0\0\0\x03\0\xe0\xe7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa5\x18\0\0\0\0\x03\0\
+\x40\xe8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4c\x13\0\0\0\0\x03\0\x98\xe8\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x42\x0e\0\0\0\0\x03\0\xf0\xe8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x41\
+\x09\0\0\0\0\x03\0\x48\xe9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3e\x04\0\0\0\0\x03\0\
+\xa0\xe9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x18\0\0\0\0\x03\0\xf8\xe9\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\xee\x12\0\0\0\0\x03\0\x50\xea\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdb\
+\x0d\0\0\0\0\x03\0\xa8\xea\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xda\x08\0\0\0\0\x03\0\0\
+\xeb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd7\x03\0\0\0\0\x03\0\x58\xeb\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xe0\x17\0\0\0\0\x03\0\xb0\xeb\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87\x12\
+\0\0\0\0\x03\0\x08\xec\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\x0d\0\0\0\0\x03\0\x60\
+\xec\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x73\x08\0\0\0\0\x03\0\xb8\xec\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x70\x03\0\0\0\0\x03\0\x10\xed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x79\x17\
+\0\0\0\0\x03\0\x68\xed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x20\x12\0\0\0\0\x03\0\xc0\
+\xed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0d\x0d\0\0\0\0\x03\0\x18\xee\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x0c\x08\0\0\0\0\x03\0\x70\xee\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x09\x03\
+\0\0\0\0\x03\0\xc8\xee\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x12\x17\0\0\0\0\x03\0\x20\
+\xef\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb9\x11\0\0\0\0\x03\0\x78\xef\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xa6\x0c\0\0\0\0\x03\0\xd0\xef\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa5\x07\
+\0\0\0\0\x03\0\x28\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa2\x02\0\0\0\0\x03\0\x80\
+\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7b\x1a\0\0\0\0\x03\0\xd8\xf0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x2b\x15\0\0\0\0\x03\0\x30\xf1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x10\
+\0\0\0\0\x03\0\x88\xf1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x0b\0\0\0\0\x03\0\xe0\
+\xf1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1d\x06\0\0\0\0\x03\0\x38\xf2\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x6f\x04\0\0\0\0\x03\0\x98\xf5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x24\x16\
+\0\0\0\0\x03\0\x18\xf3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf7\x10\0\0\0\0\x03\0\x30\
+\xf3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf3\x06\0\0\0\0\x03\0\xd0\xf3\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xf0\x01\0\0\0\0\x03\0\xf8\xf3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd4\x10\
+\0\0\0\0\x03\0\xa0\xf4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xda\x0b\0\0\0\0\x03\0\xc8\
+\xf4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5d\x15\0\0\x01\0\x07\0\x24\0\0\0\0\0\0\0\x0a\
+\0\0\0\0\0\0\0\0\0\0\0\x03\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
+\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x0a\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x03\0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
+\0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x10\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x03\0\x11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
+\0\x17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x19\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x03\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc9\0\0\0\
+\x12\0\x03\0\0\0\0\0\0\0\0\0\xc8\xf6\0\0\0\0\0\0\xb1\0\0\0\x11\0\x06\0\0\0\0\0\
+\0\0\0\0\x20\0\0\0\0\0\0\0\xe7\0\0\0\x11\0\x08\0\0\0\0\0\0\0\0\0\x0d\0\0\0\0\0\
+\0\0\xa0\0\0\0\0\0\0\0\x01\0\0\0\xcc\x02\0\0\xc0\0\0\0\0\0\0\0\x01\0\0\0\xc1\
+\x02\0\0\x28\x01\0\0\0\0\0\0\x01\0\0\0\xc1\x02\0\0\xc8\xf5\0\0\0\0\0\0\x01\0\0\
+\0\xc1\x02\0\0\x90\xf6\0\0\0\0\0\0\x01\0\0\0\xc1\x02\0\0\x08\0\0\0\0\0\0\0\x03\
+\0\0\0\xc3\x02\0\0\x11\0\0\0\0\0\0\0\x03\0\0\0\xc5\x02\0\0\x15\0\0\0\0\0\0\0\
+\x03\0\0\0\xc9\x02\0\0\x1f\0\0\0\0\0\0\0\x03\0\0\0\xc7\x02\0\0\x23\0\0\0\0\0\0\
+\0\x03\0\0\0\xc4\x02\0\0\x27\0\0\0\0\0\0\0\x03\0\0\0\xc2\x02\0\0\x08\0\0\0\0\0\
+\0\0\x03\0\0\0\xc6\x02\0\0\x0c\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x10\0\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x14\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x18\0\0\0\
+\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x1c\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x20\0\0\
+\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x24\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x28\0\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x2c\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x30\
+\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x34\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x38\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x3c\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\
+\0\x40\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x44\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\
+\0\0\x48\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x4c\0\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x50\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x54\0\0\0\0\0\0\0\x03\0\0\0\
+\xc6\x02\0\0\x58\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x5c\0\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x60\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x64\0\0\0\0\0\0\0\x03\0\
+\0\0\xc6\x02\0\0\x68\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x6c\0\0\0\0\0\0\0\x03\
+\0\0\0\xc6\x02\0\0\x70\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x74\0\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x78\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x7c\0\0\0\0\0\0\
+\0\x03\0\0\0\xc6\x02\0\0\x80\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x84\0\0\0\0\0\
+\0\0\x03\0\0\0\xc6\x02\0\0\x88\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x8c\0\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x90\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x94\0\0\0\
+\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x98\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x9c\0\0\
+\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa0\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa4\0\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa8\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xac\
+\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb0\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\xb4\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb8\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\
+\0\xbc\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc0\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\
+\0\0\xc4\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc8\0\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xcc\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xd0\0\0\0\0\0\0\0\x03\0\0\0\
+\xc6\x02\0\0\xd4\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xd8\0\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\xdc\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xe0\0\0\0\0\0\0\0\x03\0\
+\0\0\xc6\x02\0\0\xe4\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xe8\0\0\0\0\0\0\0\x03\
+\0\0\0\xc6\x02\0\0\xec\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xf0\0\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\xf4\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xf8\0\0\0\0\0\0\
+\0\x03\0\0\0\xc6\x02\0\0\xfc\0\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\0\x01\0\0\0\0\
+\0\0\x03\0\0\0\xc6\x02\0\0\x04\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x08\x01\0\
+\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x0c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x10\
+\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x14\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\
+\0\x18\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x1c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x20\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x24\x01\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x28\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x2c\x01\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x30\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x34\x01\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x38\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x3c\x01\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x40\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x44\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x48\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x4c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x50\x01\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x54\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x58\x01\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x5c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x60\x01\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x64\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x68\x01\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x6c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x70\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x74\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x78\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x7c\x01\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x80\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x84\x01\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x88\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x8c\x01\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x90\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x94\x01\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x98\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x9c\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa0\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xa4\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa8\x01\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\xac\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb0\x01\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\xb4\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb8\x01\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\xbc\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc0\x01\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc4\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\xc8\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xcc\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xd0\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xd4\x01\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\xd8\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xdc\x01\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\xe0\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xe4\x01\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\xe8\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xec\x01\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xf0\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\xf4\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xf8\x01\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xfc\x01\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\0\x02\0\0\0\0\0\0\x03\0\0\0\
+\xc6\x02\0\0\x04\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x08\x02\0\0\0\0\0\0\x03\
+\0\0\0\xc6\x02\0\0\x0c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x10\x02\0\0\0\0\0\
+\0\x03\0\0\0\xc6\x02\0\0\x14\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x18\x02\0\0\
+\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x1c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x20\
+\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x24\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\
+\0\x28\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x2c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x30\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x34\x02\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x38\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x3c\x02\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x40\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x44\x02\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x48\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x4c\x02\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x50\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x54\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x58\x02\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x5c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x60\x02\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x64\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x68\x02\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x6c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x70\x02\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\x74\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x78\x02\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x7c\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\x80\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x84\x02\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\x88\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x8c\x02\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\x90\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x94\x02\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\x98\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x9c\x02\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\xa0\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa4\x02\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xa8\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\xac\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb0\x02\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xb4\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xb8\x02\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\xbc\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc0\x02\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\xc4\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xc8\x02\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\xcc\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xd0\x02\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xd4\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\
+\xd8\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xdc\x02\0\0\0\0\0\0\x03\0\0\0\xc6\
+\x02\0\0\xe0\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xe4\x02\0\0\0\0\0\0\x03\0\0\
+\0\xc6\x02\0\0\xe8\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xec\x02\0\0\0\0\0\0\
+\x03\0\0\0\xc6\x02\0\0\xf0\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xf4\x02\0\0\0\
+\0\0\0\x03\0\0\0\xc6\x02\0\0\xf8\x02\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\xfc\x02\
+\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\0\x03\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x04\
+\x03\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x08\x03\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\
+\0\x0c\x03\0\0\0\0\0\0\x03\0\0\0\xc6\x02\0\0\x08\0\0\0\0\0\0\0\x02\0\0\0\xc1\
+\x02\0\0\x10\0\0\0\0\0\0\0\x02\0\0\0\xc1\x02\0\0\x18\0\0\0\0\0\0\0\x02\0\0\0\
+\xc1\x02\0\0\x20\0\0\0\0\0\0\0\x02\0\0\0\xcd\x02\0\0\x28\0\0\0\0\0\0\0\x02\0\0\
+\0\xcc\x02\0\0\x30\0\0\0\0\0\0\0\x02\0\0\0\x02\0\0\0\x38\0\0\0\0\0\0\0\x02\0\0\
+\0\x02\0\0\0\x40\0\0\0\0\0\0\0\x02\0\0\0\x02\0\0\0\x48\0\0\0\0\0\0\0\x02\0\0\0\
+\x02\0\0\0\x50\0\0\0\0\0\0\0\x02\0\0\0\x02\0\0\0\x58\0\0\0\0\0\0\0\x02\0\0\0\
+\x02\0\0\0\x7c\x04\0\0\0\0\0\0\x04\0\0\0\xcc\x02\0\0\x94\x04\0\0\0\0\0\0\x03\0\
+\0\0\xc1\x02\0\0\xa0\x04\0\0\0\0\0\0\x03\0\0\0\xc1\x02\0\0\xac\x04\0\0\0\0\0\0\
+\x03\0\0\0\xc1\x02\0\0\xc4\x04\0\0\0\0\0\0\x04\0\0\0\xcd\x02\0\0\x2c\0\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\0\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x01\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x01\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x01\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x01\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x01\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x01\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x01\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x01\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x02\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x02\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x02\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x02\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x02\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x03\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x03\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x03\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x03\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x03\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x03\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x03\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x03\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x03\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x04\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x04\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x04\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x04\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x04\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x04\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x05\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x05\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x05\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x05\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x05\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x05\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x05\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x05\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x05\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x06\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x06\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x06\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x06\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x06\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x07\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x07\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x07\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x07\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x07\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x07\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x07\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x07\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\x07\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x08\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x08\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x08\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x08\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x08\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x08\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x09\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x09\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x09\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x09\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x09\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x09\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x09\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x09\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0a\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x0a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\x0a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0b\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0b\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\x0b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0c\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x0c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0c\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0c\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0d\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x0d\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x0d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0e\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x0e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x0e\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0f\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\x0f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x10\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x10\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x10\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x10\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x10\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x10\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x10\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x10\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x10\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x11\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x11\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x11\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x11\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\x11\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x11\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x12\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x12\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x12\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x12\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x12\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x12\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x12\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\x12\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x12\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x13\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x13\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x13\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x13\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x13\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\x13\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x14\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x14\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x14\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x14\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x14\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x14\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\x14\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x15\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x15\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x15\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x15\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x15\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x15\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x15\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x15\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x16\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x16\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x16\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x16\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\x16\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x16\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x17\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x17\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x17\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x17\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x17\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x17\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x17\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x17\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x17\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x18\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x18\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x18\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x18\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x18\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x19\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x19\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x19\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x19\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x19\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x19\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x19\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x19\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x19\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1a\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\x1a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1a\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1b\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1b\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1b\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1b\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\x1b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1b\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1c\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\x1c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1d\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1d\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1d\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1d\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\x1d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1e\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1e\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1f\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1f\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1f\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\x1f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1f\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x20\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x20\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x20\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x20\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x20\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x20\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x20\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x20\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x21\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x21\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x21\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x21\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x21\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x22\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x22\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x22\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x22\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x22\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x22\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x22\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x22\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x22\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x23\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x23\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x23\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x23\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x23\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x23\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x24\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x24\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x24\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x24\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x24\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x24\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x24\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x24\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x24\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x25\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x25\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x25\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x25\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x25\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x26\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x26\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x26\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x26\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x26\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x26\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x26\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x26\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\x26\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x27\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x27\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x27\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x27\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x27\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x27\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x28\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x28\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x28\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x28\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x28\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x28\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x28\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x28\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x29\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x29\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x29\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x29\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x29\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x29\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\x29\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2a\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2a\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2a\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2a\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2a\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\x2a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2b\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2b\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2b\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2b\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2b\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2b\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2b\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2c\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2c\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x2c\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x2c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2c\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2d\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x2d\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2d\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2d\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2d\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x2d\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2d\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2e\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2e\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\x2e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2f\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2f\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2f\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2f\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2f\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2f\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2f\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x30\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x30\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x30\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x30\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\x30\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x30\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x31\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x31\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x31\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x31\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x31\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x31\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x31\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\x31\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x31\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x32\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x32\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x32\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x32\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x32\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\x32\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x33\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x33\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x33\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x33\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x33\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x33\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\x33\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x34\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x34\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x34\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x34\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x34\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x34\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x34\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x34\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x35\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x35\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x35\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x35\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\x35\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x35\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x36\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x36\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x36\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x36\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x36\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x36\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x36\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x36\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x36\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x37\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x37\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x37\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x37\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x37\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x38\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x38\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x38\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x38\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x38\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x38\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x38\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x38\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x38\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x39\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x39\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x39\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x39\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\x39\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x39\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x3a\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x3a\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x3a\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x3a\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x3a\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x3a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x3a\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\x3a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x3a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x3b\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x3b\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x3b\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x3b\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\x3b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x3c\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x3c\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x3c\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x3c\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x3c\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x3c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x3c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\x3c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x3d\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x3d\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x3d\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x3d\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x3d\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x3d\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x3d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x3e\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x3e\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x3e\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x3e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x3e\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\x3e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x3e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x3f\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x3f\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x3f\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x3f\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x3f\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x3f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x3f\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x3f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x40\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x40\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x40\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x40\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x40\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x41\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x41\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x41\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x41\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x41\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x41\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x41\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x41\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x41\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x42\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x42\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x42\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x42\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x42\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x42\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x43\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x43\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x43\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x43\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x43\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x43\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x43\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x43\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x43\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x44\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x44\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x44\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x44\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x44\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x45\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x45\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x45\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x45\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x45\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x45\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x45\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x45\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\x45\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x46\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x46\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x46\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x46\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x46\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x46\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x47\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x47\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x47\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x47\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x47\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x47\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x47\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x47\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x48\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x48\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x48\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x48\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x48\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x48\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\x48\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x49\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x49\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x49\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x49\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x49\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\x49\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x4a\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x4a\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x4a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x4a\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x4a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x4a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x4a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x4a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x4a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x4b\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x4b\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x4b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x4b\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x4b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x4b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x4c\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x4c\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x4c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x4c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x4c\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x4c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x4c\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x4c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x4c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x4d\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x4d\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x4d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\x4d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x4e\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x4e\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x4e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x4e\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x4e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x4e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x4e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x4e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x4e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x4f\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x4f\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x4f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x4f\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x4f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x50\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x50\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x50\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x50\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x50\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x50\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x50\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\x50\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x50\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x51\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x51\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x51\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x51\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x51\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\x51\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x52\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x52\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x52\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x52\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x52\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x52\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\x52\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x53\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x53\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x53\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x53\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x53\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x53\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x53\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x53\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x54\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x54\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x54\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x54\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\x54\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x54\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x55\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x55\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x55\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x55\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x55\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x55\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x55\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x55\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x55\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x56\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x56\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x56\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x56\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x56\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x57\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x57\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x57\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x57\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x57\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x57\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x57\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x57\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x57\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x58\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x58\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x58\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x58\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\x58\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x58\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x59\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x59\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x59\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x59\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x59\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x59\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x59\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\x59\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x59\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x5a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x5a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x5a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x5a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\x5a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x5b\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x5b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x5b\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x5b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x5b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x5b\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x5b\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\x5b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x5c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x5c\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x5c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x5c\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x5c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x5c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x5c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x5d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x5d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x5d\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x5d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x5d\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\x5d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x5d\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x5e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x5e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x5e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x5e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x5e\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x5e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x5e\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x5e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x5f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x5f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x5f\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x5f\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x5f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x60\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x60\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x60\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x60\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x60\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x60\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x60\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x60\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x60\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x61\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x61\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x61\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x61\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x61\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x61\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x62\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x62\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x62\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x62\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x62\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x62\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x62\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x62\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x62\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x63\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x63\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x63\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x63\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x63\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x64\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x64\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x64\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x64\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x64\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x64\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x64\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x64\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\x64\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x65\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x65\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x65\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x65\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x65\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x65\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x66\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x66\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x66\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x66\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x66\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x66\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x66\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x66\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x67\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x67\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x67\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x67\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x67\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x67\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\x67\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x68\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x68\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x68\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x68\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x68\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\x68\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x69\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x69\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x69\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x69\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x69\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x69\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x69\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x69\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x69\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x6a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x6a\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x6a\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x6a\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x6a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x6a\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x6b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x6b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x6b\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x6b\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x6b\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x6b\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x6b\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x6b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x6b\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x6c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x6c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x6c\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\x6c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x6d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x6d\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x6d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x6d\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x6d\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x6d\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x6d\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x6d\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x6d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x6e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x6e\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x6e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x6e\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x6e\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x6f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x6f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x6f\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x6f\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x6f\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x6f\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x6f\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\x6f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x6f\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x70\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x70\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x70\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x70\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x70\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\x70\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x71\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x71\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x71\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x71\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x71\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x71\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\x71\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x72\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x72\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x72\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x72\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x72\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x72\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x72\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x72\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x73\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x73\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x73\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x73\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\x73\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x73\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x74\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x74\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x74\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x74\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x74\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x74\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x74\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x74\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x74\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x75\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x75\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x75\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x75\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x75\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x76\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x76\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x76\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x76\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x76\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x76\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x76\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x76\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x76\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x77\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x77\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x77\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x77\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\x77\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x77\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x78\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x78\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x78\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x78\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x78\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x78\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x78\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\x78\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x78\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x79\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x79\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x79\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x79\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\x79\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x7a\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x7a\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x7a\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x7a\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x7a\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x7a\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x7a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\x7a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x7b\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x7b\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x7b\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x7b\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x7b\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x7b\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x7b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x7c\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x7c\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x7c\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x7c\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x7c\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\x7c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x7c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x7d\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x7d\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x7d\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x7d\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x7d\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x7d\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x7d\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x7d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x7e\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x7e\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x7e\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x7e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x7e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x7f\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x7f\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x7f\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x7f\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x7f\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x7f\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x7f\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x7f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x7f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x80\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x80\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x80\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x80\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x80\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x80\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x81\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x81\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x81\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x81\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x81\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x81\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x81\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x81\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x81\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x82\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x82\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x82\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x82\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x82\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x83\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x83\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x83\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x83\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x83\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x83\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x83\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x83\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\x83\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x84\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x84\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x84\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x84\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x84\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x84\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x85\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x85\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x85\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x85\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x85\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x85\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x85\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x85\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x86\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x86\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x86\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x86\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x86\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x86\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\x86\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x87\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x87\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x87\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x87\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x87\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\x87\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x88\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x88\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x88\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x88\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x88\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x88\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x88\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x88\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x88\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x89\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x89\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x89\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x89\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x89\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x89\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x8a\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x8a\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x8a\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x8a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x8a\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x8a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x8a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x8a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x8a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x8b\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x8b\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x8b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\x8b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x8c\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x8c\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x8c\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x8c\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x8c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x8c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x8c\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x8c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x8c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x8d\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x8d\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x8d\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x8d\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x8d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x8e\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x8e\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x8e\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x8e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x8e\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x8e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x8e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\x8e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x8e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x8f\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x8f\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x8f\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x8f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x8f\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\x8f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x90\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x90\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x90\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x90\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x90\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x90\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\x90\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x91\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x91\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x91\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x91\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x91\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x91\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x91\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x91\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x92\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x92\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x92\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x92\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\x92\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x92\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x93\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x93\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x93\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x93\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x93\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x93\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x93\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x93\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x93\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x94\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x94\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x94\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x94\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x94\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x95\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x95\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x95\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x95\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x95\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x95\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x95\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x95\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x95\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x96\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x96\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x96\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x96\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\x96\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x96\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x97\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x97\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x97\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x97\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x97\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x97\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x97\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\x97\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x97\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x98\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x98\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x98\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x98\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\x98\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x99\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x99\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x99\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x99\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x99\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x99\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x99\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\x99\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x9a\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x9a\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x9a\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x9a\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x9a\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x9a\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x9a\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x9b\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x9b\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x9b\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x9b\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x9b\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\x9b\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x9b\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x9c\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x9c\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x9c\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x9c\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x9c\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x9c\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x9c\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\x9c\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x9d\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x9d\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x9d\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x9d\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\x9d\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x9e\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x9e\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x9e\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x9e\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x9e\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x9e\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x9e\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x9e\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x9e\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x9f\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x9f\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x9f\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x9f\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\x9f\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x9f\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa0\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa0\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa0\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa0\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa0\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa0\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa0\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa1\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa1\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa1\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\xa1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa2\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xa2\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xa2\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa2\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa2\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xa2\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa2\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa2\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\xa2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa3\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xa3\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xa3\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa3\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa3\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa3\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa4\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa4\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa4\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa4\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa4\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa4\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\xa4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa4\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa5\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa5\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa5\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa5\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa5\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa5\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\xa5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa6\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa6\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xa6\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa6\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa6\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\xa6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa7\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xa7\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xa7\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xa7\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xa7\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xa7\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa7\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa7\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xa8\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa8\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa8\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa8\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\xa8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa8\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xa9\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xa9\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xa9\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xa9\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xa9\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xa9\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xa9\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xa9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xa9\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xaa\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xaa\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xaa\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\xaa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xab\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xab\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xab\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xab\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xab\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xab\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xab\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xab\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xab\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xac\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xac\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xac\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xac\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\xac\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xac\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xad\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xad\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xad\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xad\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xad\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xad\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xad\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\xad\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xad\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xae\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xae\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xae\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xae\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xae\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\xae\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xaf\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xaf\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xaf\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xaf\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xaf\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xaf\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\xaf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb0\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb0\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb0\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb0\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb0\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb0\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb1\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb1\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb1\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb1\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\xb1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb1\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb2\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xb2\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb2\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb2\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb2\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb2\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb2\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xb2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb2\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb3\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb3\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb3\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xb3\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\xb3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb4\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb4\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb4\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb4\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb4\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb4\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb4\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xb4\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb5\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb5\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb5\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb5\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\xb5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb5\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb6\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xb6\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb6\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb6\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb6\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb6\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb6\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\xb6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb6\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xb7\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xb7\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb7\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb7\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\xb7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb8\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb8\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb8\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb8\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb8\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xb8\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xb8\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\xb8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xb9\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xb9\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xb9\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xb9\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xb9\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xb9\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xb9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xba\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xba\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xba\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xba\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xba\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\xba\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xba\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xbb\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xbb\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xbb\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xbb\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xbb\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xbb\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xbb\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\xbb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xbc\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xbc\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xbc\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xbc\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\xbc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xbd\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xbd\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xbd\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xbd\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xbd\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xbd\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xbd\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xbd\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xbd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xbe\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xbe\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xbe\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xbe\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\xbe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xbe\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xbf\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xbf\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xbf\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xbf\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xbf\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xbf\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xbf\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xbf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xbf\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc0\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc0\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc0\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\xc0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc1\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc1\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc1\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc1\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc1\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc1\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc1\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc1\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\xc1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc2\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc2\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc2\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc2\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc2\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xc2\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc3\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc3\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xc3\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc3\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc3\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xc3\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\xc3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xc3\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc4\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc4\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc4\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xc4\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc4\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc4\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\xc4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc5\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc5\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc5\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc5\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc5\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\xc5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc6\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc6\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc6\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc6\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc6\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc6\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc6\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc6\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xc6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc7\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc7\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc7\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xc7\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\xc7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xc7\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc8\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc8\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xc8\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xc8\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xc8\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xc8\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xc8\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xc8\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xc9\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xc9\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xc9\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\xc9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xca\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xca\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xca\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xca\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xca\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xca\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xca\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xca\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xca\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xcb\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xcb\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xcb\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xcb\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xcb\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xcc\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xcc\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xcc\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xcc\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xcc\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xcc\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xcc\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\xcc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xcc\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xcd\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xcd\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xcd\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xcd\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xcd\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\xcd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xce\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xce\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xce\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xce\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xce\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xce\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\xce\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xcf\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xcf\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xcf\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xcf\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xcf\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xcf\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xcf\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xcf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd0\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd0\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd0\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd0\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\xd0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd0\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd1\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd1\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd1\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd1\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd1\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd1\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd1\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xd1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd1\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd2\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd2\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xd2\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xd2\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\xd2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xd3\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd3\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd3\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xd3\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xd3\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd3\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xd3\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xd3\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xd4\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd4\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd4\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd4\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\xd4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd4\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd5\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd5\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd5\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd5\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd5\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd5\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd5\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\xd5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd5\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd6\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd6\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd6\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd6\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\xd6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd7\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd7\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xd7\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xd7\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd7\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xd7\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xd7\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\xd7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xd8\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xd8\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xd8\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xd8\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xd8\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xd8\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xd9\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xd9\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xd9\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xd9\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xd9\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\xd9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xd9\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xda\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xda\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xda\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xda\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xda\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xda\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xda\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\xda\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xdb\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xdb\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xdb\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xdb\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\xdb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xdc\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xdc\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xdc\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xdc\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xdc\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xdc\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xdc\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xdc\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xdc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xdd\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xdd\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xdd\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xdd\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\xdd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xdd\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xde\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xde\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xde\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xde\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xde\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xde\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xde\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xde\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xde\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xdf\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xdf\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xdf\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\xdf\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe0\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe0\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe0\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe0\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe0\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe0\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe0\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\xe0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe1\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe1\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe1\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe1\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe1\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe1\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x20\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe2\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xe2\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x60\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xe2\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x80\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe2\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xa0\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe2\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xc0\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xe2\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\xe2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe2\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\0\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xe3\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x20\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe3\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x40\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xe3\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xe3\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe3\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe3\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\
+\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xf0\xe3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x10\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x30\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x50\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe4\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x70\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe4\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe4\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xb0\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe4\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xd0\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe4\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xf0\xe4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe5\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe5\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x30\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe5\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe5\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x70\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe5\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe5\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe5\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe5\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe6\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\
+\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x40\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x60\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x80\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe6\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe6\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xc0\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xe6\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\xe6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe6\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\0\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xe7\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x20\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe7\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xe7\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x60\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xe7\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xe7\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xa0\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xe7\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xe7\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe7\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xe8\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xe8\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x70\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x90\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xb0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe8\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xf0\xe8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xe9\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xe9\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x30\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xe9\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x50\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xe9\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x70\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xe9\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x90\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xe9\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xe9\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xd0\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xe9\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xe9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xea\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x10\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xea\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xea\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xea\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\
+\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xc0\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xe0\xea\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xea\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\0\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xeb\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x20\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xeb\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xeb\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xeb\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x80\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xeb\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xa0\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xeb\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xc0\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xeb\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xe0\xeb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xeb\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xec\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xec\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x40\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xec\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xec\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xec\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\
+\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xf0\xec\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x10\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x30\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xed\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x50\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xed\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xed\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x90\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xed\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xb0\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xed\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xd0\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xed\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xf0\xed\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xee\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x10\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xee\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xee\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x50\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xee\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x70\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xee\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xee\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xee\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\
+\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xee\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x40\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x60\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xef\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x80\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xef\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xa0\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xef\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xef\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xe0\xef\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xef\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\0\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf0\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x20\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf0\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x40\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf0\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf0\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x80\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf0\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf0\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf0\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf0\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf0\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf1\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x50\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x90\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf1\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xb0\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf1\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xd0\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf1\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\xf1\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xf2\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x10\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf2\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x30\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf2\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x50\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xf2\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x70\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf2\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x90\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf2\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xb0\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf2\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf2\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf2\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xf3\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf3\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf3\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\
+\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xa0\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xc0\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf3\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xe0\xf3\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf3\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\0\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf4\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf4\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x40\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf4\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x60\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf4\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x80\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf4\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xa0\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf4\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xc0\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf4\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xe0\xf4\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf4\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf5\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf5\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf5\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf5\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\
+\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xd0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xf0\xf5\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x10\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf6\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x30\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf6\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x50\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xf6\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x70\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf6\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x90\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf6\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf6\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xd0\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf6\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xf0\xf6\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xf7\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x10\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xf7\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x30\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xf7\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xf7\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf7\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf7\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\
+\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xe0\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf7\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\0\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x40\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf8\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x60\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf8\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x80\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf8\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xa0\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf8\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xc0\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf8\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xe0\xf8\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xf8\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xf9\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x20\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xf9\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x40\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xf9\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x60\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xf9\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x80\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xf9\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xf9\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xf9\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\
+\xf9\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\
+\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x30\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\x70\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xfa\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x90\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xfa\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xb0\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xfa\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xd0\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xfa\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\xf0\xfa\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xfb\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x10\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xfb\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xfb\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x50\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xfb\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x70\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xfb\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x90\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xfb\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xfb\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xfb\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xfb\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xfc\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xfc\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\
+\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x60\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x80\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xa0\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xfc\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xfc\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\xe0\xfc\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xfc\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\0\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xfd\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x20\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xfd\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x40\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xfd\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\xfd\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\xfd\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xa0\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\xfd\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xc0\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\xfd\0\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xfd\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\xfd\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\xfe\0\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\xfe\0\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\xfe\
+\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\
+\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x90\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xb0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\xd0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\xfe\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\xff\0\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x10\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\xff\0\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x30\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\xff\0\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x50\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\xff\0\0\0\0\0\0\x04\0\
+\0\0\x02\0\0\0\x70\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\xff\0\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\xff\0\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xb0\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\xff\0\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\xff\0\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\xf0\xff\0\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\0\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x10\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\0\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\x30\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\0\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\0\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\0\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\
+\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xc0\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\xe0\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\0\x01\0\0\0\0\0\x04\0\0\0\x02\0\
+\0\0\0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x01\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x20\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x01\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x40\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x01\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x60\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x01\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x01\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xb0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xd0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x01\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xf0\x01\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x02\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x10\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x02\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x30\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x02\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x02\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x80\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x02\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xa0\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x02\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xc0\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x02\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\xe0\x02\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x02\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\0\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x03\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\
+\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x50\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x03\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x70\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x03\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x90\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x03\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xb0\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x03\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x03\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x03\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\
+\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x20\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x04\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x40\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x04\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x60\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x04\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x80\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x04\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x04\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x04\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x04\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x05\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x05\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x05\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x05\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x05\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x05\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x05\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x05\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x05\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x06\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x06\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x06\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x06\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x06\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x06\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x06\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x07\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x07\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x07\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x07\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x07\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x07\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x07\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x07\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x08\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x08\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x08\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x08\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x08\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x08\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x08\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x08\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x08\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x09\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x09\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x09\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x09\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x09\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x09\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x09\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0a\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x0a\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0a\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0a\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0a\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x0a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0b\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x0b\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0b\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0b\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0b\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x0b\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x0b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0b\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0c\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0c\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0c\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0c\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0c\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0c\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0d\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x0d\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0d\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0d\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0d\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x0d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x0e\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x0e\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0e\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0e\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0e\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x0e\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x0e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0e\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x0f\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x0f\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x0f\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x0f\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x0f\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x0f\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x0f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x10\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x10\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x10\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x10\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x10\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x10\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x10\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x10\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x11\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x11\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x11\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x11\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x11\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x11\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x11\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x11\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x11\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x12\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x12\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x12\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x12\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x12\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x12\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x12\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x13\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x13\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x13\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x13\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x13\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x13\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x13\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x13\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x14\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x14\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x14\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x14\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x14\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x14\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x14\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x14\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x14\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x15\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x15\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x15\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x15\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x15\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x15\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x15\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x16\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x16\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x16\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x16\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x16\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x16\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x16\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x16\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x17\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x17\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x17\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x17\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x17\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x17\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x17\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x17\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x17\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x18\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x18\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x18\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x18\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x18\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x18\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x18\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x19\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x19\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x19\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x19\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x19\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x19\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x19\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x19\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1a\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1a\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1a\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1a\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1a\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1a\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x1a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1a\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1b\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1b\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1b\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1b\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1b\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1b\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1c\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1c\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1c\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1c\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1c\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x1c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1d\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x1d\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1d\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1d\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1d\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x1d\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x1d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1d\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1e\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1e\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x1e\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1e\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1e\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1e\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x1e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x1f\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x1f\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x1f\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x1f\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x1f\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x1f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x20\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x20\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x20\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x20\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x20\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x20\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x20\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x20\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x20\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x21\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x21\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x21\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x21\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x21\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x21\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x21\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x22\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x22\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x22\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x22\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x22\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x22\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x22\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x22\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x23\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x23\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x23\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x23\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x23\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x23\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x23\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x23\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x23\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x24\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x24\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x24\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x24\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x24\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x24\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x24\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x25\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x25\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x25\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x25\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x25\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x25\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x25\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x25\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x26\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x26\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x26\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x26\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x26\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x26\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x26\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x26\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x26\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x27\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x27\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x27\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x27\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x27\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x27\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x27\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x28\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x28\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x28\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x28\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x28\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x28\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x28\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x28\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x29\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x29\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x29\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x29\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x29\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x29\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x29\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x29\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x29\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2a\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2a\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2a\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2a\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2a\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2a\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2a\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2b\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x2b\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2b\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2b\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2b\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x2b\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2c\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2c\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2c\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2c\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2c\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x2c\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x2c\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2c\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2d\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2d\x01\
+\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\
+\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\
+\0\x70\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2d\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x90\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2d\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\xb0\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2d\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\xd0\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2d\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2d\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2e\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\x20\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x30\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\x40\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x50\x2e\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\x60\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2e\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\x80\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2e\x01\0\0\
+\0\0\0\x04\0\0\0\x02\0\0\0\xa0\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2e\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xc0\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xd0\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xe0\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xf0\x2e\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\0\x2f\x01\0\0\0\0\0\x04\0\0\0\
+\x02\0\0\0\x10\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x20\x2f\x01\0\0\0\0\0\x04\
+\0\0\0\x02\0\0\0\x30\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x40\x2f\x01\0\0\0\0\
+\0\x04\0\0\0\x02\0\0\0\x50\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x60\x2f\x01\0\
+\0\0\0\0\x04\0\0\0\x02\0\0\0\x70\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x80\x2f\
+\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x90\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\
+\xa0\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xb0\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\
+\0\0\0\xc0\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xd0\x2f\x01\0\0\0\0\0\x04\0\0\
+\0\x02\0\0\0\xe0\x2f\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\xf0\x2f\x01\0\0\0\0\0\
+\x04\0\0\0\x02\0\0\0\0\x30\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x10\x30\x01\0\0\0\
+\0\0\x04\0\0\0\x02\0\0\0\x20\x30\x01\0\0\0\0\0\x04\0\0\0\x02\0\0\0\x14\0\0\0\0\
+\0\0\0\x03\0\0\0\xc8\x02\0\0\x18\0\0\0\0\0\0\0\x02\0\0\0\x02\0\0\0\x22\0\0\0\0\
+\0\0\0\x03\0\0\0\xca\x02\0\0\x26\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x2a\0\0\0\
+\0\0\0\0\x03\0\0\0\xca\x02\0\0\x2e\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x32\0\0\
+\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x3e\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x53\0\
+\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x68\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x7d\
+\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x92\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\
+\xa7\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\xbc\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\
+\0\xd1\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\xe6\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\
+\0\0\xfb\0\0\0\0\0\0\0\x03\0\0\0\xca\x02\0\0\x15\x01\0\0\0\0\0\0\x02\0\0\0\x02\
+\0\0\0\xcb\x05\xcc\x05\x04\x08\xc0\x05\xcd\x05\0\x2e\x64\x65\x62\x75\x67\x5f\
+\x61\x62\x62\x72\x65\x76\0\x2e\x74\x65\x78\x74\0\x2e\x72\x65\x6c\x2e\x42\x54\
+\x46\x2e\x65\x78\x74\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\
+\x6e\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\0\x2e\x64\x65\x62\x75\x67\x5f\x72\x6e\x67\
+\x6c\x69\x73\x74\x73\0\x2e\x64\x65\x62\x75\x67\x5f\x6c\x6f\x63\x6c\x69\x73\x74\
+\x73\0\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x73\x74\x72\x5f\x6f\x66\x66\
+\x73\x65\x74\x73\0\x2e\x72\x65\x6c\x74\x63\x2f\x69\x6e\x67\x72\x65\x73\x73\0\
+\x2e\x6d\x61\x70\x73\0\x2e\x64\x65\x62\x75\x67\x5f\x73\x74\x72\0\x2e\x64\x65\
+\x62\x75\x67\x5f\x6c\x69\x6e\x65\x5f\x73\x74\x72\0\x2e\x72\x65\x6c\x2e\x64\x65\
+\x62\x75\x67\x5f\x61\x64\x64\x72\0\x72\x73\x73\x5f\x6d\x61\x70\0\x2e\x72\x65\
+\x6c\x2e\x64\x65\x62\x75\x67\x5f\x69\x6e\x66\x6f\0\x72\x73\x73\x5f\x66\x6c\x6f\
+\x77\x5f\x61\x63\x74\x69\x6f\x6e\0\x2e\x6c\x6c\x76\x6d\x5f\x61\x64\x64\x72\x73\
+\x69\x67\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x2e\x72\x65\x6c\x2e\x64\x65\x62\
+\x75\x67\x5f\x6c\x69\x6e\x65\0\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x66\
+\x72\x61\x6d\x65\0\x74\x61\x70\x5f\x72\x73\x73\x2e\x63\0\x2e\x73\x74\x72\x74\
+\x61\x62\0\x2e\x73\x79\x6d\x74\x61\x62\0\x2e\x72\x6f\x64\x61\x74\x61\0\x2e\x72\
+\x65\x6c\x2e\x42\x54\x46\0\x4c\x42\x42\x30\x5f\x39\0\x4c\x42\x42\x30\x5f\x39\
+\x39\0\x4c\x42\x42\x30\x5f\x32\x39\x39\0\x4c\x42\x42\x30\x5f\x31\x39\x39\0\x4c\
+\x42\x42\x30\x5f\x38\x39\0\x4c\x42\x42\x30\x5f\x32\x38\x39\0\x4c\x42\x42\x30\
+\x5f\x31\x38\x39\0\x4c\x42\x42\x30\x5f\x37\x39\0\x4c\x42\x42\x30\x5f\x32\x37\
+\x39\0\x4c\x42\x42\x30\x5f\x31\x37\x39\0\x4c\x42\x42\x30\x5f\x36\x39\0\x4c\x42\
+\x42\x30\x5f\x32\x36\x39\0\x4c\x42\x42\x30\x5f\x31\x36\x39\0\x4c\x42\x42\x30\
+\x5f\x35\x39\0\x4c\x42\x42\x30\x5f\x32\x35\x39\0\x4c\x42\x42\x30\x5f\x31\x35\
+\x39\0\x4c\x42\x42\x30\x5f\x34\x39\0\x4c\x42\x42\x30\x5f\x38\x34\x39\0\x4c\x42\
+\x42\x30\x5f\x32\x34\x39\0\x4c\x42\x42\x30\x5f\x31\x34\x39\0\x4c\x42\x42\x30\
+\x5f\x33\x39\0\x4c\x42\x42\x30\x5f\x38\x33\x39\0\x4c\x42\x42\x30\x5f\x32\x33\
+\x39\0\x4c\x42\x42\x30\x5f\x31\x33\x39\0\x4c\x42\x42\x30\x5f\x32\x39\0\x4c\x42\
+\x42\x30\x5f\x32\x32\x39\0\x4c\x42\x42\x30\x5f\x31\x32\x39\0\x4c\x42\x42\x30\
+\x5f\x31\x39\0\x4c\x42\x42\x30\x5f\x33\x31\x39\0\x4c\x42\x42\x30\x5f\x32\x31\
+\x39\0\x4c\x42\x42\x30\x5f\x31\x31\x39\0\x4c\x42\x42\x30\x5f\x33\x30\x39\0\x4c\
+\x42\x42\x30\x5f\x32\x30\x39\0\x4c\x42\x42\x30\x5f\x31\x30\x39\0\x4c\x42\x42\
+\x30\x5f\x39\x39\x38\0\x4c\x42\x42\x30\x5f\x38\x39\x38\0\x4c\x42\x42\x30\x5f\
+\x37\x39\x38\0\x4c\x42\x42\x30\x5f\x36\x39\x38\0\x4c\x42\x42\x30\x5f\x35\x39\
+\x38\0\x4c\x42\x42\x30\x5f\x34\x39\x38\0\x4c\x42\x42\x30\x5f\x33\x39\x38\0\x4c\
+\x42\x42\x30\x5f\x31\x33\x39\x38\0\x4c\x42\x42\x30\x5f\x31\x32\x39\x38\0\x4c\
+\x42\x42\x30\x5f\x31\x31\x39\x38\0\x4c\x42\x42\x30\x5f\x31\x30\x39\x38\0\x4c\
+\x42\x42\x30\x5f\x39\x38\x38\0\x4c\x42\x42\x30\x5f\x38\x38\x38\0\x4c\x42\x42\
+\x30\x5f\x37\x38\x38\0\x4c\x42\x42\x30\x5f\x36\x38\x38\0\x4c\x42\x42\x30\x5f\
+\x35\x38\x38\0\x4c\x42\x42\x30\x5f\x34\x38\x38\0\x4c\x42\x42\x30\x5f\x33\x38\
+\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x38\x38\0\x4c\x42\x42\x30\x5f\x31\x32\x38\
+\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x38\x38\0\x4c\x42\x42\x30\x5f\x31\x30\x38\
+\x38\0\x4c\x42\x42\x30\x5f\x39\x37\x38\0\x4c\x42\x42\x30\x5f\x38\x37\x38\0\x4c\
+\x42\x42\x30\x5f\x37\x37\x38\0\x4c\x42\x42\x30\x5f\x36\x37\x38\0\x4c\x42\x42\
+\x30\x5f\x35\x37\x38\0\x4c\x42\x42\x30\x5f\x34\x37\x38\0\x4c\x42\x42\x30\x5f\
+\x33\x37\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x37\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x37\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x37\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x37\x38\0\x4c\x42\x42\x30\x5f\x39\x36\x38\0\x4c\x42\x42\x30\x5f\x38\x36\
+\x38\0\x4c\x42\x42\x30\x5f\x37\x36\x38\0\x4c\x42\x42\x30\x5f\x36\x36\x38\0\x4c\
+\x42\x42\x30\x5f\x35\x36\x38\0\x4c\x42\x42\x30\x5f\x34\x36\x38\0\x4c\x42\x42\
+\x30\x5f\x33\x36\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x36\x38\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x36\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x36\x38\0\x4c\x42\x42\x30\
+\x5f\x31\x30\x36\x38\0\x4c\x42\x42\x30\x5f\x39\x35\x38\0\x4c\x42\x42\x30\x5f\
+\x38\x35\x38\0\x4c\x42\x42\x30\x5f\x37\x35\x38\0\x4c\x42\x42\x30\x5f\x36\x35\
+\x38\0\x4c\x42\x42\x30\x5f\x35\x35\x38\0\x4c\x42\x42\x30\x5f\x34\x35\x38\0\x4c\
+\x42\x42\x30\x5f\x33\x35\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x35\x38\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x35\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x35\x38\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x35\x38\0\x4c\x42\x42\x30\x5f\x39\x34\x38\0\x4c\x42\x42\
+\x30\x5f\x38\x34\x38\0\x4c\x42\x42\x30\x5f\x37\x34\x38\0\x4c\x42\x42\x30\x5f\
+\x36\x34\x38\0\x4c\x42\x42\x30\x5f\x35\x34\x38\0\x4c\x42\x42\x30\x5f\x34\x34\
+\x38\0\x4c\x42\x42\x30\x5f\x33\x34\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x34\x38\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x34\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x34\x38\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x34\x38\0\x4c\x42\x42\x30\x5f\x39\x33\x38\0\x4c\
+\x42\x42\x30\x5f\x37\x33\x38\0\x4c\x42\x42\x30\x5f\x36\x33\x38\0\x4c\x42\x42\
+\x30\x5f\x35\x33\x38\0\x4c\x42\x42\x30\x5f\x34\x33\x38\0\x4c\x42\x42\x30\x5f\
+\x33\x33\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x33\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x33\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x33\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x33\x38\0\x4c\x42\x42\x30\x5f\x39\x32\x38\0\x4c\x42\x42\x30\x5f\x37\x32\
+\x38\0\x4c\x42\x42\x30\x5f\x36\x32\x38\0\x4c\x42\x42\x30\x5f\x35\x32\x38\0\x4c\
+\x42\x42\x30\x5f\x34\x32\x38\0\x4c\x42\x42\x30\x5f\x33\x32\x38\0\x4c\x42\x42\
+\x30\x5f\x31\x33\x32\x38\0\x4c\x42\x42\x30\x5f\x31\x32\x32\x38\0\x4c\x42\x42\
+\x30\x5f\x31\x31\x32\x38\0\x4c\x42\x42\x30\x5f\x31\x30\x32\x38\0\x4c\x42\x42\
+\x30\x5f\x39\x31\x38\0\x4c\x42\x42\x30\x5f\x38\x31\x38\0\x4c\x42\x42\x30\x5f\
+\x37\x31\x38\0\x4c\x42\x42\x30\x5f\x36\x31\x38\0\x4c\x42\x42\x30\x5f\x35\x31\
+\x38\0\x4c\x42\x42\x30\x5f\x34\x31\x38\0\x4c\x42\x42\x30\x5f\x31\x33\x31\x38\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x31\x38\0\x4c\x42\x42\x30\x5f\x31\x31\x31\x38\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x31\x38\0\x4c\x42\x42\x30\x5f\x39\x30\x38\0\x4c\
+\x42\x42\x30\x5f\x38\x30\x38\0\x4c\x42\x42\x30\x5f\x37\x30\x38\0\x4c\x42\x42\
+\x30\x5f\x36\x30\x38\0\x4c\x42\x42\x30\x5f\x35\x30\x38\0\x4c\x42\x42\x30\x5f\
+\x34\x30\x38\0\x4c\x42\x42\x30\x5f\x31\x34\x30\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x33\x30\x38\0\x4c\x42\x42\x30\x5f\x31\x32\x30\x38\0\x4c\x42\x42\x30\x5f\x31\
+\x31\x30\x38\0\x4c\x42\x42\x30\x5f\x31\x30\x30\x38\0\x4c\x42\x42\x30\x5f\x39\
+\x37\0\x4c\x42\x42\x30\x5f\x32\x39\x37\0\x4c\x42\x42\x30\x5f\x31\x39\x37\0\x4c\
+\x42\x42\x30\x5f\x38\x37\0\x4c\x42\x42\x30\x5f\x32\x38\x37\0\x4c\x42\x42\x30\
+\x5f\x31\x38\x37\0\x4c\x42\x42\x30\x5f\x37\x37\0\x4c\x42\x42\x30\x5f\x32\x37\
+\x37\0\x4c\x42\x42\x30\x5f\x31\x37\x37\0\x4c\x42\x42\x30\x5f\x36\x37\0\x4c\x42\
+\x42\x30\x5f\x32\x36\x37\0\x4c\x42\x42\x30\x5f\x31\x36\x37\0\x4c\x42\x42\x30\
+\x5f\x35\x37\0\x4c\x42\x42\x30\x5f\x32\x35\x37\0\x4c\x42\x42\x30\x5f\x31\x35\
+\x37\0\x4c\x42\x42\x30\x5f\x34\x37\0\x4c\x42\x42\x30\x5f\x32\x34\x37\0\x4c\x42\
+\x42\x30\x5f\x31\x34\x37\0\x4c\x42\x42\x30\x5f\x33\x37\0\x4c\x42\x42\x30\x5f\
+\x38\x33\x37\0\x4c\x42\x42\x30\x5f\x32\x33\x37\0\x4c\x42\x42\x30\x5f\x32\x37\0\
+\x4c\x42\x42\x30\x5f\x38\x32\x37\0\x4c\x42\x42\x30\x5f\x32\x32\x37\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x37\0\x4c\x42\x42\x30\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\
+\x33\x31\x37\0\x4c\x42\x42\x30\x5f\x32\x31\x37\0\x4c\x42\x42\x30\x5f\x31\x31\
+\x37\0\x4c\x42\x42\x30\x5f\x33\x30\x37\0\x4c\x42\x42\x30\x5f\x32\x30\x37\0\x4c\
+\x42\x42\x30\x5f\x31\x30\x37\0\x4c\x42\x42\x30\x5f\x39\x39\x36\0\x4c\x42\x42\
+\x30\x5f\x38\x39\x36\0\x4c\x42\x42\x30\x5f\x37\x39\x36\0\x4c\x42\x42\x30\x5f\
+\x36\x39\x36\0\x4c\x42\x42\x30\x5f\x35\x39\x36\0\x4c\x42\x42\x30\x5f\x34\x39\
+\x36\0\x4c\x42\x42\x30\x5f\x33\x39\x36\0\x4c\x42\x42\x30\x5f\x31\x33\x39\x36\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x39\x36\0\x4c\x42\x42\x30\x5f\x31\x31\x39\x36\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x39\x36\0\x4c\x42\x42\x30\x5f\x39\x38\x36\0\x4c\
+\x42\x42\x30\x5f\x38\x38\x36\0\x4c\x42\x42\x30\x5f\x37\x38\x36\0\x4c\x42\x42\
+\x30\x5f\x36\x38\x36\0\x4c\x42\x42\x30\x5f\x35\x38\x36\0\x4c\x42\x42\x30\x5f\
+\x34\x38\x36\0\x4c\x42\x42\x30\x5f\x33\x38\x36\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x38\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x38\x36\0\x4c\x42\x42\x30\x5f\x31\x31\
+\x38\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x38\x36\0\x4c\x42\x42\x30\x5f\x39\x37\
+\x36\0\x4c\x42\x42\x30\x5f\x38\x37\x36\0\x4c\x42\x42\x30\x5f\x37\x37\x36\0\x4c\
+\x42\x42\x30\x5f\x36\x37\x36\0\x4c\x42\x42\x30\x5f\x35\x37\x36\0\x4c\x42\x42\
+\x30\x5f\x34\x37\x36\0\x4c\x42\x42\x30\x5f\x33\x37\x36\0\x4c\x42\x42\x30\x5f\
+\x31\x33\x37\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x37\x36\0\x4c\x42\x42\x30\x5f\
+\x31\x31\x37\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x37\x36\0\x4c\x42\x42\x30\x5f\
+\x39\x36\x36\0\x4c\x42\x42\x30\x5f\x38\x36\x36\0\x4c\x42\x42\x30\x5f\x37\x36\
+\x36\0\x4c\x42\x42\x30\x5f\x36\x36\x36\0\x4c\x42\x42\x30\x5f\x35\x36\x36\0\x4c\
+\x42\x42\x30\x5f\x34\x36\x36\0\x4c\x42\x42\x30\x5f\x33\x36\x36\0\x4c\x42\x42\
+\x30\x5f\x31\x33\x36\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x36\x36\0\x4c\x42\x42\
+\x30\x5f\x31\x31\x36\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x36\x36\0\x4c\x42\x42\
+\x30\x5f\x39\x35\x36\0\x4c\x42\x42\x30\x5f\x38\x35\x36\0\x4c\x42\x42\x30\x5f\
+\x37\x35\x36\0\x4c\x42\x42\x30\x5f\x36\x35\x36\0\x4c\x42\x42\x30\x5f\x35\x35\
+\x36\0\x4c\x42\x42\x30\x5f\x34\x35\x36\0\x4c\x42\x42\x30\x5f\x33\x35\x36\0\x4c\
+\x42\x42\x30\x5f\x31\x33\x35\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x35\x36\0\x4c\
+\x42\x42\x30\x5f\x31\x31\x35\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x35\x36\0\x4c\
+\x42\x42\x30\x5f\x39\x34\x36\0\x4c\x42\x42\x30\x5f\x37\x34\x36\0\x4c\x42\x42\
+\x30\x5f\x36\x34\x36\0\x4c\x42\x42\x30\x5f\x35\x34\x36\0\x4c\x42\x42\x30\x5f\
+\x34\x34\x36\0\x4c\x42\x42\x30\x5f\x33\x34\x36\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x34\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x34\x36\0\x4c\x42\x42\x30\x5f\x31\x31\
+\x34\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x34\x36\0\x4c\x42\x42\x30\x5f\x39\x33\
+\x36\0\x4c\x42\x42\x30\x5f\x37\x33\x36\0\x4c\x42\x42\x30\x5f\x36\x33\x36\0\x4c\
+\x42\x42\x30\x5f\x35\x33\x36\0\x4c\x42\x42\x30\x5f\x34\x33\x36\0\x4c\x42\x42\
+\x30\x5f\x33\x33\x36\0\x4c\x42\x42\x30\x5f\x31\x33\x33\x36\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x33\x36\0\x4c\x42\x42\x30\x5f\x31\x33\x36\0\x4c\x42\x42\x30\x5f\
+\x31\x31\x33\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x33\x36\0\x4c\x42\x42\x30\x5f\
+\x39\x32\x36\0\x4c\x42\x42\x30\x5f\x37\x32\x36\0\x4c\x42\x42\x30\x5f\x36\x32\
+\x36\0\x4c\x42\x42\x30\x5f\x35\x32\x36\0\x4c\x42\x42\x30\x5f\x34\x32\x36\0\x4c\
+\x42\x42\x30\x5f\x31\x33\x32\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x32\x36\0\x4c\
+\x42\x42\x30\x5f\x31\x31\x32\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x32\x36\0\x4c\
+\x42\x42\x30\x5f\x39\x31\x36\0\x4c\x42\x42\x30\x5f\x38\x31\x36\0\x4c\x42\x42\
+\x30\x5f\x37\x31\x36\0\x4c\x42\x42\x30\x5f\x36\x31\x36\0\x4c\x42\x42\x30\x5f\
+\x35\x31\x36\0\x4c\x42\x42\x30\x5f\x34\x31\x36\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x31\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x31\x36\0\x4c\x42\x42\x30\x5f\x31\x31\
+\x31\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x31\x36\0\x4c\x42\x42\x30\x5f\x39\x30\
+\x36\0\x4c\x42\x42\x30\x5f\x38\x30\x36\0\x4c\x42\x42\x30\x5f\x37\x30\x36\0\x4c\
+\x42\x42\x30\x5f\x36\x30\x36\0\x4c\x42\x42\x30\x5f\x35\x30\x36\0\x4c\x42\x42\
+\x30\x5f\x34\x30\x36\0\x4c\x42\x42\x30\x5f\x31\x34\x30\x36\0\x4c\x42\x42\x30\
+\x5f\x31\x33\x30\x36\0\x4c\x42\x42\x30\x5f\x31\x32\x30\x36\0\x4c\x42\x42\x30\
+\x5f\x31\x31\x30\x36\0\x4c\x42\x42\x30\x5f\x31\x30\x30\x36\0\x4c\x42\x42\x30\
+\x5f\x35\0\x4c\x42\x42\x30\x5f\x39\x35\0\x4c\x42\x42\x30\x5f\x32\x39\x35\0\x4c\
+\x42\x42\x30\x5f\x31\x39\x35\0\x4c\x42\x42\x30\x5f\x38\x35\0\x4c\x42\x42\x30\
+\x5f\x32\x38\x35\0\x4c\x42\x42\x30\x5f\x31\x38\x35\0\x4c\x42\x42\x30\x5f\x37\
+\x35\0\x4c\x42\x42\x30\x5f\x32\x37\x35\0\x4c\x42\x42\x30\x5f\x31\x37\x35\0\x4c\
+\x42\x42\x30\x5f\x36\x35\0\x4c\x42\x42\x30\x5f\x32\x36\x35\0\x4c\x42\x42\x30\
+\x5f\x31\x36\x35\0\x4c\x42\x42\x30\x5f\x35\x35\0\x4c\x42\x42\x30\x5f\x32\x35\
+\x35\0\x4c\x42\x42\x30\x5f\x31\x35\x35\0\x4c\x42\x42\x30\x5f\x34\x35\0\x4c\x42\
+\x42\x30\x5f\x38\x34\x35\0\x4c\x42\x42\x30\x5f\x32\x34\x35\0\x4c\x42\x42\x30\
+\x5f\x31\x34\x35\0\x4c\x42\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x32\x33\
+\x35\0\x4c\x42\x42\x30\x5f\x32\x35\0\x4c\x42\x42\x30\x5f\x38\x32\x35\0\x4c\x42\
+\x42\x30\x5f\x32\x32\x35\0\x4c\x42\x42\x30\x5f\x31\x32\x35\0\x4c\x42\x42\x30\
+\x5f\x31\x35\0\x4c\x42\x42\x30\x5f\x33\x31\x35\0\x4c\x42\x42\x30\x5f\x32\x31\
+\x35\0\x4c\x42\x42\x30\x5f\x31\x31\x35\0\x4c\x42\x42\x30\x5f\x33\x30\x35\0\x4c\
+\x42\x42\x30\x5f\x32\x30\x35\0\x4c\x42\x42\x30\x5f\x31\x30\x35\0\x4c\x42\x42\
+\x30\x5f\x39\x39\x34\0\x4c\x42\x42\x30\x5f\x38\x39\x34\0\x4c\x42\x42\x30\x5f\
+\x37\x39\x34\0\x4c\x42\x42\x30\x5f\x36\x39\x34\0\x4c\x42\x42\x30\x5f\x35\x39\
+\x34\0\x4c\x42\x42\x30\x5f\x34\x39\x34\0\x4c\x42\x42\x30\x5f\x33\x39\x34\0\x4c\
+\x42\x42\x30\x5f\x31\x33\x39\x34\0\x4c\x42\x42\x30\x5f\x31\x32\x39\x34\0\x4c\
+\x42\x42\x30\x5f\x31\x31\x39\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x39\x34\0\x4c\
+\x42\x42\x30\x5f\x39\x38\x34\0\x4c\x42\x42\x30\x5f\x38\x38\x34\0\x4c\x42\x42\
+\x30\x5f\x37\x38\x34\0\x4c\x42\x42\x30\x5f\x36\x38\x34\0\x4c\x42\x42\x30\x5f\
+\x35\x38\x34\0\x4c\x42\x42\x30\x5f\x34\x38\x34\0\x4c\x42\x42\x30\x5f\x33\x38\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x38\x34\0\x4c\x42\x42\x30\x5f\x31\x32\x38\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x38\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x38\
+\x34\0\x4c\x42\x42\x30\x5f\x39\x37\x34\0\x4c\x42\x42\x30\x5f\x38\x37\x34\0\x4c\
+\x42\x42\x30\x5f\x37\x37\x34\0\x4c\x42\x42\x30\x5f\x36\x37\x34\0\x4c\x42\x42\
+\x30\x5f\x35\x37\x34\0\x4c\x42\x42\x30\x5f\x34\x37\x34\0\x4c\x42\x42\x30\x5f\
+\x33\x37\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x37\x34\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x37\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x37\x34\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x37\x34\0\x4c\x42\x42\x30\x5f\x39\x36\x34\0\x4c\x42\x42\x30\x5f\x38\x36\
+\x34\0\x4c\x42\x42\x30\x5f\x37\x36\x34\0\x4c\x42\x42\x30\x5f\x36\x36\x34\0\x4c\
+\x42\x42\x30\x5f\x35\x36\x34\0\x4c\x42\x42\x30\x5f\x34\x36\x34\0\x4c\x42\x42\
+\x30\x5f\x33\x36\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x36\x34\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x36\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x36\x34\0\x4c\x42\x42\x30\
+\x5f\x31\x30\x36\x34\0\x4c\x42\x42\x30\x5f\x39\x35\x34\0\x4c\x42\x42\x30\x5f\
+\x38\x35\x34\0\x4c\x42\x42\x30\x5f\x37\x35\x34\0\x4c\x42\x42\x30\x5f\x36\x35\
+\x34\0\x4c\x42\x42\x30\x5f\x35\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x35\x34\0\x4c\
+\x42\x42\x30\x5f\x33\x35\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x35\x34\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x35\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x35\x34\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x35\x34\0\x4c\x42\x42\x30\x5f\x39\x34\x34\0\x4c\x42\x42\
+\x30\x5f\x37\x34\x34\0\x4c\x42\x42\x30\x5f\x36\x34\x34\0\x4c\x42\x42\x30\x5f\
+\x35\x34\x34\0\x4c\x42\x42\x30\x5f\x34\x34\x34\0\x4c\x42\x42\x30\x5f\x33\x34\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x34\x34\0\x4c\x42\x42\x30\x5f\x31\x32\x34\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x34\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x34\
+\x34\0\x4c\x42\x42\x30\x5f\x39\x33\x34\0\x4c\x42\x42\x30\x5f\x37\x33\x34\0\x4c\
+\x42\x42\x30\x5f\x36\x33\x34\0\x4c\x42\x42\x30\x5f\x35\x33\x34\0\x4c\x42\x42\
+\x30\x5f\x34\x33\x34\0\x4c\x42\x42\x30\x5f\x33\x33\x34\0\x4c\x42\x42\x30\x5f\
+\x31\x33\x33\x34\0\x4c\x42\x42\x30\x5f\x31\x32\x33\x34\0\x4c\x42\x42\x30\x5f\
+\x31\x31\x33\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x33\x34\0\x4c\x42\x42\x30\x5f\
+\x39\x32\x34\0\x4c\x42\x42\x30\x5f\x37\x32\x34\0\x4c\x42\x42\x30\x5f\x36\x32\
+\x34\0\x4c\x42\x42\x30\x5f\x35\x32\x34\0\x4c\x42\x42\x30\x5f\x34\x32\x34\0\x4c\
+\x42\x42\x30\x5f\x33\x32\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x32\x34\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x32\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x32\x34\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x32\x34\0\x4c\x42\x42\x30\x5f\x39\x31\x34\0\x4c\x42\x42\
+\x30\x5f\x38\x31\x34\0\x4c\x42\x42\x30\x5f\x37\x31\x34\0\x4c\x42\x42\x30\x5f\
+\x36\x31\x34\0\x4c\x42\x42\x30\x5f\x35\x31\x34\0\x4c\x42\x42\x30\x5f\x34\x31\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x31\x34\0\x4c\x42\x42\x30\x5f\x31\x32\x31\
+\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x31\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x31\
+\x34\0\x4c\x42\x42\x30\x5f\x39\x30\x34\0\x4c\x42\x42\x30\x5f\x38\x30\x34\0\x4c\
+\x42\x42\x30\x5f\x37\x30\x34\0\x4c\x42\x42\x30\x5f\x36\x30\x34\0\x4c\x42\x42\
+\x30\x5f\x35\x30\x34\0\x4c\x42\x42\x30\x5f\x34\x30\x34\0\x4c\x42\x42\x30\x5f\
+\x31\x34\x30\x34\0\x4c\x42\x42\x30\x5f\x31\x33\x30\x34\0\x4c\x42\x42\x30\x5f\
+\x31\x32\x30\x34\0\x4c\x42\x42\x30\x5f\x31\x31\x30\x34\0\x4c\x42\x42\x30\x5f\
+\x31\x30\x30\x34\0\x4c\x42\x42\x30\x5f\x39\x33\0\x4c\x42\x42\x30\x5f\x32\x39\
+\x33\0\x4c\x42\x42\x30\x5f\x31\x39\x33\0\x4c\x42\x42\x30\x5f\x38\x33\0\x4c\x42\
+\x42\x30\x5f\x32\x38\x33\0\x4c\x42\x42\x30\x5f\x31\x38\x33\0\x4c\x42\x42\x30\
+\x5f\x37\x33\0\x4c\x42\x42\x30\x5f\x32\x37\x33\0\x4c\x42\x42\x30\x5f\x31\x37\
+\x33\0\x4c\x42\x42\x30\x5f\x36\x33\0\x4c\x42\x42\x30\x5f\x32\x36\x33\0\x4c\x42\
+\x42\x30\x5f\x31\x36\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\x4c\x42\x42\x30\x5f\
+\x32\x35\x33\0\x4c\x42\x42\x30\x5f\x31\x35\x33\0\x4c\x42\x42\x30\x5f\x34\x33\0\
+\x4c\x42\x42\x30\x5f\x38\x34\x33\0\x4c\x42\x42\x30\x5f\x32\x34\x33\0\x4c\x42\
+\x42\x30\x5f\x31\x34\x33\0\x4c\x42\x42\x30\x5f\x33\x33\0\x4c\x42\x42\x30\x5f\
+\x38\x33\x33\0\x4c\x42\x42\x30\x5f\x32\x33\x33\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x33\0\x4c\x42\x42\x30\x5f\x32\x33\0\x4c\x42\x42\x30\x5f\x33\x32\x33\0\x4c\x42\
+\x42\x30\x5f\x32\x32\x33\0\x4c\x42\x42\x30\x5f\x31\x32\x33\0\x4c\x42\x42\x30\
+\x5f\x31\x33\0\x4c\x42\x42\x30\x5f\x33\x31\x33\0\x4c\x42\x42\x30\x5f\x32\x31\
+\x33\0\x4c\x42\x42\x30\x5f\x31\x31\x33\0\x4c\x42\x42\x30\x5f\x33\x30\x33\0\x4c\
+\x42\x42\x30\x5f\x32\x30\x33\0\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\x42\
+\x30\x5f\x32\0\x4c\x42\x42\x30\x5f\x39\x39\x32\0\x4c\x42\x42\x30\x5f\x38\x39\
+\x32\0\x4c\x42\x42\x30\x5f\x37\x39\x32\0\x4c\x42\x42\x30\x5f\x36\x39\x32\0\x4c\
+\x42\x42\x30\x5f\x35\x39\x32\0\x4c\x42\x42\x30\x5f\x34\x39\x32\0\x4c\x42\x42\
+\x30\x5f\x33\x39\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x39\x32\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x39\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x39\x32\0\x4c\x42\x42\x30\
+\x5f\x31\x30\x39\x32\0\x4c\x42\x42\x30\x5f\x39\x38\x32\0\x4c\x42\x42\x30\x5f\
+\x38\x38\x32\0\x4c\x42\x42\x30\x5f\x37\x38\x32\0\x4c\x42\x42\x30\x5f\x36\x38\
+\x32\0\x4c\x42\x42\x30\x5f\x35\x38\x32\0\x4c\x42\x42\x30\x5f\x34\x38\x32\0\x4c\
+\x42\x42\x30\x5f\x33\x38\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x38\x32\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x38\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x38\x32\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x38\x32\0\x4c\x42\x42\x30\x5f\x39\x37\x32\0\x4c\x42\x42\
+\x30\x5f\x38\x37\x32\0\x4c\x42\x42\x30\x5f\x37\x37\x32\0\x4c\x42\x42\x30\x5f\
+\x36\x37\x32\0\x4c\x42\x42\x30\x5f\x35\x37\x32\0\x4c\x42\x42\x30\x5f\x34\x37\
+\x32\0\x4c\x42\x42\x30\x5f\x33\x37\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x37\x32\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x37\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x37\x32\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x37\x32\0\x4c\x42\x42\x30\x5f\x39\x36\x32\0\x4c\
+\x42\x42\x30\x5f\x38\x36\x32\0\x4c\x42\x42\x30\x5f\x37\x36\x32\0\x4c\x42\x42\
+\x30\x5f\x36\x36\x32\0\x4c\x42\x42\x30\x5f\x35\x36\x32\0\x4c\x42\x42\x30\x5f\
+\x34\x36\x32\0\x4c\x42\x42\x30\x5f\x33\x36\x32\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x36\x32\0\x4c\x42\x42\x30\x5f\x31\x32\x36\x32\0\x4c\x42\x42\x30\x5f\x31\x31\
+\x36\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x36\x32\0\x4c\x42\x42\x30\x5f\x39\x35\
+\x32\0\x4c\x42\x42\x30\x5f\x37\x35\x32\0\x4c\x42\x42\x30\x5f\x36\x35\x32\0\x4c\
+\x42\x42\x30\x5f\x35\x35\x32\0\x4c\x42\x42\x30\x5f\x34\x35\x32\0\x4c\x42\x42\
+\x30\x5f\x33\x35\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x35\x32\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x35\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x35\x32\0\x4c\x42\x42\x30\
+\x5f\x31\x30\x35\x32\0\x4c\x42\x42\x30\x5f\x39\x34\x32\0\x4c\x42\x42\x30\x5f\
+\x37\x34\x32\0\x4c\x42\x42\x30\x5f\x36\x34\x32\0\x4c\x42\x42\x30\x5f\x35\x34\
+\x32\0\x4c\x42\x42\x30\x5f\x34\x34\x32\0\x4c\x42\x42\x30\x5f\x33\x34\x32\0\x4c\
+\x42\x42\x30\x5f\x31\x33\x34\x32\0\x4c\x42\x42\x30\x5f\x31\x32\x34\x32\0\x4c\
+\x42\x42\x30\x5f\x31\x31\x34\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x34\x32\0\x4c\
+\x42\x42\x30\x5f\x39\x33\x32\0\x4c\x42\x42\x30\x5f\x37\x33\x32\0\x4c\x42\x42\
+\x30\x5f\x36\x33\x32\0\x4c\x42\x42\x30\x5f\x35\x33\x32\0\x4c\x42\x42\x30\x5f\
+\x34\x33\x32\0\x4c\x42\x42\x30\x5f\x33\x33\x32\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x33\x32\0\x4c\x42\x42\x30\x5f\x31\x32\x33\x32\0\x4c\x42\x42\x30\x5f\x31\x33\
+\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x33\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x33\
+\x32\0\x4c\x42\x42\x30\x5f\x39\x32\x32\0\x4c\x42\x42\x30\x5f\x38\x32\x32\0\x4c\
+\x42\x42\x30\x5f\x37\x32\x32\0\x4c\x42\x42\x30\x5f\x36\x32\x32\0\x4c\x42\x42\
+\x30\x5f\x35\x32\x32\0\x4c\x42\x42\x30\x5f\x34\x32\x32\0\x4c\x42\x42\x30\x5f\
+\x31\x33\x32\x32\0\x4c\x42\x42\x30\x5f\x31\x32\x32\x32\0\x4c\x42\x42\x30\x5f\
+\x31\x31\x32\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x32\x32\0\x4c\x42\x42\x30\x5f\
+\x39\x31\x32\0\x4c\x42\x42\x30\x5f\x38\x31\x32\0\x4c\x42\x42\x30\x5f\x37\x31\
+\x32\0\x4c\x42\x42\x30\x5f\x36\x31\x32\0\x4c\x42\x42\x30\x5f\x35\x31\x32\0\x4c\
+\x42\x42\x30\x5f\x34\x31\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x31\x32\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x31\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x31\x32\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x31\x32\0\x4c\x42\x42\x30\x5f\x39\x30\x32\0\x4c\x42\x42\
+\x30\x5f\x38\x30\x32\0\x4c\x42\x42\x30\x5f\x37\x30\x32\0\x4c\x42\x42\x30\x5f\
+\x36\x30\x32\0\x4c\x42\x42\x30\x5f\x35\x30\x32\0\x4c\x42\x42\x30\x5f\x34\x30\
+\x32\0\x4c\x42\x42\x30\x5f\x31\x34\x30\x32\0\x4c\x42\x42\x30\x5f\x31\x33\x30\
+\x32\0\x4c\x42\x42\x30\x5f\x31\x32\x30\x32\0\x4c\x42\x42\x30\x5f\x31\x31\x30\
+\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x30\x32\0\x72\x73\x73\x5f\x66\x6c\x6f\x77\
+\x5f\x61\x63\x74\x69\x6f\x6e\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\x2e\x32\0\x4c\x42\
+\x42\x30\x5f\x39\x31\0\x4c\x42\x42\x30\x5f\x32\x39\x31\0\x4c\x42\x42\x30\x5f\
+\x31\x39\x31\0\x4c\x42\x42\x30\x5f\x38\x31\0\x4c\x42\x42\x30\x5f\x32\x38\x31\0\
+\x4c\x42\x42\x30\x5f\x31\x38\x31\0\x4c\x42\x42\x30\x5f\x37\x31\0\x4c\x42\x42\
+\x30\x5f\x32\x37\x31\0\x4c\x42\x42\x30\x5f\x31\x37\x31\0\x4c\x42\x42\x30\x5f\
+\x36\x31\0\x4c\x42\x42\x30\x5f\x32\x36\x31\0\x4c\x42\x42\x30\x5f\x31\x36\x31\0\
+\x4c\x42\x42\x30\x5f\x35\x31\0\x4c\x42\x42\x30\x5f\x38\x35\x31\0\x4c\x42\x42\
+\x30\x5f\x32\x35\x31\0\x4c\x42\x42\x30\x5f\x31\x35\x31\0\x4c\x42\x42\x30\x5f\
+\x34\x31\0\x4c\x42\x42\x30\x5f\x32\x34\x31\0\x4c\x42\x42\x30\x5f\x31\x34\x31\0\
+\x4c\x42\x42\x30\x5f\x33\x31\0\x4c\x42\x42\x30\x5f\x38\x33\x31\0\x4c\x42\x42\
+\x30\x5f\x32\x33\x31\0\x4c\x42\x42\x30\x5f\x31\x33\x31\0\x4c\x42\x42\x30\x5f\
+\x32\x31\0\x4c\x42\x42\x30\x5f\x33\x32\x31\0\x4c\x42\x42\x30\x5f\x32\x32\x31\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x31\0\x4c\x42\x42\x30\x5f\x31\x31\0\x4c\x42\x42\
+\x30\x5f\x31\x34\x31\x31\0\x4c\x42\x42\x30\x5f\x33\x31\x31\0\x4c\x42\x42\x30\
+\x5f\x32\x31\x31\0\x4c\x42\x42\x30\x5f\x31\x31\x31\0\x4c\x42\x42\x30\x5f\x33\
+\x30\x31\0\x4c\x42\x42\x30\x5f\x32\x30\x31\0\x4c\x42\x42\x30\x5f\x31\x30\x31\0\
+\x72\x73\x73\x5f\x66\x6c\x6f\x77\x5f\x61\x63\x74\x69\x6f\x6e\x2e\x5f\x5f\x5f\
+\x5f\x66\x6d\x74\x2e\x31\0\x2e\x72\x6f\x64\x61\x74\x61\x2e\x73\x74\x72\x31\x2e\
+\x31\0\x4c\x42\x42\x30\x5f\x39\x39\x30\0\x4c\x42\x42\x30\x5f\x38\x39\x30\0\x4c\
+\x42\x42\x30\x5f\x37\x39\x30\0\x4c\x42\x42\x30\x5f\x36\x39\x30\0\x4c\x42\x42\
+\x30\x5f\x35\x39\x30\0\x4c\x42\x42\x30\x5f\x34\x39\x30\0\x4c\x42\x42\x30\x5f\
+\x33\x39\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x39\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x39\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x39\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x39\x30\0\x4c\x42\x42\x30\x5f\x39\x38\x30\0\x4c\x42\x42\x30\x5f\x38\x38\
+\x30\0\x4c\x42\x42\x30\x5f\x37\x38\x30\0\x4c\x42\x42\x30\x5f\x36\x38\x30\0\x4c\
+\x42\x42\x30\x5f\x35\x38\x30\0\x4c\x42\x42\x30\x5f\x34\x38\x30\0\x4c\x42\x42\
+\x30\x5f\x33\x38\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x38\x30\0\x4c\x42\x42\x30\
+\x5f\x31\x32\x38\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x38\x30\0\x4c\x42\x42\x30\
+\x5f\x31\x30\x38\x30\0\x4c\x42\x42\x30\x5f\x39\x37\x30\0\x4c\x42\x42\x30\x5f\
+\x38\x37\x30\0\x4c\x42\x42\x30\x5f\x37\x37\x30\0\x4c\x42\x42\x30\x5f\x36\x37\
+\x30\0\x4c\x42\x42\x30\x5f\x35\x37\x30\0\x4c\x42\x42\x30\x5f\x34\x37\x30\0\x4c\
+\x42\x42\x30\x5f\x33\x37\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x37\x30\0\x4c\x42\
+\x42\x30\x5f\x31\x32\x37\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x37\x30\0\x4c\x42\
+\x42\x30\x5f\x31\x30\x37\x30\0\x4c\x42\x42\x30\x5f\x39\x36\x30\0\x4c\x42\x42\
+\x30\x5f\x38\x36\x30\0\x4c\x42\x42\x30\x5f\x37\x36\x30\0\x4c\x42\x42\x30\x5f\
+\x36\x36\x30\0\x4c\x42\x42\x30\x5f\x35\x36\x30\0\x4c\x42\x42\x30\x5f\x34\x36\
+\x30\0\x4c\x42\x42\x30\x5f\x33\x36\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x36\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x36\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x36\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x36\x30\0\x4c\x42\x42\x30\x5f\x39\x35\x30\0\x4c\
+\x42\x42\x30\x5f\x37\x35\x30\0\x4c\x42\x42\x30\x5f\x36\x35\x30\0\x4c\x42\x42\
+\x30\x5f\x35\x35\x30\0\x4c\x42\x42\x30\x5f\x34\x35\x30\0\x4c\x42\x42\x30\x5f\
+\x33\x35\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x35\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x35\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x35\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x35\x30\0\x4c\x42\x42\x30\x5f\x39\x34\x30\0\x4c\x42\x42\x30\x5f\x37\x34\
+\x30\0\x4c\x42\x42\x30\x5f\x36\x34\x30\0\x4c\x42\x42\x30\x5f\x35\x34\x30\0\x4c\
+\x42\x42\x30\x5f\x34\x34\x30\0\x4c\x42\x42\x30\x5f\x33\x34\x30\0\x4c\x42\x42\
+\x30\x5f\x31\x33\x34\x30\0\x4c\x42\x42\x30\x5f\x31\x32\x34\x30\0\x4c\x42\x42\
+\x30\x5f\x31\x31\x34\x30\0\x4c\x42\x42\x30\x5f\x31\x30\x34\x30\0\x4c\x42\x42\
+\x30\x5f\x39\x33\x30\0\x4c\x42\x42\x30\x5f\x37\x33\x30\0\x4c\x42\x42\x30\x5f\
+\x36\x33\x30\0\x4c\x42\x42\x30\x5f\x35\x33\x30\0\x4c\x42\x42\x30\x5f\x34\x33\
+\x30\0\x4c\x42\x42\x30\x5f\x33\x33\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x33\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x32\x33\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x33\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x30\x33\x30\0\x4c\x42\x42\x30\x5f\x39\x32\x30\0\x4c\
+\x42\x42\x30\x5f\x38\x32\x30\0\x4c\x42\x42\x30\x5f\x37\x32\x30\0\x4c\x42\x42\
+\x30\x5f\x36\x32\x30\0\x4c\x42\x42\x30\x5f\x35\x32\x30\0\x4c\x42\x42\x30\x5f\
+\x34\x32\x30\0\x4c\x42\x42\x30\x5f\x31\x33\x32\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x32\x32\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x32\x30\0\x4c\x42\x42\x30\x5f\x31\
+\x30\x32\x30\0\x4c\x42\x42\x30\x5f\x39\x31\x30\0\x4c\x42\x42\x30\x5f\x38\x31\
+\x30\0\x4c\x42\x42\x30\x5f\x37\x31\x30\0\x4c\x42\x42\x30\x5f\x36\x31\x30\0\x4c\
+\x42\x42\x30\x5f\x35\x31\x30\0\x4c\x42\x42\x30\x5f\x34\x31\x30\0\x4c\x42\x42\
+\x30\x5f\x31\x33\x31\x30\0\x4c\x42\x42\x30\x5f\x31\x32\x31\x30\0\x4c\x42\x42\
+\x30\x5f\x31\x31\x31\x30\0\x4c\x42\x42\x30\x5f\x31\x30\x31\x30\0\x4c\x42\x42\
+\x30\x5f\x39\x30\x30\0\x4c\x42\x42\x30\x5f\x38\x30\x30\0\x4c\x42\x42\x30\x5f\
+\x37\x30\x30\0\x4c\x42\x42\x30\x5f\x36\x30\x30\0\x4c\x42\x42\x30\x5f\x35\x30\
+\x30\0\x4c\x42\x42\x30\x5f\x34\x30\x30\0\x4c\x42\x42\x30\x5f\x31\x34\x30\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x33\x30\x30\0\x4c\x42\x42\x30\x5f\x31\x32\x30\x30\0\
+\x4c\x42\x42\x30\x5f\x31\x31\x30\x30\0\x4c\x42\x42\x30\x5f\x31\x30\x30\x30\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\x01\0\0\x03\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x92\x76\x04\0\0\0\0\0\xad\x1a\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0f\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x75\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x40\0\0\0\0\0\0\0\xc8\xf6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\x71\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x37\x03\0\
+\0\0\0\0\x50\0\0\0\0\0\0\0\x1d\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\
+\0\0\xc4\x16\0\0\x01\0\0\0\x32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\xf7\0\0\0\0\0\
+\0\x1c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x80\0\
+\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x28\xf7\0\0\0\0\0\0\x20\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2b\x01\0\0\x01\0\0\
+\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\xf7\0\0\0\0\0\0\x2e\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe8\0\0\0\x01\0\0\0\x03\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x76\xf7\0\0\0\0\0\0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4a\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\x83\xf7\0\0\0\0\0\0\x35\x4f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb8\
+\x46\x01\0\0\0\0\0\xb1\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\xbd\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x69\x49\x01\0\0\
+\0\0\0\x7e\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\xb9\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe8\x37\x03\0\0\0\0\0\
+\x60\0\0\0\0\0\0\0\x1d\0\0\0\x0b\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x3a\
+\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe7\x54\x01\0\0\0\0\0\xcd\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5e\0\0\0\x01\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb4\x55\x01\0\0\0\0\0\x10\x03\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5a\0\0\0\x09\0\0\0\x40\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x48\x38\x03\0\0\0\0\0\x20\x0c\0\0\0\0\0\0\x1d\0\0\0\
+\x0e\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x86\0\0\0\x01\0\0\0\x30\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\xc4\x58\x01\0\0\0\0\0\xee\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\x01\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\xa5\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\xb2\x60\x01\0\0\0\0\0\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\xa1\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x68\x44\x03\0\0\0\0\0\xb0\0\0\0\0\0\0\0\x1d\0\0\0\x11\0\0\0\x08\0\0\0\0\0\0\0\
+\x10\0\0\0\0\0\0\0\x37\x01\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14\
+\x61\x01\0\0\0\0\0\xbe\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\x33\x01\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x45\x03\
+\0\0\0\0\0\x50\0\0\0\0\0\0\0\x1d\0\0\0\x13\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\
+\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd4\x6f\x01\0\0\0\0\
+\0\x30\x30\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x15\
+\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x45\x03\0\0\0\0\0\0\x30\
+\x01\0\0\0\0\0\x1d\0\0\0\x15\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x04\x01\
+\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\xa0\x02\0\0\0\0\0\x28\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\x09\0\0\0\
+\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x75\x04\0\0\0\0\0\x20\0\0\0\0\0\0\0\x1d\
+\0\0\0\x17\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\xf4\0\0\0\x01\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x30\xa0\x02\0\0\0\0\0\x46\x53\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf0\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\x88\x75\x04\0\0\0\0\0\0\x01\0\0\0\0\0\0\x1d\0\0\0\x19\0\0\0\
+\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x91\0\0\0\x01\0\0\0\x30\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x76\xf3\x02\0\0\0\0\0\xcc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\
+\0\0\0\0\x01\0\0\0\0\0\0\0\xd9\0\0\0\x03\x4c\xff\x6f\0\0\0\x80\0\0\0\0\0\0\0\0\
+\0\0\0\0\x88\x76\x04\0\0\0\0\0\x0a\0\0\0\0\0\0\0\x1d\0\0\0\0\0\0\0\x01\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x23\x01\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x48\xf4\x02\0\0\0\0\0\x50\x43\0\0\0\0\0\0\x01\0\0\0\xcb\x02\0\0\x08\0\0\0\0\0\
+\0\0\x18\0\0\0\0\0\0\0";
+}
+
+#ifdef __cplusplus
+struct tap_rss *tap_rss::open(const struct bpf_object_open_opts *opts) { return tap_rss__open_opts(opts); }
+struct tap_rss *tap_rss::open_and_load() { return tap_rss__open_and_load(); }
+int tap_rss::load(struct tap_rss *skel) { return tap_rss__load(skel); }
+int tap_rss::attach(struct tap_rss *skel) { return tap_rss__attach(skel); }
+void tap_rss::detach(struct tap_rss *skel) { tap_rss__detach(skel); }
+void tap_rss::destroy(struct tap_rss *skel) { tap_rss__destroy(skel); }
+const void *tap_rss::elf_bytes(size_t *sz) { return tap_rss__elf_bytes(sz); }
+#endif /* __cplusplus */
+
+__attribute__((unused)) static void
+tap_rss__assert(struct tap_rss *s __attribute__((unused)))
+{
+#ifdef __cplusplus
+#define _Static_assert static_assert
+#endif
+#ifdef __cplusplus
+#undef _Static_assert
+#endif
+}
+
+#endif /* __TAP_RSS_SKEL_H__ */
diff --git a/drivers/net/tap/tap_rss.stub.h b/drivers/net/tap/tap_rss.stub.h
new file mode 100644
index 000000000000..10a1692e1e15
--- /dev/null
+++ b/drivers/net/tap/tap_rss.stub.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Stub if libbpf is not available
+ */
+
+struct bpf_object;
+struct bpf_map;
+
+struct tap_rss {
+	struct bpf_object *obj;
+	struct {
+		struct bpf_map *rss_map;
+	} maps;
+};
+
+static struct tap_rss *tap_rss__open_and_load(void)
+{
+	errno = ENOTSUP;
+	return NULL;
+}
+
+static void tap_rss__destroy(struct tap_rss *obj)
+{
+}
+
+static int tap_rss__attach(struct tap_rss *obj)
+{
+	return -1;
+}
+
+static int bpf_object__btf_fd(struct bpf_object *obj)
+{
+	return -1;
+}
+
+static int bpf_map__update_elem(const struct bpf_map *map, const void *key, size_t key_size,
+				const void *value, size_t value_size, int flags)
+{
+	return -1;
+}
+
+static int bpf_map__delete_elem(const struct bpf_map *map,
+				const void *key, size_t key_size, int flags)
+{
+	return -1;
+}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 0/7] net/tap: RSS using BPF overhaul
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
  2024-01-30  3:46 ` [RFC 1/2] tap: stop "vendoring" linux bpf headers Stephen Hemminger
  2024-01-30  3:46 ` [RFC 2/2] tap: rework BPF handling Stephen Hemminger
@ 2024-02-07 22:11 ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
                     ` (6 more replies)
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                   ` (9 subsequent siblings)
  12 siblings, 7 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

THe support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.
The build process checks for the required components
and if not there will stub out to not supported.

This patch series is mostly the same as the original RFC,
most of the changes are to split it up and always build
the BPF from source.

Stephen Hemminger (7):
  net/tap: remove unused RSS hash types
  net/tap: validate and setup parameters for BPF RSS
  net/tap: stop "vendoring" linux bpf headers
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  MAINTAINERS: add maintainer for TAP device

 .gitignore                            |    3 -
 MAINTAINERS                           |    1 +
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   12 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |   81 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  272 ++++
 drivers/net/tap/meson.build           |   26 +-
 drivers/net/tap/rte_eth_tap.c         |    2 +
 drivers/net/tap/rte_eth_tap.h         |    9 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  531 +++-----
 drivers/net/tap/tap_flow.h            |   11 +-
 drivers/net/tap/tap_rss.h             |   14 +-
 drivers/net/tap/tap_rss.stub.h        |   45 +
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 21 files changed, 584 insertions(+), 3170 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h
 create mode 100644 drivers/net/tap/tap_rss.stub.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v2 1/7] net/tap: remove unused RSS hash types
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_rss.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f94..8766ffc244f6 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 2/7] net/tap: validate and setup parameters for BPF RSS
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 3/7] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_insns.h | 16 ++++----
 drivers/net/tap/tap_flow.c      | 65 ++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h       |  5 +--
 3 files changed, 70 insertions(+), 16 deletions(-)

diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6b0..ee26cf885ed7 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -1709,13 +1709,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    1,    0,        0, 0x00000001},
 	{0x15,    1,    0,        1, 0x00000000},
 	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
+	{0x71,    1,    0,       45, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
+	{0x71,    2,    0,       44, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
+	{0x71,    2,    0,       46, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
+	{0x71,    4,    0,       47, 0x00000000},
 	{0x67,    4,    0,        0, 0x00000018},
 	{0x4f,    4,    2,        0, 0x00000000},
 	{0x4f,    4,    1,        0, 0x00000000},
@@ -1725,13 +1725,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    3,    0,        0, 0x0000000f},
 	{0x67,    3,    0,        0, 0x00000002},
 	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
+	{0x71,    1,    0,       49, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
+	{0x71,    2,    0,       48, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
+	{0x71,    2,    0,       50, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
+	{0x71,    3,    0,       51, 0x00000000},
 	{0x67,    3,    0,        0, 0x00000018},
 	{0x4f,    3,    2,        0, 0x00000000},
 	{0x4f,    3,    1,        0, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index ed4d42f92f9f..cd49aa51c8b0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,8 +11,10 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2053,6 +2055,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2071,11 +2088,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2087,6 +2104,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2101,8 +2153,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244f6..6009be7031b0 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 3/7] net/tap: stop "vendoring" linux bpf headers
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF. This is not
a supportable build method, and not how rest of DPDK works.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

Since DPDK officially supports only LTS or later kernel
there is no need for the #ifdef workarounds in the TAP flow
code. Cloning headers leads to problems and no longer needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   1 -
 drivers/net/tap/tap_flow.c         |  89 ---------------------
 5 files changed, 13 insertions(+), 219 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b809f..73c4dafe4eca 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111fe0..000000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917ed..9e05e2ddf19b 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index ee26cf885ed7..b59b7e9141fd 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,7 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
 
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index cd49aa51c8b0..94436af55ce8 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -20,95 +20,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
 
 /* RSS key management */
 enum bpf_rss_key_e {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 4/7] net/tap: rewrite the RSS BPF program
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-02-07 22:11   ` [PATCH v2 3/7] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 5/7] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  12 ++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 272 +++++++++++++++++++++++++
 9 files changed, 365 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace2e..01a47a760660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc704..000000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 000000000000..960a10da73b8
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,12 @@
+This is the BPF program used to implement the RSS across queues
+flow action. It works like the skbedit tc filter but instead of mapping
+to only one queues, it maps to multiple queues based on RSS hash.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+- requires libbpf version XX or later
+- rebuilding the BPF requires clang and bpftool
+- only Toeplitz hash with standard 40 byte key is supported
+- the number of queues per RSS action is limited to 16
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 2638a8a4ac9a..000000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	({								\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c0f..000000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4eca..000000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 000000000000..f2c03a19fd4d
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c30..000000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 000000000000..1abd18cb606e
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows
+ * which need BPF RSS.
+ *
+ * The hash is indexed by the tc_index.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u16));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_MAX_QUEUES);
+} rss_map SEC(".maps");
+
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/* Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* No L4 if packet is a fragmented */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/* parse ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/* scale value to be into range [0, n), assumes val is large */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/* layout of qdisc skb cb (from sch_generic.h) */
+struct qdisc_skb_cb {
+	struct {
+		unsigned int	pkt_len;
+		__u16		dev_queue_mapping;
+		__u16		tc_classid;
+	};
+#define QDISC_CB_PRIV_LEN 20
+	unsigned char		data[QDISC_CB_PRIV_LEN];
+};
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u16 classid;
+	__u32 hash;
+
+	/* TC layer puts the BPF_CLASSID into the skb cb area */
+	classid = ((const struct qdisc_skb_cb *)skb->cb)->tc_classid;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &classid);
+	if (rsskey == NULL) {
+		bpf_printk("hash(): rss not configured");
+		return TC_ACT_OK;
+	}
+
+	hash = calculate_rss_hash(skb, rsskey);
+	bpf_printk("hash %u\n", hash);
+	if (hash) {
+		/* Fold hash to the number of queues configured */
+		skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+		bpf_printk("queue %u\n", skb->queue_mapping);
+		return TC_ACT_PIPE;
+	}
+	return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 5/7] net/tap: use libbpf to load new BPF program
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-02-07 22:11   ` [PATCH v2 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 6/7] net/tap: remove no longer used files Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It alsow fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/meson.build    |  26 +--
 drivers/net/tap/rte_eth_tap.c  |   2 +
 drivers/net/tap/rte_eth_tap.h  |   9 +-
 drivers/net/tap/tap_flow.c     | 391 +++++++++------------------------
 drivers/net/tap/tap_flow.h     |  11 +-
 drivers/net/tap/tap_rss.h      |   3 +
 drivers/net/tap/tap_rss.stub.h |  45 ++++
 drivers/net/tap/tap_tcmsgs.h   |   4 +-
 8 files changed, 163 insertions(+), 328 deletions(-)
 create mode 100644 drivers/net/tap/tap_rss.stub.h

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff11b..ad51b6bbbb7c 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,21 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
-
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b41fa971cb7e..a98cc8f01ae1 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1138,6 +1138,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1959,6 +1960,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e961..0cf2b30bb03b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@ struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 94436af55ce8..ef34e85c423b 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -16,24 +16,19 @@
 #include <rte_eth_tap.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#pragma GCC diagnostic push
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#else
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include "tap_rss.stub.h"
+#endif
+#pragma GCC diagnostic pop
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +36,7 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
+	uint16_t flowid;
 	struct nlmsg msg;
 };
 
@@ -72,7 +66,7 @@ struct action_data {
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
-			int bpf_fd;
+			uint16_t classid;
 			const char *annotation;
 		} bpf;
 	};
@@ -112,10 +106,7 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
@@ -829,7 +820,8 @@ tap_flow_item_validate(const struct rte_flow_item *item,
  *   -1 on failure, 0 on success
  */
 static int
-add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
+add_action(struct rte_flow *flow, struct pmd_internals *pmd,
+	   size_t *act_index, struct action_data *adata)
 {
 	struct nlmsg *msg = &flow->msg;
 
@@ -858,13 +850,18 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
 			     adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
-		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
+		struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
+
+		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, bpf_program__fd(rss_prog));
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
 			   adata->bpf.annotation);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+		tap_nlattr_add(&msg->nh, TCA_BPF_CLASSID,
+			       sizeof(adata->bpf.classid),
+			       &adata->bpf.classid);
 	} else {
 		return -1;
 	}
@@ -892,7 +889,8 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
  *   -1 on failure, 0 on success
  */
 static int
-add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
+add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
+	    int nb_actions, struct action_data *data,
 	    int classifier_action)
 {
 	struct nlmsg *msg = &flow->msg;
@@ -902,7 +900,7 @@ add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
 	if (tap_nlattr_nested_start(msg, classifier_action) < 0)
 		return -1;
 	for (i = 0; i < nb_actions; i++)
-		if (add_action(flow, &act_index, data + i) < 0)
+		if (add_action(flow, pmd,  &act_index, data + i) < 0)
 			return -1;
 	tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
 	return 0;
@@ -1062,7 +1060,7 @@ priv_flow_process(struct pmd_internals *pmd,
 			adata.mirred.action = TC_ACT_PIPE;
 		else
 			adata.mirred.action = TC_ACT_STOLEN;
-		if (add_actions(flow, 1, &adata, TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, pmd, 1, &adata, TCA_FLOWER_ACT) < 0)
 			goto exit_action_not_supported;
 		else
 			goto end;
@@ -1085,7 +1083,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
+				err = add_actions(flow, pmd, 1, &adata,
 						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
@@ -1101,7 +1099,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
+				err = add_actions(flow, pmd, 1, &adata,
 						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
@@ -1126,8 +1124,8 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-					TCA_FLOWER_ACT);
+				err = add_actions(flow, pmd, 1, &adata,
+						  TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
@@ -1137,8 +1135,8 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_action_not_supported;
 			}
@@ -1241,23 +1239,14 @@ tap_flow_set_handle(struct rte_flow *flow)
 static void
 tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
 {
-	int i;
+	struct tap_rss *rss = pmd->rss;
 
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map, &flow->flowid,
+				     sizeof(flow->flowid), 0);
 
 	/* Free flow allocated memory */
 	rte_free(flow);
@@ -1725,13 +1714,16 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd)
+{
+	if (pmd->rss == NULL)
+		return;
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+}
 
 /**
  * Enable RSS on tap: create TC rules for queuing.
@@ -1747,226 +1739,62 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
+	return 0;
 }
 
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
 
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
+/* Choose next flow id to use for BPF action */
+static int tap_rss_flow_assign(struct pmd_internals *pmd, uint16_t *flow_id)
+{
+	struct rte_flow *flow;
+	uint16_t id;
 
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
+	id = pmd->bpf_flowid;
 
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
+next_id:
+	/* Skip 0xffff and 0 as id's */
+	if (++id == UINT16_MAX)
+		id = 1;
 
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
+	/* Wrapped around, all id's have been used */
+	if (id == pmd->bpf_flowid)
+		return -1;
 
-	default:
-		break;
+	/* Make sure this id has not been used already */
+	for (flow = LIST_FIRST(&pmd->flows); flow; flow = LIST_NEXT(flow, next)) {
+		if (flow->flowid == id)
+			goto next_id;
 	}
 
-	return err;
+	/* Record starting point for next time */
+	pmd->bpf_flowid = id;
+	*flow_id = id;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2050,34 +1878,34 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
+
+	/* Choose new flow id, which is used as index into the BPF map */
+	err = tap_rss_flow_assign(pmd, &flow->flowid);
 	if (err < 0) {
 		rte_flow_error_set(
 			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
+			"Failed to get BPF flowid");
 
 		return -1;
 	}
 
-	/* Update RSS map entry with queues */
-	rss_entry.nb_queues = rss->queue_num;
-	for (i = 0; i < rss->queue_num; i++)
-		rss_entry.queues[i] = rss->queue[i];
-
 	rss_entry.hash_fields = hash_type;
 	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
 			    TAP_RSS_HASH_KEY_SIZE);
 
+	/* Update RSS map entry with queues */
+	rss_entry.nb_queues = rss->queue_num;
+	for (i = 0; i < rss->queue_num; i++)
+		rss_entry.queues[i] = rss->queue[i];
 
 	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
-
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &flow->flowid, sizeof(uint16_t),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
 			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			flow->flowid, errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2086,33 +1914,14 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
 	/* Actions */
 	{
 		struct action_data adata[] = {
 			{
 				.id = "bpf",
 				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
+					.annotation = "tap_rss",
+					.classid = flow->flowid,
 					.bpf = {
 						.action = TC_ACT_PIPE,
 					},
@@ -2120,8 +1929,8 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			},
 		};
 
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, pmd, RTE_DIM(adata), adata,
+				TCA_FLOWER_ACT) < 0)
 			return -1;
 	}
 
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfaef..41f9833619a1 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,6 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +40,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +52,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031b0..51b7ff0d007e 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -9,6 +9,9 @@
 #define TAP_MAX_QUEUES 16
 #endif
 
+/* Size of the map from BPF classid to queue table */
+#define TAP_RSS_MAX	TAP_MAX_QUEUES
+
 /* Fixed RSS hash key size in bytes. */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
diff --git a/drivers/net/tap/tap_rss.stub.h b/drivers/net/tap/tap_rss.stub.h
new file mode 100644
index 000000000000..10a1692e1e15
--- /dev/null
+++ b/drivers/net/tap/tap_rss.stub.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Stub if libbpf is not available
+ */
+
+struct bpf_object;
+struct bpf_map;
+
+struct tap_rss {
+	struct bpf_object *obj;
+	struct {
+		struct bpf_map *rss_map;
+	} maps;
+};
+
+static struct tap_rss *tap_rss__open_and_load(void)
+{
+	errno = ENOTSUP;
+	return NULL;
+}
+
+static void tap_rss__destroy(struct tap_rss *obj)
+{
+}
+
+static int tap_rss__attach(struct tap_rss *obj)
+{
+	return -1;
+}
+
+static int bpf_object__btf_fd(struct bpf_object *obj)
+{
+	return -1;
+}
+
+static int bpf_map__update_elem(const struct bpf_map *map, const void *key, size_t key_size,
+				const void *value, size_t value_size, int flags)
+{
+	return -1;
+}
+
+static int bpf_map__delete_elem(const struct bpf_map *map,
+				const void *key, size_t key_size, int flags)
+{
+	return -1;
+}
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6fa8..00a0f22e3108 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 6/7] net/tap: remove no longer used files
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-02-07 22:11   ` [PATCH v2 5/7] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-07 22:11   ` [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1742 -------------------------------
 2 files changed, 1938 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf19b..000000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index b59b7e9141fd..000000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1742 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,       45, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       44, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       46, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,       47, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,       49, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       48, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       50, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,       51, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-02-07 22:11   ` [PATCH v2 6/7] net/tap: remove no longer used files Stephen Hemminger
@ 2024-02-07 22:11   ` Stephen Hemminger
  2024-02-08  7:01     ` Morten Brørup
  6 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-07 22:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Add myself as maintainer for TAP device.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5fb3a73f840e..92d27e97aa9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1015,6 +1015,7 @@ F: doc/guides/nics/pcap_ring.rst
 F: doc/guides/nics/features/pcap.ini
 
 Tap PMD
+M: Stephen Hemminger <stephen@networkplumber.org>
 F: drivers/net/tap/
 F: doc/guides/nics/tap.rst
 F: doc/guides/nics/features/tap.ini
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* RE: [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device
  2024-02-07 22:11   ` [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
@ 2024-02-08  7:01     ` Morten Brørup
  0 siblings, 0 replies; 133+ messages in thread
From: Morten Brørup @ 2024-02-08  7:01 UTC (permalink / raw)
  To: Stephen Hemminger, dev

> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Wednesday, 7 February 2024 23.11
> 
> Add myself as maintainer for TAP device.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---

Thank you.

Series-acked-by: Morten Brørup <mb@smartsharesystems.com>


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v3 0/7] net/tap: RSS using BPF overhaul
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (2 preceding siblings ...)
  2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
@ 2024-02-08 17:41 ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
                     ` (6 more replies)
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                   ` (8 subsequent siblings)
  12 siblings, 7 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.
The build process checks for the required components
and if not there will stub out to not supported.

This patch series is mostly the same as the original RFC,
most of the changes are to split it up and always build
the BPF from source.

v3 - fix handling of case where libbpf not present and
     therefore the not supported needs to be returned.

Stephen Hemminger (7):
  net/tap: remove unused RSS hash types
  net/tap: validate and setup parameters for BPF RSS
  tap: stop "vendoring" linux bpf headers
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  MAINTAINERS: add maintainer for TAP device

 .gitignore                            |    3 -
 MAINTAINERS                           |    1 +
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   12 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |   81 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_bpf_program.o |  Bin 0 -> 28080 bytes
 drivers/net/tap/bpf/tap_rss.c         |  272 ++++
 drivers/net/tap/meson.build           |   26 +-
 drivers/net/tap/rte_eth_tap.c         |    2 +
 drivers/net/tap/rte_eth_tap.h         |    9 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  521 +++-----
 drivers/net/tap/tap_flow.h            |   11 +-
 drivers/net/tap/tap_rss.h             |   14 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 21 files changed, 534 insertions(+), 3165 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_bpf_program.o
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v3 1/7] net/tap: remove unused RSS hash types
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_rss.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f94..8766ffc244f6 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 2/7] net/tap: validate and setup parameters for BPF RSS
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_insns.h | 16 ++++----
 drivers/net/tap/tap_flow.c      | 65 ++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h       |  5 +--
 3 files changed, 70 insertions(+), 16 deletions(-)

diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6b0..ee26cf885ed7 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -1709,13 +1709,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    1,    0,        0, 0x00000001},
 	{0x15,    1,    0,        1, 0x00000000},
 	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
+	{0x71,    1,    0,       45, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
+	{0x71,    2,    0,       44, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
+	{0x71,    2,    0,       46, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
+	{0x71,    4,    0,       47, 0x00000000},
 	{0x67,    4,    0,        0, 0x00000018},
 	{0x4f,    4,    2,        0, 0x00000000},
 	{0x4f,    4,    1,        0, 0x00000000},
@@ -1725,13 +1725,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    3,    0,        0, 0x0000000f},
 	{0x67,    3,    0,        0, 0x00000002},
 	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
+	{0x71,    1,    0,       49, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
+	{0x71,    2,    0,       48, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
+	{0x71,    2,    0,       50, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
+	{0x71,    3,    0,       51, 0x00000000},
 	{0x67,    3,    0,        0, 0x00000018},
 	{0x4f,    3,    2,        0, 0x00000000},
 	{0x4f,    3,    1,        0, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index ed4d42f92f9f..cd49aa51c8b0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,8 +11,10 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2053,6 +2055,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2071,11 +2088,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2087,6 +2104,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2101,8 +2153,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244f6..6009be7031b0 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 3/7] tap: stop "vendoring" linux bpf headers
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF. This is not
a supportable build method, and not how rest of DPDK works.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

Since DPDK officially supports only LTS or later kernel
there is no need for the #ifdef workarounds in the TAP flow
code. Cloning headers leads to problems and no longer needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   1 -
 drivers/net/tap/tap_flow.c         |  89 ---------------------
 5 files changed, 13 insertions(+), 219 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b809f..73c4dafe4eca 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111fe0..000000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917ed..9e05e2ddf19b 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index ee26cf885ed7..b59b7e9141fd 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,7 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
 
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index cd49aa51c8b0..94436af55ce8 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -20,95 +20,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
 
 /* RSS key management */
 enum bpf_rss_key_e {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 4/7] net/tap: rewrite the RSS BPF program
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-02-08 17:41   ` [PATCH v3 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 5/7] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  12 ++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 272 +++++++++++++++++++++++++
 9 files changed, 365 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace2e..01a47a760660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc704..000000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 000000000000..960a10da73b8
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,12 @@
+This is the BPF program used to implement the RSS across queues
+flow action. It works like the skbedit tc filter but instead of mapping
+to only one queues, it maps to multiple queues based on RSS hash.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+- requires libbpf version XX or later
+- rebuilding the BPF requires clang and bpftool
+- only Toeplitz hash with standard 40 byte key is supported
+- the number of queues per RSS action is limited to 16
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 2638a8a4ac9a..000000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	({								\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c0f..000000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4eca..000000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 000000000000..f2c03a19fd4d
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c30..000000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 000000000000..1abd18cb606e
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows
+ * which need BPF RSS.
+ *
+ * The hash is indexed by the tc_index.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u16));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_MAX_QUEUES);
+} rss_map SEC(".maps");
+
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/* Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* No L4 if packet is a fragmented */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/* parse ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/* scale value to be into range [0, n), assumes val is large */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/* layout of qdisc skb cb (from sch_generic.h) */
+struct qdisc_skb_cb {
+	struct {
+		unsigned int	pkt_len;
+		__u16		dev_queue_mapping;
+		__u16		tc_classid;
+	};
+#define QDISC_CB_PRIV_LEN 20
+	unsigned char		data[QDISC_CB_PRIV_LEN];
+};
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u16 classid;
+	__u32 hash;
+
+	/* TC layer puts the BPF_CLASSID into the skb cb area */
+	classid = ((const struct qdisc_skb_cb *)skb->cb)->tc_classid;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &classid);
+	if (rsskey == NULL) {
+		bpf_printk("hash(): rss not configured");
+		return TC_ACT_OK;
+	}
+
+	hash = calculate_rss_hash(skb, rsskey);
+	bpf_printk("hash %u\n", hash);
+	if (hash) {
+		/* Fold hash to the number of queues configured */
+		skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+		bpf_printk("queue %u\n", skb->queue_mapping);
+		return TC_ACT_PIPE;
+	}
+	return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 5/7] net/tap: use libbpf to load new BPF program
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-02-08 17:41   ` [PATCH v3 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 18:02     ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 6/7] net/tap: remove no longer used files Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
  6 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It alsow fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/tap_bpf_program.o | Bin 0 -> 28080 bytes
 drivers/net/tap/meson.build           |  26 +-
 drivers/net/tap/rte_eth_tap.c         |   2 +
 drivers/net/tap/rte_eth_tap.h         |   9 +-
 drivers/net/tap/tap_flow.c            | 381 +++++++-------------------
 drivers/net/tap/tap_flow.h            |  11 +-
 drivers/net/tap/tap_rss.h             |   3 +
 drivers/net/tap/tap_tcmsgs.h          |   4 +-
 8 files changed, 113 insertions(+), 323 deletions(-)
 create mode 100644 drivers/net/tap/bpf/tap_bpf_program.o

diff --git a/drivers/net/tap/bpf/tap_bpf_program.o b/drivers/net/tap/bpf/tap_bpf_program.o
new file mode 100644
index 0000000000000000000000000000000000000000..db016eaadefc63e0bbc45b3115f497a465438d33
GIT binary patch
literal 28080
zcmbtc4Rl>qnY~G0+W>_|BoeE_McN@Cl-$3Uv<g0c3K4KxghCLQHiWc6TAH*)0!4U`
zq7ki>KaIassx~TUg(Zzk<#m{m2FHQoj1rW=GRzEt@uvbx!3wj_x!?ER_kGkZSo7AR
zci+A5Is4rG&N=U#oA<bO-WjLV*VP65staBUYG=#_!RC+DaLL0`Fb!9B9hmyF=1D>D
zhx_k-lCSEXyZbeVw-C{_F+ZP*>w<~zUcD5@5bz2*UKkhrm0RllA?QAg>c#16c;##m
z+)ki!a1OdY+UP;oz!~}R$_4(|jGIvHnUVWf?##<gh0ku(>#mcp8*t*Ng+Y_2x8UUB
zeS_fA89RL&-1RFiTXKmLmtMZIXU&X>Du2nU@G{4*SRHn+nX#kFuUxe%bo`|~SB7h5
zj92;Iu2sE`Z#i-<`0bwGGSx9bu<EMk{dwi9`T11%Zby4vK8J&H?VN)DCI{=?A#m+H
z0LQMC2f5RrsUD5St83*u{c&M^LohTF1eKNkG+>{~b@{og|3JWFZvJ?+K6ie}$MbwE
zN95O?3)Q_FYpxpe?Q5Fy!@7_E2mH})_tq|)a?O+m9H%$u*YC;4NyprLW!1-B**`eV
z7wEr!AAfABuM6G+w6MO(-)H~zc`*HJeX*c2&tDcSog4(t?_3;%LxW)cteig=-6;f|
ze|CPpu#neZxjsL4@4ri`e`bEZ6xX|U^&f^H@LGz4yYu-c_)}cx?oOP)8x`QS6bI)&
z|1f_VRPt^cxcb^bZKEUi>z+cL@6RrmN3VPEXujUHw}k7Ppu5*5=yy(9cb?Qk@KT>Q
zb;i9?ckPw>jR&Mlr0&`&^`>|A{!Hp<g3{kJcl)r^-5tyF=d9ik^{?F@Eb>P@uH{XW
zYVE&!qSReE$;*Ko?>-MYRxZ!^O?cnVM-a>7yd3jf&edCz_2T+12uA9m(N`cCsry{G
zT`2z~f|0t<Md&|9FjDuq2z?ELk-E=C=zm5q{ex~aA{P|)x$yf6|KA}P&eisl%DKLn
zfB%1tV3waqxe(9g_S9dtAQ-8Ks7k(HD-ev-ZGZU<f|0uIFBJqMb=zOAK`>Ic{pGI+
zrhn~pe}jAKFRvgN&UJ77<wXSZX8Oys2!`u*zCIW6e*GJQk-F_Kn-GlDZGV}MV5DyQ
z%U2ML)NOw`4#D&fI@dk-mo*56bKP5ic?rS1nf~$z1jF_6d@1|OZxD>sZGWjC7^&O-
zaxH?9y6rEoAsDIK{_+}v>0j$U1@=6@yoz8r*S+<Z-3aE*^p}?r4A;A-{_;G6k-F_K
z|BYazZu`qm5scJrf4L38NZt0A76j8j=sunI++WT_FqNX0gQfVm^z$wqEA)A|38r@<
znB^DI{6c&s%gedX(-L6Q<Xm^x&qFX$4~>2!f|0t<MU+1X!ARZbBJ>s)jPUol2z>#9
zk-E=C=o=7B{|#?NtM<@eP}vCxrgD~-U;lY@YR<dQ-9ZFX?JvZ0xz~Lj;rb~EM(QD|
zlAnXq5RBASe?j?X1S56TU!X?_M(REnp1+`XBN(Zx{sR3$1moUM_fA&dPw<~cAQiU=
z!pqGoA&%SVSXt#*tV1wgz8!&7=M~~BdG`y>b!O-)ZoTGS?)n6Q7(Kl58?;^&*DXab
z=DJ2%&%-Vl?b9IjFC!SE7o`4P1Y`7isecr~7`;yFze7M;FJoO@yU$-E7_FC-ejkF+
zdZ_ee2tezNN*_l6T5nML_Yi>A3rg=s09vnC`hy5S>vc+BhX9mbM*k7_KLY_My`=RN
z0VqAxdM^S{ItGTU|4{^>bPNosZ$tn}N8gqDsR%&n=&Mq{2>~b_Z>`i1MF3LA?JNCw
z1R!<XzS2L20Hhuo{S^ctbw4kNd|yNWQup(M(4R#BQup(M(0`5qr0(Yhp?@6#oQr#Q
zJ-VsxTduetzo+5GCkG?`d~f@>qjCK)H*fXVbzSdT7X(khq=e%(977!Y2lM?})1-R8
zpL6?E_gXk<n%~z|2J`c&m^WGg`^Emr@5iFN!0Yy7DGK0K-Jd1y?l6ymb}gA7`O}~>
zGe2H|R$_bT*W-TQb$HIZ`5doOb-u=Re&40_Q0ji)rS(Rs`+b+z8>H^{U0N?l-S4}!
zUN3dG@2Y6MPU?Q&rSx*`^9c9n_FKAqN$GxnrOJm&_xmfQW8UJ=Bh>HrS4zjcC3L^P
zQaa`>q5J)n(lKud-R-Y*`!R0`-S4kt`7-*q(A~aDl`m=C@1tb-Q0smlC3QD%iTeFM
zO6us4Quq5PsUtI~`+bzu(Y2-S_ED<+7$Q>l`zTQ!x36@!f0E^K`%3rwB~d;!y5BDe
zU9D$uFMhuybT=Ml``mu1i=OvXW<kWutxr(2wm!j$+c!NiDW6Z|b#A0r*D<)x?Vq;c
zy3o}F(ajjuc^taiKk@Syes1KRJNW$)KX;giLU_sj2u@4Y{SdCV`z7e1)a`x=dZX0s
zehGSm)a`x=dO_-TzXZKr=?KEKzfS6YzeMw^+wTQIx%PYj_viLWx_n9LeqW@@hf4SR
zBBf(q5YIjQzDVhq7liKjMM}rKAauVkQaa`Zp}T#NZa?M)q5FN2EMG=H5xUzCsq!VQ
z`~8nBA8Ot2f28i_1yR4>|47}<3qtq%AF1O#lDgmjNZri~qP*MxsP?;gLFj(}Bg*6U
zmG1UEvOI2I>3*Lh%7;ex`y8SBc|rL5eU8xmydZS9&*@t0N?{z*{?$Eic3rh;iW}9K
zThLG4e&-30C7jFa{JbEpbNe3N&$!QdKQHh+je7k4M?7y+`y77Wc9L_=_meo3s`D83
zPkx`H^-$`5f1~x<IsxVV{zmJybpmw1ztMVaodDhMZ?s-pCqVc68?D#Y3DEuiM(O3+
zJPqCNZ<JnAy5HX@Jyg2i-zZ(I6Hve3-zZ(I6QKM3jnc(B0lMGcC|#@*p!@xe(#1Lf
zy5HYOy^Maw{R6t+-$=crb-%xndZ=~3zmd9|4@CWbe<O9dPJqAP-$>of2co>+-$>of
z2SWGz8>zebK<IvdBXr!p(*6EM=(v5Q`~8j3L!<lsjnMskApHIQM(Aptfctm*o36ow
zP%FmyJb!roIsw<YeNJ_qAg=TC0Y4wYb#A{?T_+$*KOgY?1KsU=`0o#Hp1BPHRG$OU
z-z((&h!&OP{Mv#*j2=q;Oax+dwLaL0K#Z=|2d5wqqpS77Is{>KwLX}E0F18I2N?p;
zdRfi?mm(0Ymz4e(0?>M>^zR@5t?Tu{1qeXvdVTN%1fX@jK3IhSw650&&maJ;>-E7S
z2tes&^mpzb=nr2(07@@u{e1{P>7mvK5P;I%d?4!oBLYymSsy%&0F>_L15th(0#Le}
z4}|_11fX;`9|--O2tew%eWkY}0IB2lmEMm4q#hdmX#^m3KOYGH2N8hO?fPIH0_a-n
zo(kyCeZ-*F2k$@-Z)AN?L?C-xA1p&4^6znvBY^62&^NF?xCepA=lE!5DCggc5s1;%
z`rsi1Vsy1WxCMb2U9AshAqb<Z^}*=~!02jy@L2?)^|G4(k47L`FDd;z1fca$>GvQ2
zt?Tu{#Rx#_dVTN^0?@i%AKZ!nw650&M<4*L>-E9kBLJnB(a*%^*Ow50(o0%zM*vC>
zwcdvSly24sI}m`<&H7*~0#LeHACwV*(#`rHKmbZN>w`K3Aa&fny8lTCK<c=CrB6iw
zQV)$j9RWz)t`81D08+Q>gX0iD*I@qrmc6YHu0jxRWPR`=0@>U8U;=^2^}(YE;LWTL
zHX;x?zafrL&cCN15TmR0!8!zDbhSR1fk2F|)(07aFuGbFT#5jUuGR;?L;zYZtNH(K
z1funl($7Z#S`U?e9|F+2ULPz&09x1UgU1no*7f?}UId_Zy*^li0JN^x2R}mqN-v|o
zi_fpmBLJnBv>qb>rH5MYK>$iO>w}*n0HvGt!EFdY>1KV<f&i3m)(2-I0HvGt!JP;|
z>bQM%|0g2=spIyQ{z(KN_0Z@CA^@q|^}#FzAa%PwI1K@Gt#!5TeSL5nf_NkAgCh~h
z-qr_aArQGf*n|My%=%zH0+I6@njOl|mpc%M(bf9kcm!f}wLbV50x`N;AN&PD7+tLo
z{)_;OuGR;?MF3hatNH(N1funl((ge4S`U@pg8;Oy*9SjE09x1UgWC~+*7f?}C<LH&
zy*^lo0JN^x2j4~jN-v|oi}k@d2tes2t>1+Jlpbom69FjQtPj420F-Xl2i*uj>1KVf
z4FM?KtPgHN07^IOgF_I2)N%Xj{*OZdQpfEp{VD_?_0Z^lLI6^?>x1VIfYj~!;1>v>
zYj7rN-TU){ZzG5|vOYKmf$VL4a2EoptoC-nCS-jc0;sMJh?n1A!IdTXcZ_=wh|z1`
zo8addsP|$7W3FqI^^74Hqc=!>J%TZMLFyp_F?zk!Pe2exuao*9g3x+d{k>)ig3)?O
z>C+H|)<dN?BLJ;qUJ&_22tezY7lhu80JM&ILFn5MfYvcD2>m7mpmod(LO%onD7}n+
zFZA~z0Hv3-K7as}9%_9j0#Le}7exI}ApoVjc|qt8AONMic|quF5rER&ydd;_5P;I%
zydd-g5rEWj`%0gM0HluFSNiD)K<c5<KZgLM?&k&Je=Gu!x}O(>z6b$G9k;Li??(Vq
z$L%ZqY6S4QzbBxQmvQ5jCR~iyQampTaok2no~JfV3W669!150vG`yIX-_rnHs{Z{F
z*FS?mj2=q;5d>m%^*yRP5Qx#$_o&{FK#Z=wM|CX%F}nI5)oTdE=<0h^uOb+&mur8Y
z#r^F@AX+aeeHQ}IdZ_fB2tezY55)Ieb|3()V?Gf2KOz9FV?Gf2AOg@j<^!QmMF3jI
zd?57c2tes&^e3SoiU5>e()#-mfYL*)UyA^g?&bqg|EmZ<>25v{`d<-%(%pO@^uHhg
zrMvk+=r17vrMvk+=)Xq*QpfEp{Rsphb=<zvM-hP3L!<X00IB==K=?m}0Hp5c1ED{F
z0Hp5c1EJr50Hp5c1EKGW0BYZ(%Ez@E=S{fr{<>q(TFeKaoo|1=`_@$L_agoEv;DdI
z9f@mqf8p5t9F1^KI_J;yr@{RE&mjK$O(Cc&P`^9gaT5N)%gsmboApa^bnTno>R8lQ
zmwyqe=AR4vdzJqB*k4!mpOob1sK@&s?oWgHZ_STW!MopYbr(}lxZkn3JFfKQ`tA9_
zb1p|u=aG2MwT)jVU*5GWJn^iPk3Dt48O*ugM7iHXx!+8=-%GjQRJq?%x!+v5-&?ug
zV!2miehBKW`cTkt^?r5k*FCPi`P1QC9H495!969)Tbz>{=zGTb+28)R15zRQqyMdw
zy=s#G#gk^w-p`#+%I{lCU|k~m^+A7qA!wwGSiQ-07F@sHwDSRco;ZHMT)&F0@6CT+
z;V$y88~x973c*fu{WhOtAsCi#2ui$$_tVusX83vJJ7M_s{=5)0xPBpCCy{T9;mhRP
zVfaz<?KS+XKC(hEWcUw|?}*`dyN-bN?=buv@`a>c{p1@Oehc}Q3|~*aiw*yM@+}+w
zdH-{^La@Q`N0IMV!}s~~La@v5KlJZkA!zpRL+utWBj0wzf17+e4ga+NIwty$;g2NW
zVZ*N`-%-OKLB8XLznFX*^RInY8~P>kZ8iLV`uC|2EHL~r<lATX9W-9n8~$D7yV>vy
z{dpnSZul>f?@q)2k8g1yXz}k)wfVv4$+yGszvOXe_=CxJ$nY1E?}*_?$al=}=acV*
z;fKk$!5?eweB8eug`i~kL&<ls;XgvYWy4SPKVL(?HT=oco~?$z+Mi?G8U6><p1{99
zwRY}L?FkJ(M)O9e;U|;tfZ>lL-(kZKlJBVDAExm;ZuslScbDPsr+K5<A8YOZvwuGd
zLA&AKN4|ZA{{;E2H~d`k-E8<P{5krq;lE41I}QIQ8o!M`r&>Ep<lAca7ij!;7`~N!
z%ZBeI-wlTU4*8B5{$(1!6NbNwd>j0+*3M^r?ihE5Ka6}k48N3odkudN`3@Pr$DbF1
z5yRg}zGH^}6^-8s!-wSC;NQ1e`!6Nm7Q-Jxz8!`?pL}}_e=E-$hJT#r4a3hQ-!a2K
z=5sFu6NW#Cd>itgr&e#^4DxL;{4M0$VR-!H8?QppYxwo#J7oBOrExl9_yfpy%<yNE
z?}Xv+Am0YF&Uw|}C;E@!-%IW3F#MC;9=Rw)-ESk`F>`%^_!eGx`gUO5OTLQ@znjOA
z;ZyS6VEC(O-q>pRpV0W-VfX>^^*^ehwz$Lh$v4b@Hd$4EN8_ku_=J2H8~z&dEgL=}
z-wlSpjC{8m{u|`G!|=bQapeD}1JzarK^yso^t&&Xo}+P8GW-$byV&rH$hU0xuaoZv
z!{_VcLa^2F8_9Qv;djtD3TR)%?QACB(D462z9qwdlg962!(TwYWy61-d^Z^WQ5r{E
z4Sz8CP8j|o@@=GjCAYtcd|M6wA@c1s{Eg&0VEFAcUWN_-4)Pr}{KGU(#|^(9`R+3O
zN#xs1&)c~DpCsRQ!~eU#pb&H#{uAUoVEBLLb%o(4lkceEPbc4T!+(~1cNzXqG>)3z
z#x2i}F}0`N@E@V}bQ*p$jo$&o|AofUu;K3`-%-QAK;vlK@b4ktU54)`-{ymL`+r2f
z?S@}LzMY1@i+l$R|6eqYh7Erd`HmX?a`GKFd<*%i2Lotw5Bavp2L|B3Ouik4f11Wo
zui<Bt?~vi2qH#20_(RBd%<$)s?}XvMM7|Ag*Ev5!<EX{(Um)KO!#_sjsMqk*$#=-`
z3(0rH@Egc?%<yNC?}XvklW)Te-TpBeM=gdwfP6a)e;)bv8h#r24jKLf<U3;c>&SP^
z@Y`toP8j|`@@;sBZvRhcoVFOgo_sqDKbL%a4PPeTA;bTRx5IkX@Yj&<nBjj&<8;FC
zyJ@^M=3kSl-o%MKPa1w5`F0xqw=|9h41XlGXV~yv)SgkpyYE%Ib>q0<pQmxO%kX!T
zZ}YpVP50nA8b|Ghe>cyQhVLcc0mI)*zQcxJLcXJh-$=gWhW|B<qg{qSjC`99(d}PG
zzU_uTlzcl4e*yUp82&c$9X9;0XdI0ieir$T8-AR|(JsR`k#Dp6@vL}#kbK(>e=GTR
z8vaQdM+1hxnS6&0|1gcCQNvFm-*LmALB6{T|2gsvL(zD^)5y2O@Sh;xUc*;t{0<p@
zGWm`eegXN886H1-#tZv0!<Y8S`G&*XvGy9^dD8Ir)A;Q${66H{Yxp10I2|(l%QRj_
z3?K14X?XW{2j70fKj52;=fLl-wcVl1$+yMu_mFRg;a{Nf(rfrRJWm>aE%}ZZ{%IOV
zV}=i@JrjoSr1mr%uG{|=YEO&dpRIS-6@m`Ke~o;54gVC4qank;o%1*RBJv$G{I|$=
z!tfW8Z^KO8{x6VktKol6<EYc{&Ez{^_-^tYHvHSjchvA_k?*+SKSjQ~4F6~$&$D@!
zZvQ*Ux83lM&^YQe{50|%F#O5nJ8bwH$#>N7zo^UGGj90&xe}hw8~!IWew+VJxBss+
zj@k`>68Ux-{xjq|VE7Ywo;3V5<U4Bk`=(I)4ZnL*&hIk(spQ*ygl_*UG+x>b-$uTj
zhF?Lx1BU-T`3@W2|4|U*Xw>lclJB_TchY#-W%w5IZEn%+zl?lKhW~-T49~9&zl?l`
z4FAoBJhu_UKQ}q&#|+;}z7vLDL%t11dQko6S2T`V41X}Sr^E2`sXe`hzn$7MWcVF4
zjz$dsMe-dp{5XxH3Bxy%Z^Kd5rh9M>`L-DTtK{2Z__N8k*YG#*>#D=w`waik)SMqN
z{B+LW@E<1M3B&JCz76m3&944)+P-=HEr!qkx09IX4L?TXx7YA*CEp>#KS<+u#PE~I
zcg*nbrTd*Q{B`8paCEil9{h~PZ;RotCEo>x|It4A{SFxZMH)xLhM&vxq~UMidD8Ih
z)AIU*V{|(&C*RQUcav|)@GsCfT5R~^$+v9yKkk?NZZQ08^4)6qCFHxq@OP1KFk83(
zC4X87Lc@QHd`pIZhQ`Zc!yih%WyAN7?*_wfCf}`w?<U_JhR^?Qhd1q5-TtR&yo827
zf_zJcUrD};4gcu=PACLr!ymx;8~zl^VXNUkP3_rX_{V4*1+BXMw~%jW_(y0Ql?*?X
z^Ednl$+v9y{QD62UWDOKC*SRcA0pqKhTlr#w=vS~pF+N^hCh?;cY)yx<lATX6UcYH
z;jbj$&4#bg_}y;!eaUyH;eSlyw=vf3e}%?TtKnnvU10bD^6fMHKhgMIZ}^Xr?`Ff_
zOTOC;|GzYjb{ak+-^N6@|7!AWHT<#UyTI_v$hXh%UnAf3hJTL6(PqPE<h$MQ`QJzJ
z{T##3BHzYTxBo)&Z8iKx@?Bu~-}~Z)pwIAMrE$96@b2-^f%v8pzXk{#?s*@oXZZV5
z?rndI|37)<7tYKNft!xr68KKx8Q+b8I!JeMtiwP2xW{!v_g_2d4tuxRt9u4k2g|$q
z7UAn)s~lJrbT3=As2^~3cQ201l10nXMgD)Ly$G*mmvr}BwyGzXy|QQ7?4I65OICI*
z?+I3;f{Xf=Eb3diVkwB(-NEctt5>e>x(LTBm%HN`C!QEBnlmRq78zs=QU(cwm_fv#
zol7&w7^Dmm1~G$(K^v8BV^Cy}F-RFC3}OZmgCbYMpvWL&kTOUZ#0(+^8CS!g$RJ~o
zGDsN23?c?8SHqylAY+g+NEpNnA_fUp!=T6@V~{dP7{m-B1~FH|pvWL&kTOUZ#0;V;
z;A$cQMFtszltIEEW)LxGYvtk$G6pGwgh9+8Vi32sQ>Sg?PD>!0Lm*|4Fo+pM4BELg
zgN#ASAYl+Qh#0g{={5#M1{s5tLBb$r5HTonH4KUjG6pGwgh9+8Vvun)42ldg1}TGt
zLChdxka9H)iVQLaDT9PT%phWra5W5y3^E2OgM>lMAYu@6H4KUjG6pGwgh9+8ssgSi
zB2Z+IF-RFC3}OZmgSJ*K&LCruGDsLi42qbJS6tk+y35VF(d?*5JvZZ?OCXy=AZ3s+
zh#5o-+PO4?j6upEVGuKj7_?F8HU>oo8H1ET!XRc4F(`6142ldg1}TGtLChdxka0B(
ziVQLaDT9PT%phWray1N!3^E2OgM>lMAYzbkH4KUjG6pGwgh9+8Vi0pR42ldg1}TGt
zLChek0<I<^P-KuXNEsvyVg?a|wpK3AAY+g+NEpNnA^^9P@T-ixx3;yX)O{1~z67#4
z1X2bGgP1|Ypq;L5V^Cy}F-RFC3}OZmgEp>)L6JemAZ3s+h#5o-id+qYB7=-U${=A7
zGl&>uTn&RFgN#ASAYl+Qh!~_?4TB<sj6upEVGuKj7$jT`gCc{BLCPRu5HpAv#9R%7
zB7=-U${=A7Gl;5ytBD8{8DtDn1_^_hLByb~m5VdT7^Dmm1~G$(LG1c$>mq-^f;ZwW
zOdw+>Wsoq48AJ@)sZbk(B7=-U${=A7Gl&?paWxEz3^E2OgM>lMAYxGDY8Vt5WDHUU
z34@qH#318p7!(;~3{nOOgP1|YAmwTp6d7a;QU(cwm_fuK;c6HZ8DtDn1_^_hLBt^D
zY8Vt5WDHUU34@qHR0Uj3M4-qZV~{dP7{m-B25qfeoI%DQWsoq48AJg8-`9sxL2Y+i
zt8K#tIc_|l#yRA-?SgXW?mxc`7ko)z32Qs%oONFV+go|wZ*v{~@fDxo_(>3ZDnCls
z@V=aj*zz}kaE}&Bd;uN%`2OkKJsxmv=kkrjyQA~B8Fm))3wZxem*;zUKEcsFrrA^Z
ztEoIcC*UIPTKRei&(9oZ9`^+6sl0nmAz$2XuIG4&4!h?I@-<537f2GA@1N<p0DH=>
qO!<X$q07%*$K|;l7lE_hu1G_h`!@)BXXQuN#!ulNF5jHf!T$l;Zey+h

literal 0
HcmV?d00001

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff11b..ad51b6bbbb7c 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,21 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
-
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b41fa971cb7e..a98cc8f01ae1 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1138,6 +1138,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1959,6 +1960,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e961..0cf2b30bb03b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@ struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 94436af55ce8..bc817bdb4fd3 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -16,24 +16,16 @@
 #include <rte_eth_tap.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +33,7 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
+	uint16_t flowid;
 	struct nlmsg msg;
 };
 
@@ -72,6 +63,7 @@ struct action_data {
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint16_t classid;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -112,13 +104,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -865,6 +856,9 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+		tap_nlattr_add(&msg->nh, TCA_BPF_CLASSID,
+			       sizeof(adata->bpf.classid),
+			       &adata->bpf.classid);
 	} else {
 		return -1;
 	}
@@ -1101,8 +1095,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1129,6 +1122,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1137,13 +1131,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_action_not_supported;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1239,26 +1234,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map, &flow->flowid,
+				     sizeof(flow->flowid), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1725,14 +1711,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1747,226 +1737,62 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
+	return 0;
 }
 
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
 
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
+/* Choose next flow id to use for BPF action */
+static int tap_rss_flow_assign(struct pmd_internals *pmd, uint16_t *flow_id)
+{
+	struct rte_flow *flow;
+	uint16_t id;
 
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
+	id = pmd->bpf_flowid;
 
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
+next_id:
+	/* Skip 0xffff and 0 as id's */
+	if (++id == UINT16_MAX)
+		id = 1;
 
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
+	/* Wrapped around, all id's have been used */
+	if (id == pmd->bpf_flowid)
+		return -1;
 
-	default:
-		break;
+	/* Make sure this id has not been used already */
+	for (flow = LIST_FIRST(&pmd->flows); flow; flow = LIST_NEXT(flow, next)) {
+		if (flow->flowid == id)
+			goto next_id;
 	}
 
-	return err;
+	/* Record starting point for next time */
+	pmd->bpf_flowid = id;
+	*flow_id = id;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2050,34 +1876,34 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
+
+	/* Choose new flow id, which is used as index into the BPF map */
+	err = tap_rss_flow_assign(pmd, &flow->flowid);
 	if (err < 0) {
 		rte_flow_error_set(
 			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
+			"Failed to get BPF flowid");
 
 		return -1;
 	}
 
-	/* Update RSS map entry with queues */
-	rss_entry.nb_queues = rss->queue_num;
-	for (i = 0; i < rss->queue_num; i++)
-		rss_entry.queues[i] = rss->queue[i];
-
 	rss_entry.hash_fields = hash_type;
 	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
 			    TAP_RSS_HASH_KEY_SIZE);
 
+	/* Update RSS map entry with queues */
+	rss_entry.nb_queues = rss->queue_num;
+	for (i = 0; i < rss->queue_num; i++)
+		rss_entry.queues[i] = rss->queue[i];
 
 	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
-
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &flow->flowid, sizeof(uint16_t),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
 			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			flow->flowid, errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2086,33 +1912,16 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
 	/* Actions */
 	{
+		const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 		struct action_data adata[] = {
 			{
 				.id = "bpf",
 				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
+					.annotation = "tap_rss",
+					.classid = flow->flowid,
+					.bpf_fd = bpf_program__fd(rss_prog),
 					.bpf = {
 						.action = TC_ACT_PIPE,
 					},
@@ -2120,13 +1929,13 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			},
 		};
 
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, 1, adata, TCA_FLOWER_ACT) < 0)
 			return -1;
 	}
 
 	return 0;
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfaef..41f9833619a1 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,6 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +40,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +52,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031b0..51b7ff0d007e 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -9,6 +9,9 @@
 #define TAP_MAX_QUEUES 16
 #endif
 
+/* Size of the map from BPF classid to queue table */
+#define TAP_RSS_MAX	TAP_MAX_QUEUES
+
 /* Fixed RSS hash key size in bytes. */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6fa8..00a0f22e3108 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 6/7] net/tap: remove no longer used files
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-02-08 17:41   ` [PATCH v3 5/7] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  2024-02-08 17:41   ` [PATCH v3 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1742 -------------------------------
 2 files changed, 1938 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf19b..000000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index b59b7e9141fd..000000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1742 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,       45, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       44, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       46, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,       47, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,       49, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       48, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       50, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,       51, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v3 7/7] MAINTAINERS: add maintainer for TAP device
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-02-08 17:41   ` [PATCH v3 6/7] net/tap: remove no longer used files Stephen Hemminger
@ 2024-02-08 17:41   ` Stephen Hemminger
  6 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 17:41 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Add myself as maintainer for TAP device.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5fb3a73f840e..92d27e97aa9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1015,6 +1015,7 @@ F: doc/guides/nics/pcap_ring.rst
 F: doc/guides/nics/features/pcap.ini
 
 Tap PMD
+M: Stephen Hemminger <stephen@networkplumber.org>
 F: drivers/net/tap/
 F: doc/guides/nics/tap.rst
 F: doc/guides/nics/features/tap.ini
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v3 5/7] net/tap: use libbpf to load new BPF program
  2024-02-08 17:41   ` [PATCH v3 5/7] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-02-08 18:02     ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 18:02 UTC (permalink / raw)
  To: dev

On Thu,  8 Feb 2024 09:41:29 -0800
Stephen Hemminger <stephen@networkplumber.org> wrote:

> diff --git a/drivers/net/tap/bpf/tap_bpf_program.o b/drivers/net/tap/bpf/tap_bpf_program.o
> new file mode 100644
> index 0000000000000000000000000000000000000000..db016eaadefc63e0bbc45b3115f497a465438d33
> GIT binary patch
> literal 28080

Ignore this debris, will fix in next version

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (3 preceding siblings ...)
  2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
@ 2024-02-08 19:05 ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
                     ` (7 more replies)
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                   ` (7 subsequent siblings)
  12 siblings, 8 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.
The build process checks for the required components
and if not there will stub out to not supported.

This patch series is mostly the same as the original RFC,
most of the changes are to split it up and always build
the BPF from source.

v4 - remove accidental inclusion of tap_bpf_program.o
     split number of queues from the number of RSS queue flows
     define number of queues one place

Stephen Hemminger (7):
  net/tap: remove unused RSS hash types
  net/tap: validate and setup parameters for BPF RSS
  tap: stop "vendoring" linux bpf headers
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  MAINTAINERS: add maintainer for TAP device

 .gitignore                            |    3 -
 MAINTAINERS                           |    1 +
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   12 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |   82 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  272 ++++
 drivers/net/tap/meson.build           |   29 +-
 drivers/net/tap/rte_eth_tap.c         |    2 +
 drivers/net/tap/rte_eth_tap.h         |    9 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  521 +++-----
 drivers/net/tap/tap_flow.h            |   16 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 20 files changed, 543 insertions(+), 3172 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v4 1/7] net/tap: remove unused RSS hash types
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_rss.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f94..8766ffc244f6 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 2/7] net/tap: validate and setup parameters for BPF RSS
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_insns.h | 16 ++++----
 drivers/net/tap/tap_flow.c      | 65 ++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h       |  5 +--
 3 files changed, 70 insertions(+), 16 deletions(-)

diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6b0..ee26cf885ed7 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -1709,13 +1709,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    1,    0,        0, 0x00000001},
 	{0x15,    1,    0,        1, 0x00000000},
 	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
+	{0x71,    1,    0,       45, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
+	{0x71,    2,    0,       44, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
+	{0x71,    2,    0,       46, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
+	{0x71,    4,    0,       47, 0x00000000},
 	{0x67,    4,    0,        0, 0x00000018},
 	{0x4f,    4,    2,        0, 0x00000000},
 	{0x4f,    4,    1,        0, 0x00000000},
@@ -1725,13 +1725,13 @@ static struct bpf_insn l3_l4_hash_insns[] = {
 	{0x57,    3,    0,        0, 0x0000000f},
 	{0x67,    3,    0,        0, 0x00000002},
 	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
+	{0x71,    1,    0,       49, 0x00000000},
 	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
+	{0x71,    2,    0,       48, 0x00000000},
 	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
+	{0x71,    2,    0,       50, 0x00000000},
 	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
+	{0x71,    3,    0,       51, 0x00000000},
 	{0x67,    3,    0,        0, 0x00000018},
 	{0x4f,    3,    2,        0, 0x00000000},
 	{0x4f,    3,    1,        0, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index ed4d42f92f9f..cd49aa51c8b0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,8 +11,10 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2053,6 +2055,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2071,11 +2088,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2087,6 +2104,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2101,8 +2153,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244f6..6009be7031b0 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 3/7] tap: stop "vendoring" linux bpf headers
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF. This is not
a supportable build method, and not how rest of DPDK works.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

Since DPDK officially supports only LTS or later kernel
there is no need for the #ifdef workarounds in the TAP flow
code. Cloning headers leads to problems and no longer needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   1 -
 drivers/net/tap/tap_flow.c         |  89 ---------------------
 5 files changed, 13 insertions(+), 219 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b809f..73c4dafe4eca 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111fe0..000000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917ed..9e05e2ddf19b 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index ee26cf885ed7..b59b7e9141fd 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,7 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
 
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index cd49aa51c8b0..94436af55ce8 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -20,95 +20,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
 
 /* RSS key management */
 enum bpf_rss_key_e {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 4/7] net/tap: rewrite the RSS BPF program
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-02-08 19:05   ` [PATCH v4 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-10  0:54     ` Ferruh Yigit
  2024-02-08 19:05   ` [PATCH v4 5/7] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (3 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  12 ++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 272 +++++++++++++++++++++++++
 9 files changed, 365 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace2e..01a47a760660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc704..000000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 000000000000..960a10da73b8
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,12 @@
+This is the BPF program used to implement the RSS across queues
+flow action. It works like the skbedit tc filter but instead of mapping
+to only one queues, it maps to multiple queues based on RSS hash.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+- requires libbpf version XX or later
+- rebuilding the BPF requires clang and bpftool
+- only Toeplitz hash with standard 40 byte key is supported
+- the number of queues per RSS action is limited to 16
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 2638a8a4ac9a..000000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	({								\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c0f..000000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4eca..000000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 000000000000..f2c03a19fd4d
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c30..000000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 000000000000..1abd18cb606e
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows
+ * which need BPF RSS.
+ *
+ * The hash is indexed by the tc_index.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u16));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_MAX_QUEUES);
+} rss_map SEC(".maps");
+
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/* Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* No L4 if packet is a fragmented */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/* parse ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP ports */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/* scale value to be into range [0, n), assumes val is large */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/* layout of qdisc skb cb (from sch_generic.h) */
+struct qdisc_skb_cb {
+	struct {
+		unsigned int	pkt_len;
+		__u16		dev_queue_mapping;
+		__u16		tc_classid;
+	};
+#define QDISC_CB_PRIV_LEN 20
+	unsigned char		data[QDISC_CB_PRIV_LEN];
+};
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u16 classid;
+	__u32 hash;
+
+	/* TC layer puts the BPF_CLASSID into the skb cb area */
+	classid = ((const struct qdisc_skb_cb *)skb->cb)->tc_classid;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &classid);
+	if (rsskey == NULL) {
+		bpf_printk("hash(): rss not configured");
+		return TC_ACT_OK;
+	}
+
+	hash = calculate_rss_hash(skb, rsskey);
+	bpf_printk("hash %u\n", hash);
+	if (hash) {
+		/* Fold hash to the number of queues configured */
+		skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+		bpf_printk("queue %u\n", skb->queue_mapping);
+		return TC_ACT_PIPE;
+	}
+	return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 5/7] net/tap: use libbpf to load new BPF program
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-02-08 19:05   ` [PATCH v4 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-08 20:39     ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 6/7] net/tap: remove no longer used files Stephen Hemminger
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It alsow fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |   1 +
 drivers/net/tap/bpf/tap_rss.c   |   2 +-
 drivers/net/tap/meson.build     |  29 +--
 drivers/net/tap/rte_eth_tap.c   |   2 +
 drivers/net/tap/rte_eth_tap.h   |   9 +-
 drivers/net/tap/tap_flow.c      | 381 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  16 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 123 insertions(+), 331 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd4d..dd6831797cc4 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -42,6 +42,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 1abd18cb606e..f80617fbd829 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -24,7 +24,7 @@ struct {
 	__uint(type, BPF_MAP_TYPE_HASH);
 	__uint(key_size, sizeof(__u16));
 	__uint(value_size, sizeof(struct rss_key));
-	__uint(max_entries, TAP_MAX_QUEUES);
+	__uint(max_entries, TAP_RSS_MAX);
 } rss_map SEC(".maps");
 
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff11b..46ffd35beb5a 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,22 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
-deps = ['bus_vdev', 'gso', 'hash']
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
 
-cflags += '-DTAP_MAX_QUEUES=16'
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+deps = ['bus_vdev', 'gso', 'hash']
 
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b41fa971cb7e..a98cc8f01ae1 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1138,6 +1138,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1959,6 +1960,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e961..0cf2b30bb03b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@ struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 94436af55ce8..bc817bdb4fd3 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -16,24 +16,16 @@
 #include <rte_eth_tap.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +33,7 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
+	uint16_t flowid;
 	struct nlmsg msg;
 };
 
@@ -72,6 +63,7 @@ struct action_data {
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint16_t classid;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -112,13 +104,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -865,6 +856,9 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+		tap_nlattr_add(&msg->nh, TCA_BPF_CLASSID,
+			       sizeof(adata->bpf.classid),
+			       &adata->bpf.classid);
 	} else {
 		return -1;
 	}
@@ -1101,8 +1095,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1129,6 +1122,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1137,13 +1131,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_action_not_supported;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1239,26 +1234,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map, &flow->flowid,
+				     sizeof(flow->flowid), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1725,14 +1711,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1747,226 +1737,62 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
+	return 0;
 }
 
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
 
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
+/* Choose next flow id to use for BPF action */
+static int tap_rss_flow_assign(struct pmd_internals *pmd, uint16_t *flow_id)
+{
+	struct rte_flow *flow;
+	uint16_t id;
 
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
+	id = pmd->bpf_flowid;
 
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
+next_id:
+	/* Skip 0xffff and 0 as id's */
+	if (++id == UINT16_MAX)
+		id = 1;
 
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
+	/* Wrapped around, all id's have been used */
+	if (id == pmd->bpf_flowid)
+		return -1;
 
-	default:
-		break;
+	/* Make sure this id has not been used already */
+	for (flow = LIST_FIRST(&pmd->flows); flow; flow = LIST_NEXT(flow, next)) {
+		if (flow->flowid == id)
+			goto next_id;
 	}
 
-	return err;
+	/* Record starting point for next time */
+	pmd->bpf_flowid = id;
+	*flow_id = id;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2050,34 +1876,34 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
+
+	/* Choose new flow id, which is used as index into the BPF map */
+	err = tap_rss_flow_assign(pmd, &flow->flowid);
 	if (err < 0) {
 		rte_flow_error_set(
 			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
+			"Failed to get BPF flowid");
 
 		return -1;
 	}
 
-	/* Update RSS map entry with queues */
-	rss_entry.nb_queues = rss->queue_num;
-	for (i = 0; i < rss->queue_num; i++)
-		rss_entry.queues[i] = rss->queue[i];
-
 	rss_entry.hash_fields = hash_type;
 	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
 			    TAP_RSS_HASH_KEY_SIZE);
 
+	/* Update RSS map entry with queues */
+	rss_entry.nb_queues = rss->queue_num;
+	for (i = 0; i < rss->queue_num; i++)
+		rss_entry.queues[i] = rss->queue[i];
 
 	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
-
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &flow->flowid, sizeof(uint16_t),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
 			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			flow->flowid, errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2086,33 +1912,16 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
 	/* Actions */
 	{
+		const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 		struct action_data adata[] = {
 			{
 				.id = "bpf",
 				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
+					.annotation = "tap_rss",
+					.classid = flow->flowid,
+					.bpf_fd = bpf_program__fd(rss_prog),
 					.bpf = {
 						.action = TC_ACT_PIPE,
 					},
@@ -2120,13 +1929,13 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			},
 		};
 
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
+		if (add_actions(flow, 1, adata, TCA_FLOWER_ACT) < 0)
 			return -1;
 	}
 
 	return 0;
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfaef..bc54af28cab5 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +57,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031b0..65bd8991b120 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6fa8..00a0f22e3108 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 6/7] net/tap: remove no longer used files
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-02-08 19:05   ` [PATCH v4 5/7] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-08 19:05   ` [PATCH v4 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
  2024-02-12 16:47   ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1742 -------------------------------
 2 files changed, 1938 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf19b..000000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index b59b7e9141fd..000000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1742 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,       45, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       44, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       46, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,       47, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,       49, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,       48, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,       50, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,       51, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v4 7/7] MAINTAINERS: add maintainer for TAP device
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-02-08 19:05   ` [PATCH v4 6/7] net/tap: remove no longer used files Stephen Hemminger
@ 2024-02-08 19:05   ` Stephen Hemminger
  2024-02-12 16:47   ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 19:05 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Add myself as maintainer for TAP device.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5fb3a73f840e..92d27e97aa9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1015,6 +1015,7 @@ F: doc/guides/nics/pcap_ring.rst
 F: doc/guides/nics/features/pcap.ini
 
 Tap PMD
+M: Stephen Hemminger <stephen@networkplumber.org>
 F: drivers/net/tap/
 F: doc/guides/nics/tap.rst
 F: doc/guides/nics/features/tap.ini
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 5/7] net/tap: use libbpf to load new BPF program
  2024-02-08 19:05   ` [PATCH v4 5/7] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-02-08 20:39     ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-08 20:39 UTC (permalink / raw)
  To: dev

On Thu,  8 Feb 2024 11:05:53 -0800
Stephen Hemminger <stephen@networkplumber.org> wrote:

> There were multiple issues in the RSS queue support in the TAP
> driver. This required extensive rework of the BPF support.
> 
> Change the BPF loading to use bpftool to
> create a skeleton header file, and load with libbpf.
> The BPF is always compiled from source so less chance that
> source and instructions diverge. Also resolves issue where
> libbpf and source get out of sync. The program
> is only loaded once, so if multiple rules are created
> only one BPF program is loaded in kernel.
> 
> The new BPF program only needs a single action.
> No need for action and re-classification step.
> 
> It alsow fixes the missing bits from the original.
>     - supports setting RSS key per flow
>     - level of hash can be L3 or L3/L4.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

Note: this patch introduces a optional dependency on bpftool
to get the RSS to work. If bpftool is not present, then RSS
is not built, and attempts to use rte_flow_action_queue will
fail with not supported.

It looks like the CI build environment is missing bpftool,
so all the builds just skip that code. This works but CI build
environments need to change to get bpftool. Not sure how to make
that happen.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 4/7] net/tap: rewrite the RSS BPF program
  2024-02-08 19:05   ` [PATCH v4 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-02-10  0:54     ` Ferruh Yigit
  2024-02-10  2:09       ` Stephen Hemminger
  0 siblings, 1 reply; 133+ messages in thread
From: Ferruh Yigit @ 2024-02-10  0:54 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On 2/8/2024 7:05 PM, Stephen Hemminger wrote:
> Rewrite the BPF program used to do queue based RSS.
> Important changes:
> 	- uses newer BPF map format BTF
> 	- accepts key as parameter rather than constant default
> 	- can do L3 or L4 hashing
> 	- supports IPv4 options
> 	- supports IPv6 extension headers
> 	- restructured for readability
> 
> The usage of BPF is different as well:
> 	- the incoming configuration is looked up based on
> 	  class parameters rather than patching the BPF.
> 	- the resulting queue is placed in skb rather
> 	  than requiring a second pass through classifier step.
> 
> Note: This version only works with later patch to enable it on
> the DPDK driver side. It is submitted as an incremental patch
> to allow for easier review. Bisection still works because
> the old instruction are still present for now.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

<...>

> diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> new file mode 100644
> index 000000000000..f2c03a19fd4d
> --- /dev/null
> +++ b/drivers/net/tap/bpf/meson.build
> @@ -0,0 +1,81 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
> +
> +enable_tap_rss = false
> +
> +libbpf = dependency('libbpf', required: false, method: 'pkg-config')
> +if not libbpf.found()
> +    message('net/tap: no RSS support missing libbpf')
> +    subdir_done()
> +endif
> +
> +# Debian install this in /usr/sbin which is not in $PATH
> +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> +if not bpftool.found()
> +    message('net/tap: no RSS support missing bpftool')
> +    subdir_done()
> +endif
>

I am getting following build error:
'
drivers/net/tap/bpf/meson.build:13:10: ERROR: Command `/usr/sbin/bpftool
--version` failed with status 2.
'

There is a '/usr/sbin/bpftool' file but it is a script and gives
following message when run:
"WARNING: bpftool not found for kernel 6.5.0-15"

This is with "Ubuntu 22.04.3 LTS"


Overall thanks for fixing tap BPF support.


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 4/7] net/tap: rewrite the RSS BPF program
  2024-02-10  0:54     ` Ferruh Yigit
@ 2024-02-10  2:09       ` Stephen Hemminger
  2024-02-28 17:27         ` Ferruh Yigit
  0 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-10  2:09 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev, Luca Boccassi

On Sat, 10 Feb 2024 00:54:15 +0000
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> On 2/8/2024 7:05 PM, Stephen Hemminger wrote:
> > Rewrite the BPF program used to do queue based RSS.
> > Important changes:
> > 	- uses newer BPF map format BTF
> > 	- accepts key as parameter rather than constant default
> > 	- can do L3 or L4 hashing
> > 	- supports IPv4 options
> > 	- supports IPv6 extension headers
> > 	- restructured for readability
> > 
> > The usage of BPF is different as well:
> > 	- the incoming configuration is looked up based on
> > 	  class parameters rather than patching the BPF.
> > 	- the resulting queue is placed in skb rather
> > 	  than requiring a second pass through classifier step.
> > 
> > Note: This version only works with later patch to enable it on
> > the DPDK driver side. It is submitted as an incremental patch
> > to allow for easier review. Bisection still works because
> > the old instruction are still present for now.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>  
> 
> <...>
> 
> > diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> > new file mode 100644
> > index 000000000000..f2c03a19fd4d
> > --- /dev/null
> > +++ b/drivers/net/tap/bpf/meson.build
> > @@ -0,0 +1,81 @@
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
> > +
> > +enable_tap_rss = false
> > +
> > +libbpf = dependency('libbpf', required: false, method: 'pkg-config')
> > +if not libbpf.found()
> > +    message('net/tap: no RSS support missing libbpf')
> > +    subdir_done()
> > +endif
> > +
> > +# Debian install this in /usr/sbin which is not in $PATH
> > +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> > +if not bpftool.found()
> > +    message('net/tap: no RSS support missing bpftool')
> > +    subdir_done()
> > +endif
> >  
> 
> I am getting following build error:
> '
> drivers/net/tap/bpf/meson.build:13:10: ERROR: Command `/usr/sbin/bpftool
> --version` failed with status 2.
> '
> 
> There is a '/usr/sbin/bpftool' file but it is a script and gives
> following message when run:
> "WARNING: bpftool not found for kernel 6.5.0-15"
> 
> This is with "Ubuntu 22.04.3 LTS"
> 
> 
> Overall thanks for fixing tap BPF support.

Just set up an equivalent Ubuntu VM 22.04 VM and made sure all packages
were up to date.

Looks like Ubuntu borked the packaging of bpftool.
Maybe Luca has some insight.

shemminger@ubuntu-22-04:~/dpdk$ sudo apt install libbpf-dev bpftool
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package bpftool is a virtual package provided by:
  linux-nvidia-6.2-tools-common 6.2.0-1003.3~22.04.1
  linux-lowlatency-hwe-6.5-tools-common 6.5.0-17.17.1.1.1~22.04.1
  linux-hwe-6.5-tools-common 6.5.0-17.17~22.04.1
  linux-hwe-6.2-tools-common 6.2.0-39.40~22.04.1
You should explicitly select one to install.



^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-02-08 19:05   ` [PATCH v4 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
@ 2024-02-12 16:47   ` Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-12 16:47 UTC (permalink / raw)
  To: dev

On Thu,  8 Feb 2024 11:05:48 -0800
Stephen Hemminger <stephen@networkplumber.org> wrote:

> The support of doing RSS for rte_flow_action was a cool idea
> but it has been broken for several releases of DPDK as the
> kernel and BPF infrastructure changed.
> 
> This series cleans up the BPF program, implements several
> features that were never completed in the original code
> and changes to use the current BPF toolchain.
> 
> The result should be easier to read and maintain.
> The build process checks for the required components
> and if not there will stub out to not supported.
> 
> This patch series is mostly the same as the original RFC,
> most of the changes are to split it up and always build
> the BPF from source.
> 
> v4 - remove accidental inclusion of tap_bpf_program.o
>      split number of queues from the number of RSS queue flows
>      define number of queues one place

Please hold this until after 24.03 release.
Would like to get some tests and documentation in place.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 4/7] net/tap: rewrite the RSS BPF program
  2024-02-10  2:09       ` Stephen Hemminger
@ 2024-02-28 17:27         ` Ferruh Yigit
  2024-02-29 23:39           ` Stephen Hemminger
  0 siblings, 1 reply; 133+ messages in thread
From: Ferruh Yigit @ 2024-02-28 17:27 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, Luca Boccassi

On 2/10/2024 2:09 AM, Stephen Hemminger wrote:
> On Sat, 10 Feb 2024 00:54:15 +0000
> Ferruh Yigit <ferruh.yigit@amd.com> wrote:
> 
>> On 2/8/2024 7:05 PM, Stephen Hemminger wrote:
>>> Rewrite the BPF program used to do queue based RSS.
>>> Important changes:
>>> 	- uses newer BPF map format BTF
>>> 	- accepts key as parameter rather than constant default
>>> 	- can do L3 or L4 hashing
>>> 	- supports IPv4 options
>>> 	- supports IPv6 extension headers
>>> 	- restructured for readability
>>>
>>> The usage of BPF is different as well:
>>> 	- the incoming configuration is looked up based on
>>> 	  class parameters rather than patching the BPF.
>>> 	- the resulting queue is placed in skb rather
>>> 	  than requiring a second pass through classifier step.
>>>
>>> Note: This version only works with later patch to enable it on
>>> the DPDK driver side. It is submitted as an incremental patch
>>> to allow for easier review. Bisection still works because
>>> the old instruction are still present for now.
>>>
>>> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>  
>>
>> <...>
>>
>>> diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
>>> new file mode 100644
>>> index 000000000000..f2c03a19fd4d
>>> --- /dev/null
>>> +++ b/drivers/net/tap/bpf/meson.build
>>> @@ -0,0 +1,81 @@
>>> +# SPDX-License-Identifier: BSD-3-Clause
>>> +# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
>>> +
>>> +enable_tap_rss = false
>>> +
>>> +libbpf = dependency('libbpf', required: false, method: 'pkg-config')
>>> +if not libbpf.found()
>>> +    message('net/tap: no RSS support missing libbpf')
>>> +    subdir_done()
>>> +endif
>>> +
>>> +# Debian install this in /usr/sbin which is not in $PATH
>>> +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
>>> +if not bpftool.found()
>>> +    message('net/tap: no RSS support missing bpftool')
>>> +    subdir_done()
>>> +endif
>>>  
>>
>> I am getting following build error:
>> '
>> drivers/net/tap/bpf/meson.build:13:10: ERROR: Command `/usr/sbin/bpftool
>> --version` failed with status 2.
>> '
>>
>> There is a '/usr/sbin/bpftool' file but it is a script and gives
>> following message when run:
>> "WARNING: bpftool not found for kernel 6.5.0-15"
>>
>> This is with "Ubuntu 22.04.3 LTS"
>>
>>
>> Overall thanks for fixing tap BPF support.
> 
> Just set up an equivalent Ubuntu VM 22.04 VM and made sure all packages
> were up to date.
> 
> Looks like Ubuntu borked the packaging of bpftool.
> Maybe Luca has some insight.
> 
> shemminger@ubuntu-22-04:~/dpdk$ sudo apt install libbpf-dev bpftool
> Reading package lists... Done
> Building dependency tree... Done
> Reading state information... Done
> Package bpftool is a virtual package provided by:
>   linux-nvidia-6.2-tools-common 6.2.0-1003.3~22.04.1
>   linux-lowlatency-hwe-6.5-tools-common 6.5.0-17.17.1.1.1~22.04.1
>   linux-hwe-6.5-tools-common 6.5.0-17.17~22.04.1
>   linux-hwe-6.2-tools-common 6.2.0-39.40~22.04.1
> You should explicitly select one to install.
> 

I can make it work but it can hit others too, we need something that
detects this condition and disables tap/bpf.


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v4 4/7] net/tap: rewrite the RSS BPF program
  2024-02-28 17:27         ` Ferruh Yigit
@ 2024-02-29 23:39           ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-02-29 23:39 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev, Luca Boccassi

On Wed, 28 Feb 2024 17:27:31 +0000
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> > 
> > shemminger@ubuntu-22-04:~/dpdk$ sudo apt install libbpf-dev bpftool
> > Reading package lists... Done
> > Building dependency tree... Done
> > Reading state information... Done
> > Package bpftool is a virtual package provided by:
> >   linux-nvidia-6.2-tools-common 6.2.0-1003.3~22.04.1
> >   linux-lowlatency-hwe-6.5-tools-common 6.5.0-17.17.1.1.1~22.04.1
> >   linux-hwe-6.5-tools-common 6.5.0-17.17~22.04.1
> >   linux-hwe-6.2-tools-common 6.2.0-39.40~22.04.1
> > You should explicitly select one to install.
> >   
> 
> I can make it work but it can hit others too, we need something that
> detects this condition and disables tap/bpf.

The meson rule checks for bpftool and when it doesn't find a working
version it skips building the BPF RSS stuff.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v5 0/8] net/tap: cleanups and fix BPF flow
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (4 preceding siblings ...)
  2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
@ 2024-04-02 17:12 ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 1/8] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (7 more replies)
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                   ` (6 subsequent siblings)
  12 siblings, 8 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.
The build process checks for the required componen

Stephen Hemminger (8):
  net/tap: do not duplicate fd's
  doc: fix the requirements and building of TAP flow
  net/tap: remove unused RSS hash types
  net/tap: validate and setup parameters for BPF RSS
  net/tap: stop "vendoring" linux bpf headers
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files

 .gitignore                            |    3 -
 doc/guides/linux_gsg/sys_reqs.rst     |    3 +
 doc/guides/nics/tap.rst               |   95 +-
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   38 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |   91 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  264 ++++
 drivers/net/tap/meson.build           |   29 +-
 drivers/net/tap/rte_eth_tap.c         |  199 ++-
 drivers/net/tap/rte_eth_tap.h         |   12 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  549 ++------
 drivers/net/tap/tap_flow.h            |   16 +-
 drivers/net/tap/tap_intr.c            |    7 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 22 files changed, 680 insertions(+), 3394 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v5 1/8] net/tap: do not duplicate fd's
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptopr for both rx and tx queues.
This allows up to 8 queues (versus 4).

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/meson.build   |   2 +-
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 5 files changed, 92 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..9cd124d53e 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -16,7 +16,7 @@ sources = files(
 
 deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
+cflags += '-DTAP_MAX_QUEUES=8'
 
 # input array for meson symbol search:
 # [ "MACRO to define if found", "header for the search",
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 2/8] doc: fix the requirements and building of TAP flow
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 1/8] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 3/8] net/tap: remove unused RSS hash types Stephen Hemminger
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The build process for TAP eBPF RSS is now changed, so documentation
needs to be updated.

Since kernel 4.19 is the oldest current LTS supported kernel,
the TAP documentation can be simplified. Any complaints about
flow not working means the kernel is out of scope of current DPDK.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/linux_gsg/sys_reqs.rst |  3 +
 doc/guides/nics/tap.rst           | 95 ++++++++-----------------------
 2 files changed, 28 insertions(+), 70 deletions(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 13be715933..0254568517 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -101,6 +101,9 @@ Running DPDK Applications
 
 To run a DPDK application, some customization may be required on the target machine.
 
+.. _linux_gsg_kernel_version:
+
+
 System Software
 ~~~~~~~~~~~~~~~
 
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..dcfefba567 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -103,13 +103,8 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+The tap PMD supports major flow API pattern items and actions, when running on a supported Linux version. See :ref:`linux_gsg_kernel_version`.
 
 Supported items:
 
@@ -123,7 +118,7 @@ Supported actions:
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS (requires clang, libbpf, and bpftool)
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -229,80 +224,40 @@ load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
 
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
 
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
+The RSS algorithm is written in file ``tap_rss.c`` which is compiled with
+clang and then turned into a skeleton header file with bpftool.
+The skeleton header file is then compiled into the tap driver.
 
 TAP reports on supported RSS functions as part of dev_infos_get callback:
 ``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
+
+**Known limitation:** TAP supports only these functions, it is not possible
+to be more fine grained. For example, selecting only IPv4 and not IPV6
+to be hashed is not possible.
 
 Systems supporting flow API
 ---------------------------
 
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+- Any system which meets the current DPDK kernel requirements should
+  be able to support the flow API.
+
+- Supporting eBPF/RSS requires ``bpftool`` and ``libbpf``.
 
 Limitations
 -----------
 
 * Rx/Tx must have the same number of queues.
+
+* The kernel will distribute packets across all queues.
+  If using flow API then add a default match and action to force a different
+  behavior.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 3/8] net/tap: remove unused RSS hash types
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 1/8] net/tap: do not duplicate fd's Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_rss.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 4/8] net/tap: validate and setup parameters for BPF RSS
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-04-02 17:12   ` [PATCH v5 3/8] net/tap: remove unused RSS hash types Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..7033e8411f 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2062,6 +2064,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2080,11 +2097,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2096,6 +2113,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2110,8 +2162,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 5/8] net/tap: stop "vendoring" linux bpf headers
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-04-02 17:12   ` [PATCH v5 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF. This is not
a supportable build method, and not how rest of DPDK works.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

Since DPDK officially supports only LTS or later kernel
there is no need for the #ifdef workarounds in the TAP flow
code. Cloning headers leads to problems and no longer needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_flow.c         |  89 ---------------------
 4 files changed, 13 insertions(+), 218 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111f..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 7033e8411f..e154ea0ae0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,95 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
 
 /* RSS key management */
 enum bpf_rss_key_e {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 6/8] net/tap: rewrite the RSS BPF program
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-04-02 17:12   ` [PATCH v5 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 7/8] net/tap: use libbpf to load new " Stephen Hemminger
  2024-04-02 17:12   ` [PATCH v5 8/8] net/tap: remove no longer used files Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  38 ++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 383 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..1d421ff42c
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,38 @@
+This is the BPF program used to implement the RSS across queues flow action.
+The program is loaded when first RSS flow rule is created and is never unloaded.
+
+Each flow rule creates a unique key (handle) and this is used as the key
+for finding the RSS information for that flow rule.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+- rebuilding the BPF requires Clang and bpftool.
+  Some older versions of Ubuntu do not have working bpftool package.
+  Need a version of Clang that can compile to BPF.
+- only standard Toeplitz hash with standard 40 byte key is supported
+- the number of flow rules using RSS is limited to 32
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are not available. If everything is
+there then BPF RSS is enabled.
+
+1. Using clang to compile tap_rss.c the tap_rss.bpf.o file.
+
+2. Using bpftool generate a skeleton header file tap_rss.skel.h from tap_rss.bpf.o.
+   This skeleton header is an large byte array which contains the
+   BPF binary and wrappers to load and use it.
+
+3. The tap flow code then compiles that BPF byte array into the PMD object.
+
+4. When needed the BPF array is loaded by libbpf.
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-04-02 17:12   ` [PATCH v5 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-03 11:50     ` Luca Boccassi
  2024-04-02 17:12   ` [PATCH v5 8/8] net/tap: remove no longer used files Stephen Hemminger
  7 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It alsow fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  14 +-
 drivers/net/tap/meson.build     |  29 +--
 drivers/net/tap/rte_eth_tap.c   |   2 +
 drivers/net/tap/rte_eth_tap.h   |   9 +-
 drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
 drivers/net/tap/tap_flow.h      |  16 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 8 files changed, 127 insertions(+), 367 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..3f3c4e6602 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -3,15 +3,24 @@
 
 enable_tap_rss = false
 
+# Loading BPF requires libbpf
 libbpf = dependency('libbpf', required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu has non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 9cd124d53e..46ffd35beb 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,22 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
-deps = ['bus_vdev', 'gso', 'hash']
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
 
-cflags += '-DTAP_MAX_QUEUES=8'
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+deps = ['bus_vdev', 'gso', 'hash']
 
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..b76c5bf527 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1129,6 +1129,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1941,6 +1942,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..4e9ca6d826 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@ struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index e154ea0ae0..77dc8e9741 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,26 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -42,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -70,9 +61,11 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -113,13 +106,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -854,10 +846,11 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
@@ -1105,8 +1098,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1136,6 +1128,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1144,13 +1137,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1247,26 +1241,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1734,14 +1719,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1756,226 +1745,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
-	}
-
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2008,9 +1803,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2059,34 +1856,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2095,47 +1882,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..bc54af28ca 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +57,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..00a0f22e31 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v5 8/8] net/tap: remove no longer used files
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-04-02 17:12   ` [PATCH v5 7/8] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-02 17:12   ` Stephen Hemminger
  2024-04-02 20:43     ` Stephen Hemminger
  7 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 17:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1743 -------------------------------
 2 files changed, 1939 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index 53fa76c4e6..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1743 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-#include <tap_bpf.h>
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 8/8] net/tap: remove no longer used files
  2024-04-02 17:12   ` [PATCH v5 8/8] net/tap: remove no longer used files Stephen Hemminger
@ 2024-04-02 20:43     ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-02 20:43 UTC (permalink / raw)
  To: dev

On Tue,  2 Apr 2024 10:12:40 -0700
Stephen Hemminger <stephen@networkplumber.org> wrote:

> The BPF api was replaced by use of libbpf.
> And the BPF instruction header was replaced by the skeleton.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

The build for this fails on CI because CI is testing on CentOs7.
RHEL/CentOs 7 is no longer supported and should be dropped.
Official end of life for CentOS 7 is 30 Jun 2024 which will
be before next DPDK release.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-02 17:12   ` [PATCH v5 7/8] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-03 11:50     ` Luca Boccassi
  2024-04-03 14:53       ` Stephen Hemminger
  2024-04-03 15:55       ` Stephen Hemminger
  0 siblings, 2 replies; 133+ messages in thread
From: Luca Boccassi @ 2024-04-03 11:50 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On Tue, 2024-04-02 at 10:12 -0700, Stephen Hemminger wrote:
> There were multiple issues in the RSS queue support in the TAP
> driver. This required extensive rework of the BPF support.
> 
> Change the BPF loading to use bpftool to
> create a skeleton header file, and load with libbpf.
> The BPF is always compiled from source so less chance that
> source and instructions diverge. Also resolves issue where
> libbpf and source get out of sync. The program
> is only loaded once, so if multiple rules are created
> only one BPF program is loaded in kernel.
> 
> The new BPF program only needs a single action.
> No need for action and re-classification step.
> 
> It alsow fixes the missing bits from the original.
>     - supports setting RSS key per flow
>     - level of hash can be L3 or L3/L4.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  drivers/net/tap/bpf/meson.build |  14 +-
>  drivers/net/tap/meson.build     |  29 +--
>  drivers/net/tap/rte_eth_tap.c   |   2 +
>  drivers/net/tap/rte_eth_tap.h   |   9 +-
>  drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
>  drivers/net/tap/tap_flow.h      |  16 +-
>  drivers/net/tap/tap_rss.h       |  10 +-
>  drivers/net/tap/tap_tcmsgs.h    |   4 +-
>  8 files changed, 127 insertions(+), 367 deletions(-)
> 
> diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> index f2c03a19fd..3f3c4e6602 100644
> --- a/drivers/net/tap/bpf/meson.build
> +++ b/drivers/net/tap/bpf/meson.build
> @@ -3,15 +3,24 @@
>  
>  enable_tap_rss = false
>  
> +# Loading BPF requires libbpf
>  libbpf = dependency('libbpf', required: false, method: 'pkg-config')
>  if not libbpf.found()
>      message('net/tap: no RSS support missing libbpf')
>      subdir_done()
>  endif
>  
> +# Making skeleton needs bpftool
>  # Debian install this in /usr/sbin which is not in $PATH
> -bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> -if not bpftool.found()
> +bpftool_supports_skel = false
> +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
> +if bpftool.found()
> +    # Some Ubuntu has non-functional bpftool
> +    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
> +                                        check:false).returncode() == 0
> +endif

Using bpftool to generate the header at build time is a bit icky,
because it will look at sysfs on the build system, which is from the
running kernel. But a build system's kernel might be some ancient LTS,
and even be a completely different kconfig/build/distro from the actual
runtime one.

We have ran in the same problem in systemd recently, and the solution
is to have distros publish the vmlinux.h together with the kernel
image/headers, that way we can rely on the fact that by build-depending
on the right kernel package we get exactly the generated vmlinux.h that
we want. This has already happened in Centos, Debian, Fedora and Arch,
and I am trying to get Ubuntu onboard too.

The annoying thing is that every distro packages differently, so the
path needs to be configurable with a meson option.

Feel free to pilfer the systemd meson glue:

https://github.com/systemd/systemd/pull/26826/commits/d917079e7e320aa281fc4ad6f8073b0814b9cb13

It's of course file to go to the runtime kernel if no vmlinux.h is
specified, as a fallback, which is going to be useful for developers
machines.

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 11:50     ` Luca Boccassi
@ 2024-04-03 14:53       ` Stephen Hemminger
  2024-04-03 15:55       ` Stephen Hemminger
  1 sibling, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-03 14:53 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

On Wed, 03 Apr 2024 12:50:35 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Tue, 2024-04-02 at 10:12 -0700, Stephen Hemminger wrote:
> > There were multiple issues in the RSS queue support in the TAP
> > driver. This required extensive rework of the BPF support.
> > 
> > Change the BPF loading to use bpftool to
> > create a skeleton header file, and load with libbpf.
> > The BPF is always compiled from source so less chance that
> > source and instructions diverge. Also resolves issue where
> > libbpf and source get out of sync. The program
> > is only loaded once, so if multiple rules are created
> > only one BPF program is loaded in kernel.
> > 
> > The new BPF program only needs a single action.
> > No need for action and re-classification step.
> > 
> > It alsow fixes the missing bits from the original.
> >     - supports setting RSS key per flow
> >     - level of hash can be L3 or L3/L4.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> >  drivers/net/tap/bpf/meson.build |  14 +-
> >  drivers/net/tap/meson.build     |  29 +--
> >  drivers/net/tap/rte_eth_tap.c   |   2 +
> >  drivers/net/tap/rte_eth_tap.h   |   9 +-
> >  drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
> >  drivers/net/tap/tap_flow.h      |  16 +-
> >  drivers/net/tap/tap_rss.h       |  10 +-
> >  drivers/net/tap/tap_tcmsgs.h    |   4 +-
> >  8 files changed, 127 insertions(+), 367 deletions(-)
> > 
> > diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> > index f2c03a19fd..3f3c4e6602 100644
> > --- a/drivers/net/tap/bpf/meson.build
> > +++ b/drivers/net/tap/bpf/meson.build
> > @@ -3,15 +3,24 @@
> >  
> >  enable_tap_rss = false
> >  
> > +# Loading BPF requires libbpf
> >  libbpf = dependency('libbpf', required: false, method: 'pkg-config')
> >  if not libbpf.found()
> >      message('net/tap: no RSS support missing libbpf')
> >      subdir_done()
> >  endif
> >  
> > +# Making skeleton needs bpftool
> >  # Debian install this in /usr/sbin which is not in $PATH
> > -bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> > -if not bpftool.found()
> > +bpftool_supports_skel = false
> > +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
> > +if bpftool.found()
> > +    # Some Ubuntu has non-functional bpftool
> > +    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
> > +                                        check:false).returncode() == 0
> > +endif  
> 
> Using bpftool to generate the header at build time is a bit icky,
> because it will look at sysfs on the build system, which is from the
> running kernel. But a build system's kernel might be some ancient LTS,
> and even be a completely different kconfig/build/distro from the actual
> runtime one.

I wish there was a better way to get bpf compiled to an array to load.
The other alternative is to embed the object but then the ickiness of decoding
ELF headers ends up in the driver.

This method seems to be the BPF way now.

> 
> We have ran in the same problem in systemd recently, and the solution
> is to have distros publish the vmlinux.h together with the kernel
> image/headers, that way we can rely on the fact that by build-depending
> on the right kernel package we get exactly the generated vmlinux.h that
> we want. This has already happened in Centos, Debian, Fedora and Arch,
> and I am trying to get Ubuntu onboard too.

Not sure how much it matters for the TAP BPF bits. Unlike other kernel BPF
this program only really depends on layout of skb, and is not using system
call hooks. So vmlinux.h is not referenced directly.  But if layout of skb
changes, then things would break.


> The annoying thing is that every distro packages differently, so the
> path needs to be configurable with a meson option.
> 
> Feel free to pilfer the systemd meson glue:
> 
> https://github.com/systemd/systemd/pull/26826/commits/d917079e7e320aa281fc4ad6f8073b0814b9cb13
> 
> It's of course file to go to the runtime kernel if no vmlinux.h is
> specified, as a fallback, which is going to be useful for developers
> machines.
> 


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 11:50     ` Luca Boccassi
  2024-04-03 14:53       ` Stephen Hemminger
@ 2024-04-03 15:55       ` Stephen Hemminger
  2024-04-03 21:19         ` Luca Boccassi
  1 sibling, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-03 15:55 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

On Wed, 03 Apr 2024 12:50:35 +0100
Luca Boccassi <bluca@debian.org> wrote:

> Using bpftool to generate the header at build time is a bit icky,
> because it will look at sysfs on the build system, which is from the
> running kernel. But a build system's kernel might be some ancient LTS,
> and even be a completely different kconfig/build/distro from the actual
> runtime one.

One other option would be to ship a pre-built skeleton file.
Which is what the method the old code did.
But that creates an implied dependency on the developers machine build environment.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 15:55       ` Stephen Hemminger
@ 2024-04-03 21:19         ` Luca Boccassi
  2024-04-03 23:41           ` Stephen Hemminger
  2024-04-04 15:30           ` Stephen Hemminger
  0 siblings, 2 replies; 133+ messages in thread
From: Luca Boccassi @ 2024-04-03 21:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 03 Apr 2024 12:50:35 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > Using bpftool to generate the header at build time is a bit icky,
> > because it will look at sysfs on the build system, which is from the
> > running kernel. But a build system's kernel might be some ancient LTS,
> > and even be a completely different kconfig/build/distro from the actual
> > runtime one.
>
> One other option would be to ship a pre-built skeleton file.
> Which is what the method the old code did.
> But that creates an implied dependency on the developers machine build environment.

That's what the distro-provided vmlinux.h should help with - by
#include'ing that, it should be possible to build a co-re bpf program,
no other artifacts needed. You can try it out locally by generating it
from the local running kernel on your dev machine:

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 21:19         ` Luca Boccassi
@ 2024-04-03 23:41           ` Stephen Hemminger
  2024-04-04  0:49             ` Luca Boccassi
  2024-04-04 15:30           ` Stephen Hemminger
  1 sibling, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-03 23:41 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

On Wed, 3 Apr 2024 22:19:20 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 03 Apr 2024 12:50:35 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > Using bpftool to generate the header at build time is a bit icky,
> > > because it will look at sysfs on the build system, which is from the
> > > running kernel. But a build system's kernel might be some ancient LTS,
> > > and even be a completely different kconfig/build/distro from the actual
> > > runtime one.  
> >
> > One other option would be to ship a pre-built skeleton file.
> > Which is what the method the old code did.
> > But that creates an implied dependency on the developers machine build environment.  
> 
> That's what the distro-provided vmlinux.h should help with - by
> #include'ing that, it should be possible to build a co-re bpf program,
> no other artifacts needed. You can try it out locally by generating it
> from the local running kernel on your dev machine:
> 
> bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

Not all distros are providing vmlinux.h.
And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 23:41           ` Stephen Hemminger
@ 2024-04-04  0:49             ` Luca Boccassi
  2024-04-04 15:51               ` Stephen Hemminger
  0 siblings, 1 reply; 133+ messages in thread
From: Luca Boccassi @ 2024-04-04  0:49 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 3 Apr 2024 22:19:20 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > Using bpftool to generate the header at build time is a bit icky,
> > > > because it will look at sysfs on the build system, which is from the
> > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > and even be a completely different kconfig/build/distro from the actual
> > > > runtime one.
> > >
> > > One other option would be to ship a pre-built skeleton file.
> > > Which is what the method the old code did.
> > > But that creates an implied dependency on the developers machine build environment.
> >
> > That's what the distro-provided vmlinux.h should help with - by
> > #include'ing that, it should be possible to build a co-re bpf program,
> > no other artifacts needed. You can try it out locally by generating it
> > from the local running kernel on your dev machine:
> >
> > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>
> Not all distros are providing vmlinux.h.
> And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.

Yes and for those the usual pattern is a fallback to generate at build
time, if no pre-prepared vmlinux.h is configured

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-03 21:19         ` Luca Boccassi
  2024-04-03 23:41           ` Stephen Hemminger
@ 2024-04-04 15:30           ` Stephen Hemminger
  2024-04-04 16:11             ` Luca Boccassi
  1 sibling, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-04 15:30 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

On Wed, 3 Apr 2024 22:19:20 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 03 Apr 2024 12:50:35 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > Using bpftool to generate the header at build time is a bit icky,
> > > because it will look at sysfs on the build system, which is from the
> > > running kernel. But a build system's kernel might be some ancient LTS,
> > > and even be a completely different kconfig/build/distro from the actual
> > > runtime one.  
> >
> > One other option would be to ship a pre-built skeleton file.
> > Which is what the method the old code did.
> > But that creates an implied dependency on the developers machine build environment.  
> 
> That's what the distro-provided vmlinux.h should help with - by
> #include'ing that, it should be possible to build a co-re bpf program,
> no other artifacts needed. You can try it out locally by generating it
> from the local running kernel on your dev machine:
> 
> bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

What about Ubuntu with borked installation of bpftool?

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-04  0:49             ` Luca Boccassi
@ 2024-04-04 15:51               ` Stephen Hemminger
  2024-04-04 16:12                 ` Luca Boccassi
  0 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-04 15:51 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

On Thu, 4 Apr 2024 01:49:56 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 3 Apr 2024 22:19:20 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > > <stephen@networkplumber.org> wrote:  
> > > >
> > > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > > Luca Boccassi <bluca@debian.org> wrote:
> > > >  
> > > > > Using bpftool to generate the header at build time is a bit icky,
> > > > > because it will look at sysfs on the build system, which is from the
> > > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > > and even be a completely different kconfig/build/distro from the actual
> > > > > runtime one.  
> > > >
> > > > One other option would be to ship a pre-built skeleton file.
> > > > Which is what the method the old code did.
> > > > But that creates an implied dependency on the developers machine build environment.  
> > >
> > > That's what the distro-provided vmlinux.h should help with - by
> > > #include'ing that, it should be possible to build a co-re bpf program,
> > > no other artifacts needed. You can try it out locally by generating it
> > > from the local running kernel on your dev machine:
> > >
> > > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h  
> >
> > Not all distros are providing vmlinux.h.
> > And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.  
> 
> Yes and for those the usual pattern is a fallback to generate at build
> time, if no pre-prepared vmlinux.h is configured

Looks like vmlinux.h is not setup to handle tc programs.

If vmlinux.h is included, it supersedes other kernel headers (ok).
But is missing some other things like IPv6 options, ether types, and
TC actions. To use it requires copy  pasting from other headers
to fill in the missing pieces. Thats a mess.

This little program only refers to skb and the fields that are problematic
are protocol, mark, and queue_mapping.


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-04 15:30           ` Stephen Hemminger
@ 2024-04-04 16:11             ` Luca Boccassi
  0 siblings, 0 replies; 133+ messages in thread
From: Luca Boccassi @ 2024-04-04 16:11 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On Thu, 4 Apr 2024 at 16:31, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 3 Apr 2024 22:19:20 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > Using bpftool to generate the header at build time is a bit icky,
> > > > because it will look at sysfs on the build system, which is from the
> > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > and even be a completely different kconfig/build/distro from the actual
> > > > runtime one.
> > >
> > > One other option would be to ship a pre-built skeleton file.
> > > Which is what the method the old code did.
> > > But that creates an implied dependency on the developers machine build environment.
> >
> > That's what the distro-provided vmlinux.h should help with - by
> > #include'ing that, it should be possible to build a co-re bpf program,
> > no other artifacts needed. You can try it out locally by generating it
> > from the local running kernel on your dev machine:
> >
> > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>
> What about Ubuntu with borked installation of bpftool?

Yeah that's a bit confusing, the way to do it is to install
linux-tools-generic and then here's logic to find the right one:

https://git.launchpad.net/ubuntu/+source/xdp-tools/tree/debian/rules#n34

But I wouldn't bother with it in upstream projects, let the
integrators deal with it

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v5 7/8] net/tap: use libbpf to load new BPF program
  2024-04-04 15:51               ` Stephen Hemminger
@ 2024-04-04 16:12                 ` Luca Boccassi
  0 siblings, 0 replies; 133+ messages in thread
From: Luca Boccassi @ 2024-04-04 16:12 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On Thu, 4 Apr 2024 at 16:51, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Thu, 4 Apr 2024 01:49:56 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 3 Apr 2024 22:19:20 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > > > <stephen@networkplumber.org> wrote:
> > > > >
> > > > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > > > Luca Boccassi <bluca@debian.org> wrote:
> > > > >
> > > > > > Using bpftool to generate the header at build time is a bit icky,
> > > > > > because it will look at sysfs on the build system, which is from the
> > > > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > > > and even be a completely different kconfig/build/distro from the actual
> > > > > > runtime one.
> > > > >
> > > > > One other option would be to ship a pre-built skeleton file.
> > > > > Which is what the method the old code did.
> > > > > But that creates an implied dependency on the developers machine build environment.
> > > >
> > > > That's what the distro-provided vmlinux.h should help with - by
> > > > #include'ing that, it should be possible to build a co-re bpf program,
> > > > no other artifacts needed. You can try it out locally by generating it
> > > > from the local running kernel on your dev machine:
> > > >
> > > > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
> > >
> > > Not all distros are providing vmlinux.h.
> > > And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.
> >
> > Yes and for those the usual pattern is a fallback to generate at build
> > time, if no pre-prepared vmlinux.h is configured
>
> Looks like vmlinux.h is not setup to handle tc programs.
>
> If vmlinux.h is included, it supersedes other kernel headers (ok).
> But is missing some other things like IPv6 options, ether types, and
> TC actions. To use it requires copy  pasting from other headers
> to fill in the missing pieces. Thats a mess.
>
> This little program only refers to skb and the fields that are problematic
> are protocol, mark, and queue_mapping.

That's not good, could you please report that to the BPF folks? Pretty
sure it should get fixed in bpftool?

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (5 preceding siblings ...)
  2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
@ 2024-04-05 21:14 ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 1/8] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (7 more replies)
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                   ` (5 subsequent siblings)
  12 siblings, 8 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.

v6 - don't build if missing TC flower, a kernel that
     old is not supported. But somebody will try.

     Use BPF CO:RE attribute wrapper to avoid kernel
     header skew.

Stephen Hemminger (8):
  net/tap: do not duplicate fd's
  doc: fix the requirements and building of TAP flow
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: stop "vendoring" linux bpf headers
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files

 .gitignore                            |    3 -
 doc/guides/linux_gsg/sys_reqs.rst     |    3 +
 doc/guides/nics/tap.rst               |   95 +-
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   38 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  267 ++++
 drivers/net/tap/meson.build           |   39 +-
 drivers/net/tap/rte_eth_tap.c         |  199 ++-
 drivers/net/tap/rte_eth_tap.h         |   17 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  549 ++------
 drivers/net/tap/tap_flow.h            |   17 +-
 drivers/net/tap/tap_intr.c            |    7 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 22 files changed, 710 insertions(+), 3399 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v6 1/8] net/tap: do not duplicate fd's
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptopr for both rx and tx queues.
This allows up to 8 queues (versus 4).

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/meson.build   |   2 +-
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 5 files changed, 92 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..9cd124d53e 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -16,7 +16,7 @@ sources = files(
 
 deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
+cflags += '-DTAP_MAX_QUEUES=8'
 
 # input array for meson symbol search:
 # [ "MACRO to define if found", "header for the search",
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 2/8] doc: fix the requirements and building of TAP flow
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 1/8] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 3/8] net/tap: remove unused fields Stephen Hemminger
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The build process for TAP eBPF RSS is now changed, so documentation
needs to be updated.

Since kernel 4.19 is the oldest current LTS supported kernel,
the TAP documentation can be simplified. Any complaints about
flow not working means the kernel is out of scope of current DPDK.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/linux_gsg/sys_reqs.rst |  3 +
 doc/guides/nics/tap.rst           | 95 ++++++++-----------------------
 2 files changed, 28 insertions(+), 70 deletions(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 13be715933..0254568517 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -101,6 +101,9 @@ Running DPDK Applications
 
 To run a DPDK application, some customization may be required on the target machine.
 
+.. _linux_gsg_kernel_version:
+
+
 System Software
 ~~~~~~~~~~~~~~~
 
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..dcfefba567 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -103,13 +103,8 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+The tap PMD supports major flow API pattern items and actions, when running on a supported Linux version. See :ref:`linux_gsg_kernel_version`.
 
 Supported items:
 
@@ -123,7 +118,7 @@ Supported actions:
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS (requires clang, libbpf, and bpftool)
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -229,80 +224,40 @@ load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
 
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
 
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
+The RSS algorithm is written in file ``tap_rss.c`` which is compiled with
+clang and then turned into a skeleton header file with bpftool.
+The skeleton header file is then compiled into the tap driver.
 
 TAP reports on supported RSS functions as part of dev_infos_get callback:
 ``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
+
+**Known limitation:** TAP supports only these functions, it is not possible
+to be more fine grained. For example, selecting only IPv4 and not IPV6
+to be hashed is not possible.
 
 Systems supporting flow API
 ---------------------------
 
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+- Any system which meets the current DPDK kernel requirements should
+  be able to support the flow API.
+
+- Supporting eBPF/RSS requires ``bpftool`` and ``libbpf``.
 
 Limitations
 -----------
 
 * Rx/Tx must have the same number of queues.
+
+* The kernel will distribute packets across all queues.
+  If using flow API then add a default match and action to force a different
+  behavior.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 3/8] net/tap: remove unused fields
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 1/8] net/tap: do not duplicate fd's Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 4/8] net/tap: validate and setup parameters for BPF RSS
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-04-05 21:14   ` [PATCH v6 3/8] net/tap: remove unused fields Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 5/8] net/tap: stop "vendoring" linux bpf headers
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-04-05 21:14   ` [PATCH v6 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

This also blocks tap device from building on kernels before 4.2.
The oldest supported LTS kernel is currently 4.4 and the 4.1
kernel reached end of life in December 2015.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  13 ++--
 drivers/net/tap/rte_eth_tap.c      |  11 +--
 drivers/net/tap/rte_eth_tap.h      |   4 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 30 insertions(+), 232 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 9cd124d53e..4bfb99aa11 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,6 +5,14 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
+# The flower classifier was introduced in Linux 4.2
+# any kernel older than that is outside current DPDK support
+if not cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    build = false
+    reason = 'does not support TC flower'
+endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_bpf_api.c',
@@ -23,12 +31,7 @@ cflags += '-DTAP_MAX_QUEUES=8'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..a97fbcefa0 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -2021,6 +2021,12 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2035,11 +2041,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..2e9a4dfe01 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,6 +71,7 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
@@ -78,7 +80,6 @@ struct pmd_internals {
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +87,7 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111f..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 6/8] net/tap: rewrite the RSS BPF program
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-04-05 21:14   ` [PATCH v6 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:14   ` [PATCH v6 7/8] net/tap: use libbpf to load new " Stephen Hemminger
  2024-04-05 21:15   ` [PATCH v6 8/8] net/tap: remove no longer used files Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  38 ++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 383 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..1d421ff42c
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,38 @@
+This is the BPF program used to implement the RSS across queues flow action.
+The program is loaded when first RSS flow rule is created and is never unloaded.
+
+Each flow rule creates a unique key (handle) and this is used as the key
+for finding the RSS information for that flow rule.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+- rebuilding the BPF requires Clang and bpftool.
+  Some older versions of Ubuntu do not have working bpftool package.
+  Need a version of Clang that can compile to BPF.
+- only standard Toeplitz hash with standard 40 byte key is supported
+- the number of flow rules using RSS is limited to 32
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are not available. If everything is
+there then BPF RSS is enabled.
+
+1. Using clang to compile tap_rss.c the tap_rss.bpf.o file.
+
+2. Using bpftool generate a skeleton header file tap_rss.skel.h from tap_rss.bpf.o.
+   This skeleton header is an large byte array which contains the
+   BPF binary and wrappers to load and use it.
+
+3. The tap flow code then compiles that BPF byte array into the PMD object.
+
+4. When needed the BPF array is loaded by libbpf.
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 7/8] net/tap: use libbpf to load new BPF program
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-04-05 21:14   ` [PATCH v6 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-04-05 21:14   ` Stephen Hemminger
  2024-04-05 21:15   ` [PATCH v6 8/8] net/tap: remove no longer used files Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:14 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  30 ++-
 drivers/net/tap/bpf/tap_rss.c   |  45 ++--
 drivers/net/tap/meson.build     |  26 +-
 drivers/net/tap/rte_eth_tap.c   |  13 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 408 +++++++-------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 171 insertions(+), 388 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..0e719b3ada 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -3,15 +3,24 @@
 
 enable_tap_rss = false
 
+# Loading BPF requires libbpf
 libbpf = dependency('libbpf', required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu has non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 888b3bdc24..1d71941c53 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -203,23 +203,6 @@ parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
 	return 0;
 }
 
-/*
- * Compute RSS hash for packets.
- * Returns 0 if no hash is possible.
- */
-static __u32 __attribute__((always_inline))
-calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
-{
-	const __u32 *key = (const __u32 *)rsskey->key;
-
-	if (skb->protocol == bpf_htons(ETH_P_IP))
-		return parse_ipv4(skb, rsskey->hash_fields, key);
-	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
-		return parse_ipv6(skb, rsskey->hash_fields, key);
-	else
-		return 0;
-}
-
 /*
  * Scale value to be into range [0, n)
  * Assumes val is large (ie hash covers whole u32 range)
@@ -244,20 +227,40 @@ SEC("action") int
 rss_flow_action(struct __sk_buff *skb)
 {
 	const struct rss_key *rsskey;
-	__u32 mark = skb->mark;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
 	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
 
 	/* Lookup RSS configuration for that BPF class */
 	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
 	if (rsskey == NULL)
 		return TC_ACT_OK;
 
-	hash = calculate_rss_hash(skb, rsskey);
-	if (!hash)
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
 		return TC_ACT_OK;
 
 	/* Fold hash to the number of queues configured */
-	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
 	return TC_ACT_PIPE;
 }
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 4bfb99aa11..b95267ba20 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -15,28 +15,22 @@ endif
 
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
-)
+        )
 
 deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=8'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
 
 require_iova_in_mbuf = false
+
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index a97fbcefa0..b76c5bf527 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1129,6 +1129,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1941,6 +1942,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
@@ -2021,12 +2023,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2041,6 +2037,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 2e9a4dfe01..39e9ecaf60 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,10 +79,8 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..77dc8e9741 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,9 +61,11 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -112,13 +106,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,10 +846,11 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
@@ -1104,8 +1098,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1128,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1137,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1241,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1719,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1745,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
-
-		return -ENOTSUP;
-	}
-
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
+	int err;
 
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1803,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1856,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1882,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..00a0f22e31 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 8/8] net/tap: remove no longer used files
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-04-05 21:14   ` [PATCH v6 7/8] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-05 21:15   ` Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-05 21:15 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 0/8] net/tap: cleanups and fix BPF support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (6 preceding siblings ...)
  2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
@ 2024-04-08 21:18 ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 1/8] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (7 more replies)
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                   ` (4 subsequent siblings)
  12 siblings, 8 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.

v7 - use BPF CO:RE to handle build vs runtime in skb offsets. 
   - update documentation
   - workaround for older distributions where support for
     TC flower won't work. No flower == No flow support

Stephen Hemminger (8):
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  doc: update documentation of TAP PMD

 .gitignore                            |    3 -
 doc/guides/linux_gsg/sys_reqs.rst     |    3 +
 doc/guides/nics/tap.rst               |  268 +---
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   38 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |  109 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  267 ++++
 drivers/net/tap/meson.build           |   40 +-
 drivers/net/tap/rte_eth_tap.c         |  225 ++--
 drivers/net/tap/rte_eth_tap.h         |   20 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  549 ++------
 drivers/net/tap/tap_flow.h            |   17 +-
 drivers/net/tap/tap_intr.c            |    7 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 22 files changed, 786 insertions(+), 3528 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v7 1/8] net/tap: do not duplicate fd's
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 2/8] net/tap: remove unused fields Stephen Hemminger
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptopr for both rx and tx queues.
This allows up to 8 queues (versus 4).

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/meson.build   |   2 +-
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 5 files changed, 92 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..9cd124d53e 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -16,7 +16,7 @@ sources = files(
 
 deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
+cflags += '-DTAP_MAX_QUEUES=8'
 
 # input array for meson symbol search:
 # [ "MACRO to define if found", "header for the search",
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 2/8] net/tap: remove unused fields
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 1/8] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 3/8] net/tap: validate and setup parameters for BPF RSS
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 1/8] net/tap: do not duplicate fd's Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 2/8] net/tap: remove unused fields Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 4/8] net/tap: do not build flow support if header is out of date
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-04-08 21:18   ` [PATCH v7 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 9cd124d53e..1fd20cfe93 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=8'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=8'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..3f4fe95a09 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1124,12 +1124,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1265,6 +1268,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1278,7 +1282,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1293,6 +1297,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1306,6 +1311,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1321,6 +1327,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1334,6 +1341,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1349,6 +1357,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1362,6 +1371,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1407,6 +1417,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1424,6 +1436,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1901,7 +1914,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1941,7 +1956,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2021,6 +2038,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2035,11 +2060,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2050,6 +2070,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2102,6 +2123,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2116,14 +2138,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111f..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 5/8] net/tap: rewrite the RSS BPF program
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-04-08 21:18   ` [PATCH v7 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 6/8] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  38 ++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 383 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..1d421ff42c
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,38 @@
+This is the BPF program used to implement the RSS across queues flow action.
+The program is loaded when first RSS flow rule is created and is never unloaded.
+
+Each flow rule creates a unique key (handle) and this is used as the key
+for finding the RSS information for that flow rule.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+- rebuilding the BPF requires Clang and bpftool.
+  Some older versions of Ubuntu do not have working bpftool package.
+  Need a version of Clang that can compile to BPF.
+- only standard Toeplitz hash with standard 40 byte key is supported
+- the number of flow rules using RSS is limited to 32
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are not available. If everything is
+there then BPF RSS is enabled.
+
+1. Using clang to compile tap_rss.c the tap_rss.bpf.o file.
+
+2. Using bpftool generate a skeleton header file tap_rss.skel.h from tap_rss.bpf.o.
+   This skeleton header is an large byte array which contains the
+   BPF binary and wrappers to load and use it.
+
+3. The tap flow code then compiles that BPF byte array into the PMD object.
+
+4. When needed the BPF array is loaded by libbpf.
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 6/8] net/tap: use libbpf to load new BPF program
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-04-08 21:18   ` [PATCH v7 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 7/8] net/tap: remove no longer used files Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 8/8] doc: update documentation of TAP PMD Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  34 ++-
 drivers/net/tap/bpf/tap_rss.c   |  45 ++--
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 408 +++++++-------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 179 insertions(+), 394 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..563e5d1f21 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -3,15 +3,26 @@
 
 enable_tap_rss = false
 
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu has non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +53,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +79,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 888b3bdc24..1d71941c53 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -203,23 +203,6 @@ parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
 	return 0;
 }
 
-/*
- * Compute RSS hash for packets.
- * Returns 0 if no hash is possible.
- */
-static __u32 __attribute__((always_inline))
-calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
-{
-	const __u32 *key = (const __u32 *)rsskey->key;
-
-	if (skb->protocol == bpf_htons(ETH_P_IP))
-		return parse_ipv4(skb, rsskey->hash_fields, key);
-	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
-		return parse_ipv6(skb, rsskey->hash_fields, key);
-	else
-		return 0;
-}
-
 /*
  * Scale value to be into range [0, n)
  * Assumes val is large (ie hash covers whole u32 range)
@@ -244,20 +227,40 @@ SEC("action") int
 rss_flow_action(struct __sk_buff *skb)
 {
 	const struct rss_key *rsskey;
-	__u32 mark = skb->mark;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
 	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
 
 	/* Lookup RSS configuration for that BPF class */
 	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
 	if (rsskey == NULL)
 		return TC_ACT_OK;
 
-	hash = calculate_rss_hash(skb, rsskey);
-	if (!hash)
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
 		return TC_ACT_OK;
 
 	/* Fold hash to the number of queues configured */
-	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
 	return TC_ACT_PIPE;
 }
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 1fd20cfe93..1871448a00 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,31 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
 
-deps = ['bus_vdev', 'gso', 'hash']
-
-cflags += '-DTAP_MAX_QUEUES=8'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
-
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 3f4fe95a09..793730de08 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1131,6 +1131,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1956,6 +1957,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2038,13 +2040,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2060,6 +2055,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..77dc8e9741 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,9 +61,11 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -112,13 +106,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,10 +846,11 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
@@ -1104,8 +1098,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1128,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1137,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1241,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1719,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1745,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
-
-		return -ENOTSUP;
-	}
-
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
+	int err;
 
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1803,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1856,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1882,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..00a0f22e31 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 7/8] net/tap: remove no longer used files
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-04-08 21:18   ` [PATCH v7 6/8] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  2024-04-08 21:18   ` [PATCH v7 8/8] doc: update documentation of TAP PMD Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 8/8] doc: update documentation of TAP PMD
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-04-08 21:18   ` [PATCH v7 7/8] net/tap: remove no longer used files Stephen Hemminger
@ 2024-04-08 21:18   ` Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-08 21:18 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/linux_gsg/sys_reqs.rst |   3 +
 doc/guides/nics/tap.rst           | 268 ++++++++----------------------
 2 files changed, 74 insertions(+), 197 deletions(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 13be715933..0254568517 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -101,6 +101,9 @@ Running DPDK Applications
 
 To run a DPDK application, some customization may be required on the target machine.
 
+.. _linux_gsg_kernel_version:
+
+
 System Software
 ~~~~~~~~~~~~~~~
 
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..7f07c68808 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,45 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +57,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN device are creted with the command line arguments as ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +81,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux flow based traffic control filter
+``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +117,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +158,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 0/8] net/tap: cleanups and fix BPF support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (7 preceding siblings ...)
  2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
@ 2024-04-09  3:40 ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 1/8] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (7 more replies)
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                   ` (3 subsequent siblings)
  12 siblings, 8 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain.

Stephen Hemminger (8):
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  doc: update documentation of TAP PMD

v8 - fix build with CentOS 7. Although CentOS will soon
     be unsupported in DPDK.

 .gitignore                            |    3 -
 doc/guides/linux_gsg/sys_reqs.rst     |    3 +
 doc/guides/nics/tap.rst               |  274 ++--
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   38 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  267 ++++
 drivers/net/tap/meson.build           |   42 +-
 drivers/net/tap/rte_eth_tap.c         |  225 ++--
 drivers/net/tap/rte_eth_tap.h         |   20 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  559 +++-----
 drivers/net/tap/tap_flow.h            |   17 +-
 drivers/net/tap/tap_intr.c            |    7 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 22 files changed, 801 insertions(+), 3529 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v8 1/8] net/tap: do not duplicate fd's
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 2/8] net/tap: remove unused fields Stephen Hemminger
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptopr for both rx and tx queues.
This allows up to 8 queues (versus 4).

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/meson.build   |   2 +-
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 5 files changed, 92 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..9cd124d53e 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -16,7 +16,7 @@ sources = files(
 
 deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
+cflags += '-DTAP_MAX_QUEUES=8'
 
 # input array for meson symbol search:
 # [ "MACRO to define if found", "header for the search",
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 2/8] net/tap: remove unused fields
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 1/8] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 3/8] net/tap: validate and setup parameters for BPF RSS
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 1/8] net/tap: do not duplicate fd's Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 2/8] net/tap: remove unused fields Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 4/8] net/tap: do not build flow support if header is out of date
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-04-09  3:40   ` [PATCH v8 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 9cd124d53e..1fd20cfe93 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=8'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=8'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..3f4fe95a09 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1124,12 +1124,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1265,6 +1268,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1278,7 +1282,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1293,6 +1297,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1306,6 +1311,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1321,6 +1327,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1334,6 +1341,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1349,6 +1357,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1362,6 +1371,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1407,6 +1417,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1424,6 +1436,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1901,7 +1914,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1941,7 +1956,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2021,6 +2038,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2035,11 +2060,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2050,6 +2070,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2102,6 +2123,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2116,14 +2138,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index 0d38bc111f..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-} __rte_aligned(8);
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 5/8] net/tap: rewrite the RSS BPF program
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-04-09  3:40   ` [PATCH v8 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 6/8] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  38 ++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 383 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..1d421ff42c
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,38 @@
+This is the BPF program used to implement the RSS across queues flow action.
+The program is loaded when first RSS flow rule is created and is never unloaded.
+
+Each flow rule creates a unique key (handle) and this is used as the key
+for finding the RSS information for that flow rule.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+- rebuilding the BPF requires Clang and bpftool.
+  Some older versions of Ubuntu do not have working bpftool package.
+  Need a version of Clang that can compile to BPF.
+- only standard Toeplitz hash with standard 40 byte key is supported
+- the number of flow rules using RSS is limited to 32
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are not available. If everything is
+there then BPF RSS is enabled.
+
+1. Using clang to compile tap_rss.c the tap_rss.bpf.o file.
+
+2. Using bpftool generate a skeleton header file tap_rss.skel.h from tap_rss.bpf.o.
+   This skeleton header is an large byte array which contains the
+   BPF binary and wrappers to load and use it.
+
+3. The tap flow code then compiles that BPF byte array into the PMD object.
+
+4. When needed the BPF array is loaded by libbpf.
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 6/8] net/tap: use libbpf to load new BPF program
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-04-09  3:40   ` [PATCH v8 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 7/8] net/tap: remove no longer used files Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 8/8] doc: update documentation of TAP PMD Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  36 ++-
 drivers/net/tap/bpf/tap_rss.c   |  45 ++--
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 418 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 189 insertions(+), 396 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..45e8c3b498 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -1,17 +1,26 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
 
-enable_tap_rss = false
-
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu versions have non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 888b3bdc24..1d71941c53 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -203,23 +203,6 @@ parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
 	return 0;
 }
 
-/*
- * Compute RSS hash for packets.
- * Returns 0 if no hash is possible.
- */
-static __u32 __attribute__((always_inline))
-calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
-{
-	const __u32 *key = (const __u32 *)rsskey->key;
-
-	if (skb->protocol == bpf_htons(ETH_P_IP))
-		return parse_ipv4(skb, rsskey->hash_fields, key);
-	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
-		return parse_ipv6(skb, rsskey->hash_fields, key);
-	else
-		return 0;
-}
-
 /*
  * Scale value to be into range [0, n)
  * Assumes val is large (ie hash covers whole u32 range)
@@ -244,20 +227,40 @@ SEC("action") int
 rss_flow_action(struct __sk_buff *skb)
 {
 	const struct rss_key *rsskey;
-	__u32 mark = skb->mark;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
 	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
 
 	/* Lookup RSS configuration for that BPF class */
 	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
 	if (rsskey == NULL)
 		return TC_ACT_OK;
 
-	hash = calculate_rss_hash(skb, rsskey);
-	if (!hash)
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
 		return TC_ACT_OK;
 
 	/* Fold hash to the number of queues configured */
-	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
 	return TC_ACT_PIPE;
 }
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 1fd20cfe93..26074059fa 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,33 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
-
-deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=8'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+    enable_tap_rss = false
 
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 3f4fe95a09..793730de08 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1131,6 +1131,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1956,6 +1957,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2038,13 +2040,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2060,6 +2055,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..322153d806 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,12 +61,16 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
+#ifdef HAVE_BPF_RSS
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
+#endif
 	};
 };
 
@@ -112,13 +108,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,11 +848,14 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
-	} else if (strcmp("bpf", adata->id) == 0) {
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
+	}
+#ifdef HAVE_BPF_RSS
+	else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
@@ -865,7 +863,9 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
-	} else {
+	}
+#endif
+	else {
 		return -1;
 	}
 	tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
@@ -1104,8 +1104,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1134,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1143,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1247,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1725,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1751,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-	}
-
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1809,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1862,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1888,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..9411626661 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,10 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
+#ifdef HAVE_BPF_RSS
 #include <linux/tc_act/tc_bpf.h>
 #endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 7/8] net/tap: remove no longer used files
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-04-09  3:40   ` [PATCH v8 6/8] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  2024-04-09  3:40   ` [PATCH v8 8/8] doc: update documentation of TAP PMD Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 8/8] doc: update documentation of TAP PMD
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-04-09  3:40   ` [PATCH v8 7/8] net/tap: remove no longer used files Stephen Hemminger
@ 2024-04-09  3:40   ` Stephen Hemminger
  7 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-09  3:40 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/linux_gsg/sys_reqs.rst |   3 +
 doc/guides/nics/tap.rst           | 274 +++++++++---------------------
 2 files changed, 80 insertions(+), 197 deletions(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 13be715933..0254568517 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -101,6 +101,9 @@ Running DPDK Applications
 
 To run a DPDK application, some customization may be required on the target machine.
 
+.. _linux_gsg_kernel_version:
+
+
 System Software
 ~~~~~~~~~~~~~~~
 
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..55e38fb25b 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,51 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+Requirements
+~~~~~~~~~~~~
+
+The TAP PMD requires kernel support for multiple queues in TAP device as
+well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
+These are standard kernel features in most Linux distributions.
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN devices are created with the command line arguments ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux kernel support of flow based
+traffic control filter ``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +123,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 0/9] net/tap: fix RSS (BPF) support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (8 preceding siblings ...)
  2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
@ 2024-04-26 15:48 ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 1/9] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (9 more replies)
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                   ` (2 subsequent siblings)
  12 siblings, 10 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain. I do not
intend to support backporting this to stable releases due
to lack of demand and dealing with older distros.

v9 - rebase and keep max queues at 16

Stephen Hemminger (9):
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  doc: update documentation of TAP PMD
  net/tap: simplify the internal structure

 .gitignore                            |    3 -
 doc/guides/linux_gsg/sys_reqs.rst     |    3 +
 doc/guides/nics/tap.rst               |  274 ++--
 drivers/net/tap/bpf/Makefile          |   19 -
 drivers/net/tap/bpf/README            |   38 +
 drivers/net/tap/bpf/bpf_api.h         |  276 ----
 drivers/net/tap/bpf/bpf_elf.h         |   53 -
 drivers/net/tap/bpf/bpf_extract.py    |   86 --
 drivers/net/tap/bpf/meson.build       |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c |  255 ----
 drivers/net/tap/bpf/tap_rss.c         |  267 ++++
 drivers/net/tap/meson.build           |   42 +-
 drivers/net/tap/rte_eth_tap.c         |  267 ++--
 drivers/net/tap/rte_eth_tap.h         |   32 +-
 drivers/net/tap/tap_bpf.h             |  121 --
 drivers/net/tap/tap_bpf_api.c         |  190 ---
 drivers/net/tap/tap_bpf_insns.h       | 1743 -------------------------
 drivers/net/tap/tap_flow.c            |  559 +++-----
 drivers/net/tap/tap_flow.h            |   17 +-
 drivers/net/tap/tap_intr.c            |    7 +-
 drivers/net/tap/tap_rss.h             |   21 +-
 drivers/net/tap/tap_tcmsgs.h          |    4 +-
 22 files changed, 833 insertions(+), 3551 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v9 1/9] net/tap: do not duplicate fd's
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-05-01 11:13     ` Ferruh Yigit
  2024-04-26 15:48   ` [PATCH v9 2/9] net/tap: remove unused fields Stephen Hemminger
                     ` (8 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptopr for both rx and tx queues.
This allows up to 8 queues (versus 4) to be used with secondary process.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 4 files changed, 91 insertions(+), 119 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 2/9] net/tap: remove unused fields
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 1/9] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 3/9] net/tap: validate and setup parameters for BPF RSS
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 1/9] net/tap: do not duplicate fd's Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 2/9] net/tap: remove unused fields Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 4/9] net/tap: do not build flow support if header is out of date
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..66647a1c62 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=16'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..3f4fe95a09 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1124,12 +1124,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1265,6 +1268,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1278,7 +1282,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1293,6 +1297,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1306,6 +1311,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1321,6 +1327,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1334,6 +1341,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1349,6 +1357,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1362,6 +1371,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1407,6 +1417,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1424,6 +1436,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1901,7 +1914,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1941,7 +1956,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2021,6 +2038,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2035,11 +2060,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2050,6 +2070,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2102,6 +2123,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2116,14 +2138,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index d8437927ef..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union __rte_aligned(8) bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-};
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 5/9] net/tap: rewrite the RSS BPF program
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-05-01 11:14     ` Ferruh Yigit
  2024-04-26 15:48   ` [PATCH v9 6/9] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (4 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite the BPF program used to do queue based RSS.
Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF.
	- the resulting queue is placed in skb rather
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  38 ++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 383 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..1d421ff42c
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,38 @@
+This is the BPF program used to implement the RSS across queues flow action.
+The program is loaded when first RSS flow rule is created and is never unloaded.
+
+Each flow rule creates a unique key (handle) and this is used as the key
+for finding the RSS information for that flow rule.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+- rebuilding the BPF requires Clang and bpftool.
+  Some older versions of Ubuntu do not have working bpftool package.
+  Need a version of Clang that can compile to BPF.
+- only standard Toeplitz hash with standard 40 byte key is supported
+- the number of flow rules using RSS is limited to 32
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are not available. If everything is
+there then BPF RSS is enabled.
+
+1. Using clang to compile tap_rss.c the tap_rss.bpf.o file.
+
+2. Using bpftool generate a skeleton header file tap_rss.skel.h from tap_rss.bpf.o.
+   This skeleton header is an large byte array which contains the
+   BPF binary and wrappers to load and use it.
+
+3. The tap flow code then compiles that BPF byte array into the PMD object.
+
+4. When needed the BPF array is loaded by libbpf.
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 6/9] net/tap: use libbpf to load new BPF program
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 7/9] net/tap: remove no longer used files Stephen Hemminger
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  36 ++-
 drivers/net/tap/bpf/tap_rss.c   |  45 ++--
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 418 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 189 insertions(+), 396 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..45e8c3b498 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -1,17 +1,26 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
 
-enable_tap_rss = false
-
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu versions have non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 888b3bdc24..1d71941c53 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -203,23 +203,6 @@ parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
 	return 0;
 }
 
-/*
- * Compute RSS hash for packets.
- * Returns 0 if no hash is possible.
- */
-static __u32 __attribute__((always_inline))
-calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
-{
-	const __u32 *key = (const __u32 *)rsskey->key;
-
-	if (skb->protocol == bpf_htons(ETH_P_IP))
-		return parse_ipv4(skb, rsskey->hash_fields, key);
-	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
-		return parse_ipv6(skb, rsskey->hash_fields, key);
-	else
-		return 0;
-}
-
 /*
  * Scale value to be into range [0, n)
  * Assumes val is large (ie hash covers whole u32 range)
@@ -244,20 +227,40 @@ SEC("action") int
 rss_flow_action(struct __sk_buff *skb)
 {
 	const struct rss_key *rsskey;
-	__u32 mark = skb->mark;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
 	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
 
 	/* Lookup RSS configuration for that BPF class */
 	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
 	if (rsskey == NULL)
 		return TC_ACT_OK;
 
-	hash = calculate_rss_hash(skb, rsskey);
-	if (!hash)
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
 		return TC_ACT_OK;
 
 	/* Fold hash to the number of queues configured */
-	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
 	return TC_ACT_PIPE;
 }
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 66647a1c62..26074059fa 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,33 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
-
-deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+    enable_tap_rss = false
 
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 3f4fe95a09..793730de08 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1131,6 +1131,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1956,6 +1957,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2038,13 +2040,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2060,6 +2055,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..322153d806 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,12 +61,16 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
+#ifdef HAVE_BPF_RSS
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
+#endif
 	};
 };
 
@@ -112,13 +108,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,11 +848,14 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
-	} else if (strcmp("bpf", adata->id) == 0) {
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
+	}
+#ifdef HAVE_BPF_RSS
+	else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
@@ -865,7 +863,9 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
-	} else {
+	}
+#endif
+	else {
 		return -1;
 	}
 	tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
@@ -1104,8 +1104,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1134,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1143,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1247,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1725,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1751,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-	}
-
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1809,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1862,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1888,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..9411626661 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,10 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
+#ifdef HAVE_BPF_RSS
 #include <linux/tc_act/tc_bpf.h>
 #endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 7/9] net/tap: remove no longer used files
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 6/9] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-04-26 15:48   ` [PATCH v9 8/9] doc: update documentation of TAP PMD Stephen Hemminger
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 8/9] doc: update documentation of TAP PMD
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 7/9] net/tap: remove no longer used files Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-05-01 12:36     ` Ferruh Yigit
  2024-04-26 15:48   ` [PATCH v9 9/9] net/tap: simplify the internal structure Stephen Hemminger
  2024-05-01 11:18   ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Ferruh Yigit
  9 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/linux_gsg/sys_reqs.rst |   3 +
 doc/guides/nics/tap.rst           | 274 +++++++++---------------------
 2 files changed, 80 insertions(+), 197 deletions(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 13be715933..0254568517 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -101,6 +101,9 @@ Running DPDK Applications
 
 To run a DPDK application, some customization may be required on the target machine.
 
+.. _linux_gsg_kernel_version:
+
+
 System Software
 ~~~~~~~~~~~~~~~
 
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..55e38fb25b 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,51 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+Requirements
+~~~~~~~~~~~~
+
+The TAP PMD requires kernel support for multiple queues in TAP device as
+well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
+These are standard kernel features in most Linux distributions.
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN devices are created with the command line arguments ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux kernel support of flow based
+traffic control filter ``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +123,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 9/9] net/tap: simplify the internal structure
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (7 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 8/9] doc: update documentation of TAP PMD Stephen Hemminger
@ 2024-04-26 15:48   ` Stephen Hemminger
  2024-05-01 11:18   ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Ferruh Yigit
  9 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-04-26 15:48 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The names of Linux network devices are IFNAMSIZ(16) not the
same as DPDK which has up to 64 characters. Don't need to
hold onto the whole ifreq to save the remote interface flags.

Rearrange internal structure for locality.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 42 ++++++++++++++++++++++-------------
 drivers/net/tap/rte_eth_tap.h | 12 +++++-----
 2 files changed, 32 insertions(+), 22 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 793730de08..b066a8acd1 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -212,7 +212,7 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 	 * and need to find the resulting device.
 	 */
 	TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name);
-	strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(pmd->name, ifr.ifr_name, IFNAMSIZ);
 
 	if (is_keepalive) {
 		/*
@@ -1151,9 +1151,13 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	if (internals->remote_if_index) {
+		struct ifreq remote_ifr;
+
+		strlcpy(remote_ifr.ifr_name, internals->remote_iface, IFNAMSIZ);
+		remote_ifr.ifr_flags = internals->remote_flags;
+
 		/* Restore initial remote state */
-		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS,
-				&internals->remote_initial_flags);
+		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS, &remote_ifr);
 		if (ret)
 			TAP_LOG(ERR, "restore remote state failed: %d", ret);
 
@@ -2074,16 +2078,22 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
+		struct ifreq remote_ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index) {
 			TAP_LOG(ERR, "%s: failed to get %s if_index.",
 				pmd->name, remote_iface);
 			goto error_remote;
 		}
-		strlcpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(pmd->remote_iface, remote_iface, IFNAMSIZ);
+
+		memset(&remote_ifr, 0, sizeof(ifr));
+		strlcpy(remote_ifr.ifr_name, remote_iface, IFNAMSIZ);
 
 		/* Save state of remote device */
-		tap_ioctl(pmd, SIOCGIFFLAGS, &pmd->remote_initial_flags, 0, REMOTE_ONLY);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &remote_ifr, 0, REMOTE_ONLY);
+		pmd->remote_flags = remote_ifr.ifr_flags;
 
 		/* Replicate remote MAC address */
 		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
@@ -2197,10 +2207,10 @@ set_interface_name(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	} else {
 		/* use tap%d which causes kernel to choose next available */
-		strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
 	}
 	return 0;
 }
@@ -2218,7 +2228,7 @@ set_remote_iface(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	}
 
 	return 0;
@@ -2269,13 +2279,13 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	const char *name, *params;
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
-	char tun_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tun_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_eth_dev *eth_dev;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
 	    strlen(params) == 0) {
@@ -2291,7 +2301,7 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	}
 
 	/* use tun%d which causes kernel to choose next available */
-	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
@@ -2431,8 +2441,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
 	int speed;
-	char tap_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tap_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_ether_addr user_mac = { .addr_bytes = {0} };
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
@@ -2486,8 +2496,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	speed = RTE_ETH_SPEED_NUM_10G;
 
 	/* use tap%d which causes kernel to choose next available */
-	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index ce4322ad04..ca510e2c6b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -68,15 +68,16 @@ struct tx_queue {
 
 struct pmd_internals {
 	struct rte_eth_dev *dev;          /* Ethernet device. */
-	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
-	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
+	char remote_iface[IFNAMSIZ];	  /* Remote netdevice name */
+	char name[IFNAMSIZ];		  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
 	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
-	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
+	uint16_t remote_flags;		  /* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+	int ka_fd;                        /* keep-alive file descriptor */
 
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
@@ -88,12 +89,11 @@ struct pmd_internals {
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 #endif
+	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
+	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
-	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
-	int ka_fd;                        /* keep-alive file descriptor */
-	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
 
 struct pmd_process_private {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 1/9] net/tap: do not duplicate fd's
  2024-04-26 15:48   ` [PATCH v9 1/9] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-05-01 11:13     ` Ferruh Yigit
  2024-05-01 23:53       ` Stephen Hemminger
  0 siblings, 1 reply; 133+ messages in thread
From: Ferruh Yigit @ 2024-05-01 11:13 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On 4/26/2024 4:48 PM, Stephen Hemminger wrote:
> The TAP device can use same file descriptopr for both rx and tx queues.
>

s/descriptopr/descriptor/

> This allows up to 8 queues (versus 4) to be used with secondary process.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

<...>

> @@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
>  	}
>  
>  	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
> -		if (process_private->rxq_fds[i] != -1) {
> -			rxq = &internals->rxq[i];
> -			close(process_private->rxq_fds[i]);
> -			process_private->rxq_fds[i] = -1;
> -			tap_rxq_pool_free(rxq->pool);
> -			rte_free(rxq->iovecs);
> -			rxq->pool = NULL;
> -			rxq->iovecs = NULL;
> -		}
> -		if (process_private->txq_fds[i] != -1) {
> -			close(process_private->txq_fds[i]);
> -			process_private->txq_fds[i] = -1;
> -		}
> +		struct rx_queue *rxq = &internals->rxq[i];
> +
> +		if (process_private->fds[i] == -1)
> +			continue;
> +
> +		close(process_private->fds[i]);
> +		process_private->fds[i] = -1;
>

can 'tap_queue_close()' be used here? (probably with slight change)

<...>

> @@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
>  		uint16_t qid,
>  		int is_rx)
>  {
> -	int ret;
> -	int *fd;
> -	int *other_fd;
> -	const char *dir;
> +	int fd, ret;
>  	struct pmd_internals *pmd = dev->data->dev_private;
>  	struct pmd_process_private *process_private = dev->process_private;
>  	struct rx_queue *rx = &internals->rxq[qid];
>  	struct tx_queue *tx = &internals->txq[qid];
> -	struct rte_gso_ctx *gso_ctx;
> +	struct rte_gso_ctx *gso_ctx = NULL;
> +	const char *dir = is_rx ? "rx" : "tx";
>  
> -	if (is_rx) {
> -		fd = &process_private->rxq_fds[qid];
> -		other_fd = &process_private->txq_fds[qid];
> -		dir = "rx";
> -		gso_ctx = NULL;
> -	} else {
> -		fd = &process_private->txq_fds[qid];
> -		other_fd = &process_private->rxq_fds[qid];
> -		dir = "tx";
> +	if (is_rx)
>  		gso_ctx = &tx->gso_ctx;
>

As commented on other version of this patch, shouldn't this be:
`if (!is_rx)`

<...>

> diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
> index fa50fe45d7..a78fd50cd4 100644
> --- a/drivers/net/tap/tap_flow.c
> +++ b/drivers/net/tap/tap_flow.c
> @@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
>  	 * If netdevice is there, setup appropriate flow rules immediately.
>  	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
>  	 */
> -	if (!process_private->rxq_fds[0])
> +	if (process_private->fds[0] == -1)
>

change in the condition looks reasonable but not directly related with
the change, does it require its own patch?


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 5/9] net/tap: rewrite the RSS BPF program
  2024-04-26 15:48   ` [PATCH v9 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-05-01 11:14     ` Ferruh Yigit
  0 siblings, 0 replies; 133+ messages in thread
From: Ferruh Yigit @ 2024-05-01 11:14 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On 4/26/2024 4:48 PM, Stephen Hemminger wrote:
> Rewrite the BPF program used to do queue based RSS.
> Important changes:
> 	- uses newer BPF map format BTF
> 	- accepts key as parameter rather than constant default
> 	- can do L3 or L4 hashing
> 	- supports IPv4 options
> 	- supports IPv6 extension headers
> 	- restructured for readability
> 
> The usage of BPF is different as well:
> 	- the incoming configuration is looked up based on
> 	  class parameters rather than patching the BPF.
> 	- the resulting queue is placed in skb rather
> 	  than requiring a second pass through classifier step.
> 
> Note: This version only works with later patch to enable it on
> the DPDK driver side. It is submitted as an incremental patch
> to allow for easier review. Bisection still works because
> the old instruction are still present for now.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

<...>

> @@ -0,0 +1,38 @@
> +This is the BPF program used to implement the RSS across queues flow action.
> +The program is loaded when first RSS flow rule is created and is never unloaded.
> +
> +Each flow rule creates a unique key (handle) and this is used as the key
> +for finding the RSS information for that flow rule.
> +
> +This version is built the BPF Compile Once — Run Everywhere (CO-RE)
> +framework and uses libbpf and bpftool.
> +
> +Limitations
> +-----------
> +- requires libbpf to run
> +- rebuilding the BPF requires Clang and bpftool.
> +  Some older versions of Ubuntu do not have working bpftool package.
> +  Need a version of Clang that can compile to BPF.
> +- only standard Toeplitz hash with standard 40 byte key is supported
> +- the number of flow rules using RSS is limited to 32
> +
> +Building
> +--------
> +During the DPDK build process the meson build file checks that
> +libbpf, bpftool, and clang are not available. If everything is
>

s/and clang are *not* available./and clang are available./ ?


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] net/tap: fix RSS (BPF) support
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
                     ` (8 preceding siblings ...)
  2024-04-26 15:48   ` [PATCH v9 9/9] net/tap: simplify the internal structure Stephen Hemminger
@ 2024-05-01 11:18   ` Ferruh Yigit
  2024-05-01 15:41     ` Stephen Hemminger
  9 siblings, 1 reply; 133+ messages in thread
From: Ferruh Yigit @ 2024-05-01 11:18 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On 4/26/2024 4:48 PM, Stephen Hemminger wrote:
> The support of doing RSS for rte_flow_action was a cool idea
> but it has been broken for several releases of DPDK as the
> kernel and BPF infrastructure changed.
> 
> This series cleans up the BPF program, implements several
> features that were never completed in the original code
> and changes to use the current BPF toolchain.
> 
> The result should be easier to read and maintain. I do not
> intend to support backporting this to stable releases due
> to lack of demand and dealing with older distros.
> 
> v9 - rebase and keep max queues at 16
> 
> Stephen Hemminger (9):
>   net/tap: do not duplicate fd's
>   net/tap: remove unused fields
>   net/tap: validate and setup parameters for BPF RSS
>   net/tap: do not build flow support if header is out of date
>   net/tap: rewrite the RSS BPF program
>   net/tap: use libbpf to load new BPF program
>   net/tap: remove no longer used files
>   doc: update documentation of TAP PMD
>   net/tap: simplify the internal structure
>

Thanks for reviving tap eBPF support, I am for merging this set (as
early as possible).

But I have two concerns,
1. Build environment header file dependencies and external library
dependency version changed. Not sure if this will impact users.
What do you think at least to update release notes to notify users?

2. We need this to be tested, either by users or test teams. I will
bring the issue in next release status meeting to see if we have anyone
testing tap eBPF support.

Thanks,
ferruh

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 8/9] doc: update documentation of TAP PMD
  2024-04-26 15:48   ` [PATCH v9 8/9] doc: update documentation of TAP PMD Stephen Hemminger
@ 2024-05-01 12:36     ` Ferruh Yigit
  0 siblings, 0 replies; 133+ messages in thread
From: Ferruh Yigit @ 2024-05-01 12:36 UTC (permalink / raw)
  To: Stephen Hemminger, dev

On 4/26/2024 4:48 PM, Stephen Hemminger wrote:
> The driver support of flows has changed and the wording in
> the guide was awkward.
> 
> Drop references to DPDK pktgen in this documentation since
> it is not required and confusing.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  doc/guides/linux_gsg/sys_reqs.rst |   3 +
>  doc/guides/nics/tap.rst           | 274 +++++++++---------------------
>  2 files changed, 80 insertions(+), 197 deletions(-)
> 
> diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
> index 13be715933..0254568517 100644
> --- a/doc/guides/linux_gsg/sys_reqs.rst
> +++ b/doc/guides/linux_gsg/sys_reqs.rst
> @@ -101,6 +101,9 @@ Running DPDK Applications
>  
>  To run a DPDK application, some customization may be required on the target machine.
>  
> +.. _linux_gsg_kernel_version:
> +
> +
>

I guess there was an intention to use this document as reference, but I
don't see the link. Perhaps anchor is no more required?

>  System Software
>  ~~~~~~~~~~~~~~~
>  
> diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
> index d4f45c02a1..55e38fb25b 100644
> --- a/doc/guides/nics/tap.rst
> +++ b/doc/guides/nics/tap.rst
> @@ -1,47 +1,51 @@
>  ..  SPDX-License-Identifier: BSD-3-Clause
>      Copyright(c) 2016 Intel Corporation.
>  
> -Tun|Tap Poll Mode Driver
> -========================
> +TAP Poll Mode Driver
> +====================
>  
> -The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
> -local host. The PMD allows for DPDK and the host to communicate using a raw
> -device interface on the host and in the DPDK application.
> +The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
> +by the Linux kernel. This PMD is useful when writing DPDK application
> +for offloading network functionality (such as tunneling) from the kernel.
>  
> -The device created is a TAP device, which sends/receives packet in a raw
> -format with a L2 header. The usage for a TAP PMD is for connectivity to the
> -local host using a TAP interface. When the TAP PMD is initialized it will
> -create a number of tap devices in the host accessed via ``ifconfig -a`` or
> -``ip`` command. The commands can be used to assign and query the virtual like
> -device.
> +From the kernel point of view, the TAP device looks like a regular network interface.
> +The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
> +It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
>  
> -These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
> -along with being able to be used as a network connection to the DPDK
> -application. The method enable one or more interfaces is to use the
> -``--vdev=net_tap0`` option on the DPDK application command line. Each
> -``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
> -and so on.
> +From the DPDK application, the TAP device looks like a DPDK ethdev.
> +Packets are sent and received in L2 (Ethernet) format. The standare DPDK
> +API's to query for information, statistics and send and receive packets
> +work as expected.
>  
> -The interface name can be changed by adding the ``iface=foo0``, for example::
> +Requirements
> +~~~~~~~~~~~~
> +
> +The TAP PMD requires kernel support for multiple queues in TAP device as
> +well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
> +These are standard kernel features in most Linux distributions.
> +
> +Arguments
> +---------
> +
> +TAP devices are created with the command line
> +``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
> +with a different ``net_tapX`` device.
> +
> +By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
> +The interface name can be specified by adding the ``iface=foo0``, for example::
>  
>     --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
>  
> -Normally the PMD will generate a random MAC address, but when testing or with
> -a static configuration the developer may need a fixed MAC address style.
> -Using the option ``mac=fixed`` you can create a fixed known MAC address::
> +Normally the PMD will generate a random MAC address.
> +If a static address is desired instead, the ``mac=fixed`` can be used.
>  
>     --vdev=net_tap0,mac=fixed
>  
> -The MAC address will have a fixed value with the last octet incrementing by one
> -for each interface string containing ``mac=fixed``. The MAC address is formatted
> -as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
> -actual MAC address: ``02:64:74:61:70:[00-FF]``.
> -
> -   --vdev=net_tap0,mac="02:64:74:61:70:11"
> +With the fixed option, the MAC address will have the first octets:
> +as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
>  
> -The MAC address will have a user value passed as string. The MAC address is in
> -format with delimiter ``:``. The string is byte converted to hex and you get
> -the actual MAC address: ``02:64:74:61:70:11``.
> +To specify a specific MAC address use the conventional representation.
> +The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
>  
>  It is possible to specify a remote netdevice to capture packets from by adding
>  ``remote=foo1``, for example::
> @@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
>  rte_flow rules on the tap PMD to capture specific traffic (see next section for
>  examples).
>  
> -After the DPDK application is started you can send and receive packets on the
> -interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
> -point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
> -and others to communicate with the DPDK application. The DPDK application may
> -not understand network protocols like IPv4/6, UDP or TCP unless the
> -application has been written to understand these protocols.
> -
> -If you need the interface as a real network interface meaning running and has
> -a valid IP address then you can do this with the following commands::
> -
> -   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
> -   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
> -
> -Please change the IP addresses as you see fit.
> -
> -If routing is enabled on the host you can also communicate with the DPDK App
> -over the internet via a standard socket layer application as long as you
> -account for the protocol handling in the application.
> -
> -If you have a Network Stack in your DPDK application or something like it you
> -can utilize that stack to handle the network protocols. Plus you would be able
> -to address the interface using an IP address assigned to the internal
> -interface.
> -
>  Normally, when the DPDK application exits,
>  the TAP device is marked down and is removed.
> -But this behaviour can be overridden by the use of the persist flag, example::
> +But this behavior can be overridden by the use of the persist flag, example::
>  
>    --vdev=net_tap0,iface=tap0,persist ...
>  
> -The TUN PMD allows user to create a TUN device on host. The PMD allows user
> -to transmit and receive packets via DPDK API calls with L3 header and payload.
> -The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
> -interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
> +TUN devices
> +-----------
> +
> +The TAP device can be used an L3 tunnel only device (TUN).
> +This type of device does not include the Ethernet (L2) header; all packets
> +are sent and received as IP packets.
> +
> +TUN devices are created with the command line arguments ``--vdev=net_tunX``,
>  where X stands for unique id, example::
>  
>     --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
> @@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
>  Flow API support
>  ----------------
>  
> -The tap PMD supports major flow API pattern items and actions, when running on
> -linux kernels above 4.2 ("Flower" classifier required).
> -The kernel support can be checked with this command::
> +The TAP PMD supports major flow API pattern items and actions.
> +
> +Requirements
> +~~~~~~~~~~~~
>  
> -   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
> -   tee -a /dev/stderr | grep -q '=m' &&
> -   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
> +Flow support in TAP driver requires the Linux kernel support of flow based
> +traffic control filter ``flower``. This was added in Linux 4.3 kernel.
>  
> -Supported items:
> +The implementation of RSS action uses an eBPF module that requires additional
> +libraries and tools. Building the RSS support requires the ``clang``
> +compiler to compile the C code to BPF target; ``bpftool`` to convert the
> +compiled BPF object to a header file; and ``libbpf`` to load the eBPF
> +action into the kernel.
>  
> -- eth: src and dst (with variable masks), and eth_type (0xffff mask).
> -- vlan: vid, pcp, but not eid. (requires kernel 4.9)
> -- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
> -- udp/tcp: src and dst port (0xffff) mask.
> +Supported match items:
> +
> +  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
> +  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
> +  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
> +  - udp/tcp: src and dst port (0xffff) mask.
>  
>  Supported actions:
>  
>  - DROP
>  - QUEUE
>  - PASSTHRU
> -- RSS (requires kernel 4.9)
> +- RSS
>  
>  It is generally not possible to provide a "last" item. However, if the "last"
>  item, once masked, is identical to the masked spec, then it is supported.
> @@ -133,7 +123,7 @@ full mask (exact match).
>  
>  As rules are translated to TC, it is possible to show them with something like::
>  
> -   tc -s filter show dev tap1 parent 1:
> +   tc -s filter show dev dtap1 parent 1:
>  
>  Examples of testpmd flow rules
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> @@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
>    - Maximum 8 queues shared
>    - Synchronized on probing, but not on later port update
>  
> -Example
> --------
> -
> -The following is a simple example of using the TAP PMD with the Pktgen
> -packet generator. It requires that the ``socat`` utility is installed on the
> -test system.
> -
> -Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
> -used to build the dpdk you pulled down.
> -
> -Run pktgen from the pktgen directory in a terminal with a commandline like the
> -following::
> -
> -    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
> -     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
> -     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
> -     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
> -     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
> -     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
> -     -f themes/black-yellow.theme
> -
> -.. Note:
> -
> -   Change the ``-b`` options to exclude all of your physical ports. The
> -   following command line is all one line.
> -
> -   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
> -   work on your system configuration. See the Pktgen docs for more
> -   information.
> -
> -Verify with ``ifconfig -a`` command in a different xterm window, should have a
> -``dtap0`` and ``dtap1`` interfaces created.
> -
> -Next set the links for the two interfaces to up via the commands below::
> -
> -    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
> -    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
> -
> -Then use socat to create a loopback for the two interfaces::
> -
> -    sudo socat interface:dtap0 interface:dtap1
> -
> -Then on the Pktgen command line interface you can start sending packets using
> -the commands ``start 0`` and ``start 1`` or you can start both at the same
> -time with ``start all``. The command ``str`` is an alias for ``start all`` and
> -``stp`` is an alias for ``stop all``.
> -
> -While running you should see the 64 byte counters increasing to verify the
> -traffic is being looped back. You can use ``set all size XXX`` to change the
> -size of the packets after you stop the traffic. Use pktgen ``help``
> -command to see a list of all commands. You can also use the ``-f`` option to
> -load commands at startup in command line or Lua script in pktgen.
>  
>  RSS specifics
>  -------------
> -Packet distribution in TAP is done by the kernel which has a default
> -distribution. This feature is adding RSS distribution based on eBPF code.
> -The default eBPF code calculates RSS hash based on Toeplitz algorithm for
> -a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
> -is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
> -respectively) and src/dst TCP/UDP ports (4 bytes).
> -
> -The RSS algorithm is written in file ``tap_bpf_program.c`` which
> -does not take part in TAP PMD compilation. Instead this file is compiled
> -in advance to eBPF object file. The eBPF object file is then parsed and
> -translated into eBPF byte code in the format of C arrays of eBPF
> -instructions. The C array of eBPF instructions is part of TAP PMD tree and
> -is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
> -the kernel via BPF system calls and the RSS hash is calculated by the
> -kernel.
> -
> -It is possible to support different RSS hash algorithms by updating file
> -``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
> -steps:
> -
> -#. Write the new RSS implementation in file ``tap_bpf_program.c``
> -
> -   BPF programs which are uploaded to the kernel correspond to
> -   C functions under different ELF sections.
> -
> -#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
> -
> -#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
> -   and extract the resulting instructions into ``tap_bpf_insn.h``::
> -
> -    cd bpf; make
> -
> -#. Recompile the TAP PMD.
> -
> -The C arrays are uploaded to the kernel using BPF system calls.
> -
> -``tc`` (traffic control) is a well known user space utility program used to
> -configure the Linux kernel packet scheduler. It is usually packaged as
> -part of the ``iproute2`` package.
> -Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
> -to uploads eBPF code to the kernel and can be patched in order to print the
> -C arrays of eBPF instructions just before calling the BPF system call.
> -Please refer to ``iproute2`` package file ``lib/bpf.c`` function
> -``bpf_prog_load()``.
> -
> -An example utility for eBPF instruction generation in the format of C arrays will
> -be added in next releases
> -
> -TAP reports on supported RSS functions as part of dev_infos_get callback:
> -``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
> -**Known limitation:** TAP supports all of the above hash functions together
> -and not in partial combinations.
> -
> -Systems supporting flow API
> ----------------------------
> -
> -- "tc flower" classifier requires linux kernel above 4.2
> -- eBPF/RSS requires linux kernel above 4.9
> -
> -+--------------------+-----------------------+
> -| RH7.3              | No flow rule support  |
> -+--------------------+-----------------------+
> -| RH7.4              | No RSS action support |
> -+--------------------+-----------------------+
> -| RH7.5              | No RSS action support |
> -+--------------------+-----------------------+
> -| SLES 15,           | No limitation         |
> -| kernel 4.12        |                       |
> -+--------------------+-----------------------+
> -| Azure Ubuntu 16.04,| No limitation         |
> -| kernel 4.13        |                       |
> -+--------------------+-----------------------+
> +The default packet distribution in TAP without flow rules is done by the
> +kernel which has a default flow based distribution.
> +When flow rules are used to distribute packets across a set of queues
> +an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
> +with the given key.
> +
> +The hash is calculated for IPv4 and IPv6, over src/dst addresses
> +(8 or 32 bytes for IPv4 or IPv6 respectively) and
> +optionally the src/dst TCP/UDP ports (4 bytes).
> +
>  
>  Limitations
>  -----------
>  
> -* Rx/Tx must have the same number of queues.
> +- Since TAP device uses a file descriptors to talk to the kernel.
> +  The same number of queues must be specified for receive and transmit.
> +
> +- The RSS algorithm only support L3 or L4 functions. It does not support
> +  finer grain selections (for example: only IPV6 packets with extension headers).

Section headers in the document seems mixed up, it is currently as
following, I don't think this was the intention:

TAP
    Requirements
        Arguments
        TUN devices
        Flow API support
    Requirements
    Examples of testpmd flow rules
        Multi-process sharing
        RSS specifics
        Limitations

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] net/tap: fix RSS (BPF) support
  2024-05-01 11:18   ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Ferruh Yigit
@ 2024-05-01 15:41     ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 15:41 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Wed, 1 May 2024 12:18:16 +0100
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> Thanks for reviving tap eBPF support, I am for merging this set (as
> early as possible).
> 
> But I have two concerns,
> 1. Build environment header file dependencies and external library
> dependency version changed. Not sure if this will impact users.
> What do you think at least to update release notes to notify users?

Added a short note in release notes. 

> 
> 2. We need this to be tested, either by users or test teams. I will
> bring the issue in next release status meeting to see if we have anyone
> testing tap eBPF support.

Agreed. I ended up doing lots of manual tests. That is how it was
discovered that > 1 flow rule never worked with TAP.

There is a bigger issue here. There is no basic test suite for
PMD's. I see lots of differences creeping in with statistics etc.

And there is no test suite for rte_flow. Lots of untested code paths
and driver differences.  Testing actual flows is hard, but basic
functional tests should be possible. Like:
   - try all possible flow rules and actions
   - make sure that any supported flow rule accepts a valid parameter.
     and for those supported flow rules pass invalid data (like queue > nrx queue).
   - make sure validate and create work the same.
   - make sure that validate doesn't actually create state in hw/sw.
     should be possible to validate same rule 10,000 times without leaks blowing up.


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (9 preceding siblings ...)
  2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
@ 2024-05-01 16:11 ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 1/9] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (8 more replies)
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
  12 siblings, 9 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:11 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain. I do not
intend to support backporting this to stable releases due
to lack of demand and dealing with older distros.

v10 - add some cleanups to stats and name sizes
    - update documentation from review

Stephen Hemminger (9):
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  net/tap: simplify internals
  net/tap: update documentation

 .gitignore                             |    3 -
 doc/guides/nics/tap.rst                |  274 ++--
 doc/guides/rel_notes/release_24_07.rst |    7 +
 drivers/net/tap/bpf/Makefile           |   19 -
 drivers/net/tap/bpf/README             |   49 +
 drivers/net/tap/bpf/bpf_api.h          |  276 ----
 drivers/net/tap/bpf/bpf_elf.h          |   53 -
 drivers/net/tap/bpf/bpf_extract.py     |   86 --
 drivers/net/tap/bpf/meson.build        |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c  |  255 ----
 drivers/net/tap/bpf/tap_rss.c          |  267 ++++
 drivers/net/tap/meson.build            |   42 +-
 drivers/net/tap/rte_eth_tap.c          |  339 ++---
 drivers/net/tap/rte_eth_tap.h          |   32 +-
 drivers/net/tap/tap_bpf.h              |  121 --
 drivers/net/tap/tap_bpf_api.c          |  190 ---
 drivers/net/tap/tap_bpf_insns.h        | 1743 ------------------------
 drivers/net/tap/tap_flow.c             |  559 ++------
 drivers/net/tap/tap_flow.h             |   17 +-
 drivers/net/tap/tap_intr.c             |    7 +-
 drivers/net/tap/tap_rss.h              |   21 +-
 drivers/net/tap/tap_tcmsgs.h           |    4 +-
 22 files changed, 887 insertions(+), 3584 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v10 1/9] net/tap: do not duplicate fd's
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 2/9] net/tap: remove unused fields Stephen Hemminger
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptor for both rx and tx queues.
This allows up to 8 queues (versus 4) to be used with secondary process.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 197 +++++++++++++++-------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 4 files changed, 91 insertions(+), 119 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..38a1b2d825 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1121,7 +1113,6 @@ tap_dev_close(struct rte_eth_dev *dev)
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1132,18 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		if (process_private->fds[i] == -1)
+			continue;
+
+		close(process_private->fds[i]);
+		process_private->fds[i] = -1;
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1198,6 +1188,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static void
 tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 {
@@ -1206,15 +1205,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1225,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1480,34 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = NULL;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
+	if (is_rx)
 		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1520,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1600,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1644,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1981,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2311,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2330,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2370,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 2/9] net/tap: remove unused fields
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 1/9] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 3/9] net/tap: validate and setup parameters for BPF RSS
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 1/9] net/tap: do not duplicate fd's Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 2/9] net/tap: remove unused fields Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 4/9] net/tap: do not build flow support if header is out of date
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..66647a1c62 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=16'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..3f4fe95a09 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1124,12 +1124,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1265,6 +1268,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1278,7 +1282,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1293,6 +1297,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1306,6 +1311,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1321,6 +1327,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1334,6 +1341,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1349,6 +1357,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1362,6 +1371,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1407,6 +1417,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1424,6 +1436,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1901,7 +1914,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1941,7 +1956,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2021,6 +2038,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2035,11 +2060,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2050,6 +2070,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2102,6 +2123,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2116,14 +2138,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index d8437927ef..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union __rte_aligned(8) bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-};
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 5/9] net/tap: rewrite the RSS BPF program
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 6/9] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite of the BPF program used to do queue based RSS.

Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF code.
	- the resulting queue is placed in skb by using skb mark
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  49 +++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 264 ++++++++++++++++++++++++
 9 files changed, 394 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..181f76a134
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,49 @@
+This is the BPF program used to implement Receive Side Scaling (RSS)
+across mulitple queues if required by a flow action. The program is
+loaded into the krnel when first RSS flow rule is created and is never unloaded.
+
+When flow rules with the TAP device, packets are first handled by the
+ingress queue discipline that then runs a series of classifier filter rules.
+The first stage is the flow based classifier (flower); for RSS queue
+action the second stage is an the kernel skbedit action which sets
+the skb mark to a key based on the flow id; the final stage
+is this BPF program which then maps flow id and packet header
+into a queue id.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+
+- rebuilding the BPF requires the clang compiler with bpf available
+  as a targe architecture and bpftool to convert object to headers.
+
+  Some older versions of Ubuntu do not have a working bpftool package.
+
+- only standard Toeplitz hash with standard 40 byte key is supported.
+
+- the number of flow rules using RSS is limited to 32.
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are available. If everything works then
+BPF RSS is enabled.
+
+The steps are:
+
+1. Usws clang to compile tap_rss.c to produce tap_rss.bpf.o
+
+2. Uses bpftool generate a skeleton header file tap_rss.skel.h
+   from tap_rss.bpf.o. This header contains wrapper functions for
+   managing the BPF and the actual BPF code as a large byte array.
+
+3. The header file is include in tap_flow.c so that it can load
+   the BPF code (via libbpf).
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..888b3bdc24
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __u32 __attribute__((always_inline))
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static int __attribute__((always_inline))
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __u32 __attribute__((always_inline))
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Compute RSS hash for packets.
+ * Returns 0 if no hash is possible.
+ */
+static __u32 __attribute__((always_inline))
+calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
+{
+	const __u32 *key = (const __u32 *)rsskey->key;
+
+	if (skb->protocol == bpf_htons(ETH_P_IP))
+		return parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
+		return parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __u32  __attribute__((always_inline))
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	__u32 mark = skb->mark;
+	__u32 hash;
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	hash = calculate_rss_hash(skb, rsskey);
+	if (!hash)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 6/9] net/tap: use libbpf to load new BPF program
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 7/9] net/tap: remove no longer used files Stephen Hemminger
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  36 ++-
 drivers/net/tap/bpf/tap_rss.c   |  45 ++--
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 418 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 9 files changed, 189 insertions(+), 396 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..45e8c3b498 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -1,17 +1,26 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
 
-enable_tap_rss = false
-
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu versions have non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
index 888b3bdc24..1d71941c53 100644
--- a/drivers/net/tap/bpf/tap_rss.c
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -203,23 +203,6 @@ parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
 	return 0;
 }
 
-/*
- * Compute RSS hash for packets.
- * Returns 0 if no hash is possible.
- */
-static __u32 __attribute__((always_inline))
-calculate_rss_hash(const struct __sk_buff *skb, const struct rss_key *rsskey)
-{
-	const __u32 *key = (const __u32 *)rsskey->key;
-
-	if (skb->protocol == bpf_htons(ETH_P_IP))
-		return parse_ipv4(skb, rsskey->hash_fields, key);
-	else if (skb->protocol == bpf_htons(ETH_P_IPV6))
-		return parse_ipv6(skb, rsskey->hash_fields, key);
-	else
-		return 0;
-}
-
 /*
  * Scale value to be into range [0, n)
  * Assumes val is large (ie hash covers whole u32 range)
@@ -244,20 +227,40 @@ SEC("action") int
 rss_flow_action(struct __sk_buff *skb)
 {
 	const struct rss_key *rsskey;
-	__u32 mark = skb->mark;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
 	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
 
 	/* Lookup RSS configuration for that BPF class */
 	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
 	if (rsskey == NULL)
 		return TC_ACT_OK;
 
-	hash = calculate_rss_hash(skb, rsskey);
-	if (!hash)
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
 		return TC_ACT_OK;
 
 	/* Fold hash to the number of queues configured */
-	skb->queue_mapping = reciprocal_scale(hash, rsskey->nb_queues);
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
 	return TC_ACT_PIPE;
 }
 
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 66647a1c62..26074059fa 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,33 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
-
-deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+    enable_tap_rss = false
 
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 3f4fe95a09..793730de08 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1131,6 +1131,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1956,6 +1957,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2038,13 +2040,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2060,6 +2055,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..322153d806 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,12 +61,16 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
+#ifdef HAVE_BPF_RSS
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
+#endif
 	};
 };
 
@@ -112,13 +108,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,11 +848,14 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
-	} else if (strcmp("bpf", adata->id) == 0) {
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
+	}
+#ifdef HAVE_BPF_RSS
+	else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
@@ -865,7 +863,9 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
-	} else {
+	}
+#endif
+	else {
 		return -1;
 	}
 	tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
@@ -1104,8 +1104,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1134,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1143,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1247,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1725,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1751,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-	}
-
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1809,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1862,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1888,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..9411626661 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,10 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
+#ifdef HAVE_BPF_RSS
 #include <linux/tc_act/tc_bpf.h>
 #endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 7/9] net/tap: remove no longer used files
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 6/9] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 8/9] net/tap: simplify internals Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 9/9] net/tap: update documentation Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 8/9] net/tap: simplify internals
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 7/9] net/tap: remove no longer used files Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  2024-05-01 16:12   ` [PATCH v10 9/9] net/tap: update documentation Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The names of Linux network devices are IFNAMSIZ(16) not the
same as DPDK which has up to 64 characters. Don't need to
hold onto the whole ifreq to save the remote interface flags.

Make sure packet and byte counters are read once, so that global
and per-queue values add up. No need for seperate rx_nombuf counter
since there is an alloc_failed value in ethdev.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 114 +++++++++++++++++++---------------
 drivers/net/tap/rte_eth_tap.h |  12 ++--
 2 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 793730de08..dd9ecb391d 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -46,6 +46,11 @@
 #include <tap_netlink.h>
 #include <tap_tcmsgs.h>
 
+/* Used to snapshot statistics */
+#ifndef READ_ONCE
+#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
+#endif
+
 /* Linux based path to the TUN device */
 #define TUN_TAP_DEV_PATH        "/dev/net/tun"
 #define DEFAULT_TAP_NAME        "dtap"
@@ -212,7 +217,7 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 	 * and need to find the resulting device.
 	 */
 	TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name);
-	strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(pmd->name, ifr.ifr_name, IFNAMSIZ);
 
 	if (is_keepalive) {
 		/*
@@ -466,7 +471,8 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			struct rte_mbuf *buf = rte_pktmbuf_alloc(rxq->mp);
 
 			if (unlikely(!buf)) {
-				rxq->stats.rx_nombuf++;
+				rte_eth_devices[rxq->in_port].data->rx_mbuf_alloc_failed++;
+
 				/* No new buf has been allocated: do nothing */
 				if (!new_tail || !seg)
 					goto end;
@@ -1047,43 +1053,44 @@ tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 static int
 tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
 {
-	unsigned int i, imax;
-	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
-	unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
-	unsigned long rx_nombuf = 0, ierrors = 0;
+	unsigned int i;
 	const struct pmd_internals *pmd = dev->data->dev_private;
+	uint64_t bytes, packets;
 
 	/* rx queue statistics */
-	imax = (dev->data->nb_rx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_rx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
-		tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
-		rx_total += tap_stats->q_ipackets[i];
-		rx_bytes_total += tap_stats->q_ibytes[i];
-		rx_nombuf += pmd->rxq[i].stats.rx_nombuf;
-		ierrors += pmd->rxq[i].stats.ierrors;
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		const struct rx_queue *rxq = &pmd->rxq[i];
+
+		packets = READ_ONCE(rxq->stats.ipackets);
+		bytes = READ_ONCE(rxq->stats.ibytes);
+
+		tap_stats->ipackets += packets;
+		tap_stats->ibytes += bytes;
+		tap_stats->ierrors += rxq->stats.ierrors;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_ipackets[i] = packets;
+			tap_stats->q_ibytes[i] =  bytes;
+		}
 	}
 
 	/* tx queue statistics */
-	imax = (dev->data->nb_tx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_tx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
-		tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
-		tx_total += tap_stats->q_opackets[i];
-		tx_err_total += pmd->txq[i].stats.errs;
-		tx_bytes_total += tap_stats->q_obytes[i];
-	}
-
-	tap_stats->ipackets = rx_total;
-	tap_stats->ibytes = rx_bytes_total;
-	tap_stats->ierrors = ierrors;
-	tap_stats->rx_nombuf = rx_nombuf;
-	tap_stats->opackets = tx_total;
-	tap_stats->oerrors = tx_err_total;
-	tap_stats->obytes = tx_bytes_total;
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		const struct tx_queue *txq = &pmd->txq[i];
+
+		packets = READ_ONCE(txq->stats.opackets);
+		bytes = READ_ONCE(txq->stats.obytes);
+
+		tap_stats->opackets += packets;
+		tap_stats->obytes += bytes;
+		tap_stats->oerrors += txq->stats.errs;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_opackets[i] = packets;
+			tap_stats->q_obytes[i] = bytes;
+		}
+	}
+
 	return 0;
 }
 
@@ -1097,7 +1104,6 @@ tap_stats_reset(struct rte_eth_dev *dev)
 		pmd->rxq[i].stats.ipackets = 0;
 		pmd->rxq[i].stats.ibytes = 0;
 		pmd->rxq[i].stats.ierrors = 0;
-		pmd->rxq[i].stats.rx_nombuf = 0;
 
 		pmd->txq[i].stats.opackets = 0;
 		pmd->txq[i].stats.errs = 0;
@@ -1151,9 +1157,13 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	if (internals->remote_if_index) {
+		struct ifreq remote_ifr;
+
+		strlcpy(remote_ifr.ifr_name, internals->remote_iface, IFNAMSIZ);
+		remote_ifr.ifr_flags = internals->remote_flags;
+
 		/* Restore initial remote state */
-		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS,
-				&internals->remote_initial_flags);
+		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS, &remote_ifr);
 		if (ret)
 			TAP_LOG(ERR, "restore remote state failed: %d", ret);
 
@@ -2074,16 +2084,22 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
+		struct ifreq remote_ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index) {
 			TAP_LOG(ERR, "%s: failed to get %s if_index.",
 				pmd->name, remote_iface);
 			goto error_remote;
 		}
-		strlcpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(pmd->remote_iface, remote_iface, IFNAMSIZ);
+
+		memset(&remote_ifr, 0, sizeof(ifr));
+		strlcpy(remote_ifr.ifr_name, remote_iface, IFNAMSIZ);
 
 		/* Save state of remote device */
-		tap_ioctl(pmd, SIOCGIFFLAGS, &pmd->remote_initial_flags, 0, REMOTE_ONLY);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &remote_ifr, 0, REMOTE_ONLY);
+		pmd->remote_flags = remote_ifr.ifr_flags;
 
 		/* Replicate remote MAC address */
 		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
@@ -2197,10 +2213,10 @@ set_interface_name(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	} else {
 		/* use tap%d which causes kernel to choose next available */
-		strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
 	}
 	return 0;
 }
@@ -2218,7 +2234,7 @@ set_remote_iface(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	}
 
 	return 0;
@@ -2269,13 +2285,13 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	const char *name, *params;
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
-	char tun_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tun_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_eth_dev *eth_dev;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
 	    strlen(params) == 0) {
@@ -2291,7 +2307,7 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	}
 
 	/* use tun%d which causes kernel to choose next available */
-	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
@@ -2431,8 +2447,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
 	int speed;
-	char tap_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tap_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_ether_addr user_mac = { .addr_bytes = {0} };
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
@@ -2486,8 +2502,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	speed = RTE_ETH_SPEED_NUM_10G;
 
 	/* use tap%d which causes kernel to choose next available */
-	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index ce4322ad04..ca510e2c6b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -68,15 +68,16 @@ struct tx_queue {
 
 struct pmd_internals {
 	struct rte_eth_dev *dev;          /* Ethernet device. */
-	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
-	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
+	char remote_iface[IFNAMSIZ];	  /* Remote netdevice name */
+	char name[IFNAMSIZ];		  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
 	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
-	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
+	uint16_t remote_flags;		  /* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+	int ka_fd;                        /* keep-alive file descriptor */
 
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
@@ -88,12 +89,11 @@ struct pmd_internals {
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 #endif
+	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
+	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
-	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
-	int ka_fd;                        /* keep-alive file descriptor */
-	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
 
 struct pmd_process_private {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 9/9] net/tap: update documentation
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
                     ` (7 preceding siblings ...)
  2024-05-01 16:12   ` [PATCH v10 8/9] net/tap: simplify internals Stephen Hemminger
@ 2024-05-01 16:12   ` Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 16:12 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/nics/tap.rst                | 274 +++++++------------------
 doc/guides/rel_notes/release_24_07.rst |   7 +
 2 files changed, 84 insertions(+), 197 deletions(-)

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..55e38fb25b 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,51 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+Requirements
+~~~~~~~~~~~~
+
+The TAP PMD requires kernel support for multiple queues in TAP device as
+well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
+These are standard kernel features in most Linux distributions.
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN devices are created with the command line arguments ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux kernel support of flow based
+traffic control filter ``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +123,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
diff --git a/doc/guides/rel_notes/release_24_07.rst b/doc/guides/rel_notes/release_24_07.rst
index a69f24cf99..8652271ed2 100644
--- a/doc/guides/rel_notes/release_24_07.rst
+++ b/doc/guides/rel_notes/release_24_07.rst
@@ -55,6 +55,13 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **TAP PMD updates.**
+
+  * Fixed support of RSS flow action to work with current Linux
+    kernels and BPF tooling. Will only be enabled if clang and bpftool
+    are available.
+
+  * Support up to 8 queues when used by secondary process
 
 Removed Items
 -------------
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 1/9] net/tap: do not duplicate fd's
  2024-05-01 11:13     ` Ferruh Yigit
@ 2024-05-01 23:53       ` Stephen Hemminger
  2024-05-02 14:51         ` Ferruh Yigit
  0 siblings, 1 reply; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-01 23:53 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Wed, 1 May 2024 12:13:45 +0100
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> > diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
> > index fa50fe45d7..a78fd50cd4 100644
> > --- a/drivers/net/tap/tap_flow.c
> > +++ b/drivers/net/tap/tap_flow.c
> > @@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
> >  	 * If netdevice is there, setup appropriate flow rules immediately.
> >  	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
> >  	 */
> > -	if (!process_private->rxq_fds[0])
> > +	if (process_private->fds[0] == -1)
> >  
> 
> change in the condition looks reasonable but not directly related with
> the change, does it require its own patch?

In this case, the array of fds is moving from the rxq to being global.
The old code worked because rxq_fds[] was initialized to zero.
With shared fd's the fds are now initialized to -1.

Using zero as sentinel fd is bad practice, because it is a valid fd;
but POSIX says it always is stdin.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v11 0/9] net/tap fix RSS (BPF) flow support
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (10 preceding siblings ...)
  2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
@ 2024-05-02  2:49 ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 1/9] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (8 more replies)
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
  12 siblings, 9 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF toolchain.

The result should be easier to read and maintain. I do not
intend to support backporting this to stable releases due
to lack of demand and dealing with older distros.

v11 - checkpatch and review comments
      add bugzilla id's

Stephen Hemminger (9):
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  net/tap: simplify internals
  net/tap: update documentation

 .gitignore                             |    3 -
 doc/guides/nics/tap.rst                |  274 ++--
 doc/guides/rel_notes/release_24_07.rst |    7 +
 drivers/net/tap/bpf/Makefile           |   19 -
 drivers/net/tap/bpf/README             |   49 +
 drivers/net/tap/bpf/bpf_api.h          |  276 ----
 drivers/net/tap/bpf/bpf_elf.h          |   53 -
 drivers/net/tap/bpf/bpf_extract.py     |   86 --
 drivers/net/tap/bpf/meson.build        |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c  |  255 ----
 drivers/net/tap/bpf/tap_rss.c          |  267 ++++
 drivers/net/tap/meson.build            |   42 +-
 drivers/net/tap/rte_eth_tap.c          |  334 ++---
 drivers/net/tap/rte_eth_tap.h          |   32 +-
 drivers/net/tap/tap_bpf.h              |  121 --
 drivers/net/tap/tap_bpf_api.c          |  190 ---
 drivers/net/tap/tap_bpf_insns.h        | 1743 ------------------------
 drivers/net/tap/tap_flow.c             |  557 ++------
 drivers/net/tap/tap_flow.h             |   17 +-
 drivers/net/tap/tap_intr.c             |    7 +-
 drivers/net/tap/tap_rss.h              |   21 +-
 drivers/net/tap/tap_tcmsgs.h           |    4 +-
 22 files changed, 881 insertions(+), 3583 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v11 1/9] net/tap: do not duplicate fd's
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 2/9] net/tap: remove unused fields Stephen Hemminger
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptor for both rx and tx queues.
This allows up to 8 queues (versus 4) to be used with secondary process.

Bugzilla ID: 1381
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 192 ++++++++++++++--------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 4 files changed, 85 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..b84fc01856 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1115,13 +1107,21 @@ tap_stats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static int
 tap_dev_close(struct rte_eth_dev *dev)
 {
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1141,14 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		tap_queue_close(process_private, i);
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1206,15 +1201,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1221,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1476,31 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = is_rx ? NULL : &tx->gso_ctx;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
-		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1513,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1593,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1637,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1974,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2304,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2323,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2363,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 2/9] net/tap: remove unused fields
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 1/9] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 3/9] net/tap: validate and setup parameters for BPF RSS
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 1/9] net/tap: do not duplicate fd's Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 2/9] net/tap: remove unused fields Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 4/9] net/tap: do not build flow support if header is out of date
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..66647a1c62 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=16'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b84fc01856..9058a47295 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1133,12 +1133,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1261,6 +1264,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1274,7 +1278,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1289,6 +1293,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1302,6 +1307,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1317,6 +1323,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1330,6 +1337,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1345,6 +1353,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1358,6 +1367,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1403,6 +1413,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1420,6 +1432,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1894,7 +1907,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1934,7 +1949,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2014,6 +2031,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2028,11 +2053,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2043,6 +2063,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2095,6 +2116,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2109,14 +2131,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index d8437927ef..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union __rte_aligned(8) bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-};
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 5/9] net/tap: rewrite the RSS BPF program
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 6/9] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite of the BPF program used to do queue based RSS.

Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF code.
	- the resulting queue is placed in skb by using skb mark
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  49 +++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 267 +++++++++++++++++++++++++
 9 files changed, 397 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..6d323d2051
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,49 @@
+This is the BPF program used to implement Receive Side Scaling (RSS)
+across multiple queues if required by a flow action. The program is
+loaded into the kernel when first RSS flow rule is created and is never unloaded.
+
+When flow rules with the TAP device, packets are first handled by the
+ingress queue discipline that then runs a series of classifier filter rules.
+The first stage is the flow based classifier (flower); for RSS queue
+action the second stage is an the kernel skbedit action which sets
+the skb mark to a key based on the flow id; the final stage
+is this BPF program which then maps flow id and packet header
+into a queue id.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+
+- rebuilding the BPF requires the clang compiler with bpf available
+  as a target architecture and bpftool to convert object to headers.
+
+  Some older versions of Ubuntu do not have a working bpftool package.
+
+- only standard Toeplitz hash with standard 40 byte key is supported.
+
+- the number of flow rules using RSS is limited to 32.
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are available. If everything works then
+BPF RSS is enabled.
+
+The steps are:
+
+1. Uses clang to compile tap_rss.c to produce tap_rss.bpf.o
+
+2. Uses bpftool generate a skeleton header file tap_rss.skel.h
+   from tap_rss.bpf.o. This header contains wrapper functions for
+   managing the BPF and the actual BPF code as a large byte array.
+
+3. The header file is include in tap_flow.c so that it can load
+   the BPF code (via libbpf).
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..025b831b5c
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __always_inline __u32
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __always_inline __u32
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static __always_inline int
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __always_inline __u32
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __always_inline __u32
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
+	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 6/9] net/tap: use libbpf to load new BPF program
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 7/9] net/tap: remove no longer used files Stephen Hemminger
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Bugzilla ID: 1329

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  36 ++-
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 416 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 8 files changed, 165 insertions(+), 373 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..45e8c3b498 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -1,17 +1,26 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
 
-enable_tap_rss = false
-
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu versions have non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 66647a1c62..26074059fa 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,33 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
-
-deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+    enable_tap_rss = false
 
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 9058a47295..d847565073 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1140,6 +1140,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1949,6 +1950,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2031,13 +2033,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2053,6 +2048,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..679cffe528 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,12 +61,16 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
+#ifdef HAVE_BPF_RSS
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
+#endif
 	};
 };
 
@@ -112,13 +108,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,11 +848,13 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
+#ifdef HAVE_BPF_RSS
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
@@ -865,7 +862,12 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+#else
+		TAP_LOG(ERR, "Internal error: bpf requested but not supported");
+		return -1;
+#endif
 	} else {
+		TAP_LOG(ERR, "Internal error: unknown action: %s", adata->id);
 		return -1;
 	}
 	tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
@@ -1104,8 +1106,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1136,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1145,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1249,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1727,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1753,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
-
-		return -ENOTSUP;
-	}
-
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
+	int err;
 
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1811,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1864,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1890,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..9411626661 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,10 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
+#ifdef HAVE_BPF_RSS
 #include <linux/tc_act/tc_bpf.h>
 #endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 7/9] net/tap: remove no longer used files
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 6/9] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 8/9] net/tap: simplify internals Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 9/9] net/tap: update documentation Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 8/9] net/tap: simplify internals
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 7/9] net/tap: remove no longer used files Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  2024-05-02  2:49   ` [PATCH v11 9/9] net/tap: update documentation Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The names of Linux network devices are IFNAMSIZ(16) not the
same as DPDK which has up to 64 characters. Don't need to
hold onto the whole ifreq to save the remote interface flags.

Make sure packet and byte counters are read once, so that global
and per-queue values add up. No need for separate rx_nombuf counter
since there is an alloc_failed value in ethdev.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 114 +++++++++++++++++++---------------
 drivers/net/tap/rte_eth_tap.h |  12 ++--
 2 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index d847565073..2af6b763e6 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -46,6 +46,11 @@
 #include <tap_netlink.h>
 #include <tap_tcmsgs.h>
 
+/* Used to snapshot statistics */
+#ifndef READ_ONCE
+#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
+#endif
+
 /* Linux based path to the TUN device */
 #define TUN_TAP_DEV_PATH        "/dev/net/tun"
 #define DEFAULT_TAP_NAME        "dtap"
@@ -212,7 +217,7 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 	 * and need to find the resulting device.
 	 */
 	TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name);
-	strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(pmd->name, ifr.ifr_name, IFNAMSIZ);
 
 	if (is_keepalive) {
 		/*
@@ -466,7 +471,8 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			struct rte_mbuf *buf = rte_pktmbuf_alloc(rxq->mp);
 
 			if (unlikely(!buf)) {
-				rxq->stats.rx_nombuf++;
+				rte_eth_devices[rxq->in_port].data->rx_mbuf_alloc_failed++;
+
 				/* No new buf has been allocated: do nothing */
 				if (!new_tail || !seg)
 					goto end;
@@ -1047,43 +1053,44 @@ tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 static int
 tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
 {
-	unsigned int i, imax;
-	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
-	unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
-	unsigned long rx_nombuf = 0, ierrors = 0;
+	unsigned int i;
 	const struct pmd_internals *pmd = dev->data->dev_private;
+	uint64_t bytes, packets;
 
 	/* rx queue statistics */
-	imax = (dev->data->nb_rx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_rx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
-		tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
-		rx_total += tap_stats->q_ipackets[i];
-		rx_bytes_total += tap_stats->q_ibytes[i];
-		rx_nombuf += pmd->rxq[i].stats.rx_nombuf;
-		ierrors += pmd->rxq[i].stats.ierrors;
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		const struct rx_queue *rxq = &pmd->rxq[i];
+
+		packets = READ_ONCE(rxq->stats.ipackets);
+		bytes = READ_ONCE(rxq->stats.ibytes);
+
+		tap_stats->ipackets += packets;
+		tap_stats->ibytes += bytes;
+		tap_stats->ierrors += rxq->stats.ierrors;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_ipackets[i] = packets;
+			tap_stats->q_ibytes[i] =  bytes;
+		}
 	}
 
 	/* tx queue statistics */
-	imax = (dev->data->nb_tx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_tx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
-		tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
-		tx_total += tap_stats->q_opackets[i];
-		tx_err_total += pmd->txq[i].stats.errs;
-		tx_bytes_total += tap_stats->q_obytes[i];
-	}
-
-	tap_stats->ipackets = rx_total;
-	tap_stats->ibytes = rx_bytes_total;
-	tap_stats->ierrors = ierrors;
-	tap_stats->rx_nombuf = rx_nombuf;
-	tap_stats->opackets = tx_total;
-	tap_stats->oerrors = tx_err_total;
-	tap_stats->obytes = tx_bytes_total;
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		const struct tx_queue *txq = &pmd->txq[i];
+
+		packets = READ_ONCE(txq->stats.opackets);
+		bytes = READ_ONCE(txq->stats.obytes);
+
+		tap_stats->opackets += packets;
+		tap_stats->obytes += bytes;
+		tap_stats->oerrors += txq->stats.errs;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_opackets[i] = packets;
+			tap_stats->q_obytes[i] = bytes;
+		}
+	}
+
 	return 0;
 }
 
@@ -1097,7 +1104,6 @@ tap_stats_reset(struct rte_eth_dev *dev)
 		pmd->rxq[i].stats.ipackets = 0;
 		pmd->rxq[i].stats.ibytes = 0;
 		pmd->rxq[i].stats.ierrors = 0;
-		pmd->rxq[i].stats.rx_nombuf = 0;
 
 		pmd->txq[i].stats.opackets = 0;
 		pmd->txq[i].stats.errs = 0;
@@ -1156,9 +1162,13 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	if (internals->remote_if_index) {
+		struct ifreq remote_ifr;
+
+		strlcpy(remote_ifr.ifr_name, internals->remote_iface, IFNAMSIZ);
+		remote_ifr.ifr_flags = internals->remote_flags;
+
 		/* Restore initial remote state */
-		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS,
-				&internals->remote_initial_flags);
+		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS, &remote_ifr);
 		if (ret)
 			TAP_LOG(ERR, "restore remote state failed: %d", ret);
 
@@ -2067,16 +2077,22 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
+		struct ifreq remote_ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index) {
 			TAP_LOG(ERR, "%s: failed to get %s if_index.",
 				pmd->name, remote_iface);
 			goto error_remote;
 		}
-		strlcpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(pmd->remote_iface, remote_iface, IFNAMSIZ);
+
+		memset(&remote_ifr, 0, sizeof(ifr));
+		strlcpy(remote_ifr.ifr_name, remote_iface, IFNAMSIZ);
 
 		/* Save state of remote device */
-		tap_ioctl(pmd, SIOCGIFFLAGS, &pmd->remote_initial_flags, 0, REMOTE_ONLY);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &remote_ifr, 0, REMOTE_ONLY);
+		pmd->remote_flags = remote_ifr.ifr_flags;
 
 		/* Replicate remote MAC address */
 		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
@@ -2190,10 +2206,10 @@ set_interface_name(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	} else {
 		/* use tap%d which causes kernel to choose next available */
-		strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
 	}
 	return 0;
 }
@@ -2211,7 +2227,7 @@ set_remote_iface(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	}
 
 	return 0;
@@ -2262,13 +2278,13 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	const char *name, *params;
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
-	char tun_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tun_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_eth_dev *eth_dev;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
 	    strlen(params) == 0) {
@@ -2284,7 +2300,7 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	}
 
 	/* use tun%d which causes kernel to choose next available */
-	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
@@ -2424,8 +2440,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
 	int speed;
-	char tap_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tap_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_ether_addr user_mac = { .addr_bytes = {0} };
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
@@ -2479,8 +2495,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	speed = RTE_ETH_SPEED_NUM_10G;
 
 	/* use tap%d which causes kernel to choose next available */
-	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index ce4322ad04..ca510e2c6b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -68,15 +68,16 @@ struct tx_queue {
 
 struct pmd_internals {
 	struct rte_eth_dev *dev;          /* Ethernet device. */
-	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
-	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
+	char remote_iface[IFNAMSIZ];	  /* Remote netdevice name */
+	char name[IFNAMSIZ];		  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
 	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
-	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
+	uint16_t remote_flags;		  /* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+	int ka_fd;                        /* keep-alive file descriptor */
 
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
@@ -88,12 +89,11 @@ struct pmd_internals {
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 #endif
+	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
+	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
-	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
-	int ka_fd;                        /* keep-alive file descriptor */
-	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
 
 struct pmd_process_private {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 9/9] net/tap: update documentation
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
                     ` (7 preceding siblings ...)
  2024-05-02  2:49   ` [PATCH v11 8/9] net/tap: simplify internals Stephen Hemminger
@ 2024-05-02  2:49   ` Stephen Hemminger
  8 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02  2:49 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/nics/tap.rst                | 274 +++++++------------------
 doc/guides/rel_notes/release_24_07.rst |   7 +
 2 files changed, 84 insertions(+), 197 deletions(-)

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..55e38fb25b 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,51 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+Requirements
+~~~~~~~~~~~~
+
+The TAP PMD requires kernel support for multiple queues in TAP device as
+well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
+These are standard kernel features in most Linux distributions.
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN devices are created with the command line arguments ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux kernel support of flow based
+traffic control filter ``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +123,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
diff --git a/doc/guides/rel_notes/release_24_07.rst b/doc/guides/rel_notes/release_24_07.rst
index a69f24cf99..8652271ed2 100644
--- a/doc/guides/rel_notes/release_24_07.rst
+++ b/doc/guides/rel_notes/release_24_07.rst
@@ -55,6 +55,13 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **TAP PMD updates.**
+
+  * Fixed support of RSS flow action to work with current Linux
+    kernels and BPF tooling. Will only be enabled if clang and bpftool
+    are available.
+
+  * Support up to 8 queues when used by secondary process
 
 Removed Items
 -------------
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 1/9] net/tap: do not duplicate fd's
  2024-05-01 23:53       ` Stephen Hemminger
@ 2024-05-02 14:51         ` Ferruh Yigit
  2024-05-02 16:22           ` Stephen Hemminger
  0 siblings, 1 reply; 133+ messages in thread
From: Ferruh Yigit @ 2024-05-02 14:51 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On 5/2/2024 12:53 AM, Stephen Hemminger wrote:
> On Wed, 1 May 2024 12:13:45 +0100
> Ferruh Yigit <ferruh.yigit@amd.com> wrote:
> 
>>> diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
>>> index fa50fe45d7..a78fd50cd4 100644
>>> --- a/drivers/net/tap/tap_flow.c
>>> +++ b/drivers/net/tap/tap_flow.c
>>> @@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
>>>  	 * If netdevice is there, setup appropriate flow rules immediately.
>>>  	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
>>>  	 */
>>> -	if (!process_private->rxq_fds[0])
>>> +	if (process_private->fds[0] == -1)
>>>  
>>
>> change in the condition looks reasonable but not directly related with
>> the change, does it require its own patch?
> 
> In this case, the array of fds is moving from the rxq to being global.
> The old code worked because rxq_fds[] was initialized to zero.
> With shared fd's the fds are now initialized to -1.
> 
> Using zero as sentinel fd is bad practice, because it is a valid fd;
> but POSIX says it always is stdin.
>

I agree on the fix, only I don't think it belongs to this patch.

As far as I can see 'rxq_fds' was already initialized to '-1' and
original code was already wrong.

This patch merges 'rxq_fds' & 'txq_fds' to 'fds', but this patch doesn't
do anything that requires updating the above condition, or if I missing
it please show me.

I think better to fix condition first in a separate patch.


^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 1/9] net/tap: do not duplicate fd's
  2024-05-02 14:51         ` Ferruh Yigit
@ 2024-05-02 16:22           ` Stephen Hemminger
  0 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 16:22 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Thu, 2 May 2024 15:51:43 +0100
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> I agree on the fix, only I don't think it belongs to this patch.
> 
> As far as I can see 'rxq_fds' was already initialized to '-1' and
> original code was already wrong.
> 
> This patch merges 'rxq_fds' & 'txq_fds' to 'fds', but this patch doesn't
> do anything that requires updating the above condition, or if I missing
> it please show me.
> 
> I think better to fix condition first in a separate patch.

Your right rxq_fds was not checked correctly in original code.
Let me split out that one.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v12 00/12] net/tap: RSS and other fixes
  2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
                   ` (11 preceding siblings ...)
  2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
@ 2024-05-02 21:31 ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 01/12] net/tap: fix fd check in flow_isolate Stephen Hemminger
                     ` (11 more replies)
  12 siblings, 12 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The support of doing RSS for rte_flow_action was a cool idea
but it has been broken for several releases of DPDK as the
kernel and BPF infrastructure changed.

This series cleans up the BPF program, implements several
features that were never completed in the original code
and changes to use the current BPF tool chain.

The result should be easier to read and maintain. I do not
intend to support backporting this to stable releases due
to lack of demand and dealing with older distros.

v12 - separate out the fix for rxq fd in flow_isolate
      cleanup log messages
      bug fix for queue full

Stephen Hemminger (12):
  net/tap: fix fd check in flow_isolate
  net/tap: do not duplicate fd's
  net/tap: remove unused fields
  net/tap: validate and setup parameters for BPF RSS
  net/tap: do not build flow support if header is out of date
  net/tap: rewrite the RSS BPF program
  net/tap: use libbpf to load new BPF program
  net/tap: remove no longer used files
  net/tap: simplify internals
  net/tap: remove extraneous newlines
  net/tap: do not mark queue full as error
  net/tap: update documentation

 .gitignore                             |    3 -
 doc/guides/nics/tap.rst                |  274 ++--
 doc/guides/rel_notes/release_24_07.rst |    7 +
 drivers/net/tap/bpf/Makefile           |   19 -
 drivers/net/tap/bpf/README             |   49 +
 drivers/net/tap/bpf/bpf_api.h          |  276 ----
 drivers/net/tap/bpf/bpf_elf.h          |   53 -
 drivers/net/tap/bpf/bpf_extract.py     |   86 --
 drivers/net/tap/bpf/meson.build        |  107 ++
 drivers/net/tap/bpf/tap_bpf_program.c  |  255 ----
 drivers/net/tap/bpf/tap_rss.c          |  267 ++++
 drivers/net/tap/meson.build            |   42 +-
 drivers/net/tap/rte_eth_tap.c          |  384 +++---
 drivers/net/tap/rte_eth_tap.h          |   42 +-
 drivers/net/tap/tap_bpf.h              |  121 --
 drivers/net/tap/tap_bpf_api.c          |  190 ---
 drivers/net/tap/tap_bpf_insns.h        | 1743 ------------------------
 drivers/net/tap/tap_flow.c             |  557 ++------
 drivers/net/tap/tap_flow.h             |   17 +-
 drivers/net/tap/tap_intr.c             |    7 +-
 drivers/net/tap/tap_rss.h              |   21 +-
 drivers/net/tap/tap_tcmsgs.h           |    4 +-
 22 files changed, 907 insertions(+), 3617 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c
 delete mode 100644 drivers/net/tap/tap_bpf.h
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v12 01/12] net/tap: fix fd check in flow_isolate
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 02/12] net/tap: do not duplicate fd's Stephen Hemminger
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The check for receive queue fd in flow_isolate is incorrect.
If queue has not been setup then fd will be -1 not 0.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index fa50fe45d7..79cd6a12ca 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,7 +1595,7 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (!process_private->rxq_fds[0])
+	if (process_private->rxq_fds[0] == -1)
 		return 0;
 	if (set) {
 		struct rte_flow *remote_flow;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 02/12] net/tap: do not duplicate fd's
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 01/12] net/tap: fix fd check in flow_isolate Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 03/12] net/tap: remove unused fields Stephen Hemminger
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The TAP device can use same file descriptor for both rx and tx queues.
This allows up to 8 queues (versus 4) to be used with secondary process.

Bugzilla ID: 1381
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 192 ++++++++++++++--------------------
 drivers/net/tap/rte_eth_tap.h |   3 +-
 drivers/net/tap/tap_flow.c    |   3 +-
 drivers/net/tap/tap_intr.c    |   7 +-
 4 files changed, 85 insertions(+), 120 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 69d9da695b..b84fc01856 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -124,8 +124,7 @@ enum ioctl_mode {
 /* Message header to synchronize queues via IPC */
 struct ipc_queues {
 	char port_name[RTE_DEV_NAME_MAX_LEN];
-	int rxq_count;
-	int txq_count;
+	int q_count;
 	/*
 	 * The file descriptors are in the dedicated part
 	 * of the Unix message to be translated by the kernel.
@@ -446,7 +445,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		uint16_t data_off = rte_pktmbuf_headroom(mbuf);
 		int len;
 
-		len = readv(process_private->rxq_fds[rxq->queue_id],
+		len = readv(process_private->fds[rxq->queue_id],
 			*rxq->iovecs,
 			1 + (rxq->rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER ?
 			     rxq->nb_rx_desc : 1));
@@ -643,7 +642,7 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->txq_fds[txq->queue_id], iovecs, k);
+		n = writev(process_private->fds[txq->queue_id], iovecs, k);
 		if (n <= 0)
 			return -1;
 
@@ -851,7 +850,6 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	struct rte_mp_msg msg;
 	struct ipc_queues *request_param = (struct ipc_queues *)msg.param;
 	int err;
-	int fd_iterator = 0;
 	struct pmd_process_private *process_private = dev->process_private;
 	int i;
 
@@ -859,16 +857,13 @@ tap_mp_req_on_rxtx(struct rte_eth_dev *dev)
 	strlcpy(msg.name, TAP_MP_REQ_START_RXTX, sizeof(msg.name));
 	strlcpy(request_param->port_name, dev->data->name, sizeof(request_param->port_name));
 	msg.len_param = sizeof(*request_param);
-	for (i = 0; i < dev->data->nb_tx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->txq_fds[i];
-		msg.num_fds++;
-		request_param->txq_count++;
-	}
-	for (i = 0; i < dev->data->nb_rx_queues; i++) {
-		msg.fds[fd_iterator++] = process_private->rxq_fds[i];
-		msg.num_fds++;
-		request_param->rxq_count++;
-	}
+
+	/* rx and tx share file descriptors and nb_tx_queues == nb_rx_queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		msg.fds[i] = process_private->fds[i];
+
+	request_param->q_count = dev->data->nb_rx_queues;
+	msg.num_fds = dev->data->nb_rx_queues;
 
 	err = rte_mp_sendmsg(&msg);
 	if (err < 0) {
@@ -910,8 +905,6 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	struct rte_eth_dev *dev;
 	const struct ipc_queues *request_param =
 		(const struct ipc_queues *)request->param;
-	int fd_iterator;
-	int queue;
 	struct pmd_process_private *process_private;
 
 	dev = rte_eth_dev_get_by_name(request_param->port_name);
@@ -920,14 +913,13 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 			request_param->port_name);
 		return -1;
 	}
+
 	process_private = dev->process_private;
-	fd_iterator = 0;
-	TAP_LOG(DEBUG, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,
-		request_param->txq_count);
-	for (queue = 0; queue < request_param->txq_count; queue++)
-		process_private->txq_fds[queue] = request->fds[fd_iterator++];
-	for (queue = 0; queue < request_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = request->fds[fd_iterator++];
+	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+
+	for (int q = 0; q < request_param->q_count; q++)
+		process_private->fds[q] = request->fds[q];
+
 
 	return 0;
 }
@@ -1115,13 +1107,21 @@ tap_stats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static void
+tap_queue_close(struct pmd_process_private *process_private, uint16_t qid)
+{
+	if (process_private->fds[qid] != -1) {
+		close(process_private->fds[qid]);
+		process_private->fds[qid] = -1;
+	}
+}
+
 static int
 tap_dev_close(struct rte_eth_dev *dev)
 {
 	int i;
 	struct pmd_internals *internals = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
-	struct rx_queue *rxq;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		rte_free(dev->process_private);
@@ -1141,19 +1141,14 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		if (process_private->rxq_fds[i] != -1) {
-			rxq = &internals->rxq[i];
-			close(process_private->rxq_fds[i]);
-			process_private->rxq_fds[i] = -1;
-			tap_rxq_pool_free(rxq->pool);
-			rte_free(rxq->iovecs);
-			rxq->pool = NULL;
-			rxq->iovecs = NULL;
-		}
-		if (process_private->txq_fds[i] != -1) {
-			close(process_private->txq_fds[i]);
-			process_private->txq_fds[i] = -1;
-		}
+		struct rx_queue *rxq = &internals->rxq[i];
+
+		tap_queue_close(process_private, i);
+
+		tap_rxq_pool_free(rxq->pool);
+		rte_free(rxq->iovecs);
+		rxq->pool = NULL;
+		rxq->iovecs = NULL;
 	}
 
 	if (internals->remote_if_index) {
@@ -1206,15 +1201,16 @@ tap_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!rxq)
 		return;
+
 	process_private = rte_eth_devices[rxq->in_port].process_private;
-	if (process_private->rxq_fds[rxq->queue_id] != -1) {
-		close(process_private->rxq_fds[rxq->queue_id]);
-		process_private->rxq_fds[rxq->queue_id] = -1;
-		tap_rxq_pool_free(rxq->pool);
-		rte_free(rxq->iovecs);
-		rxq->pool = NULL;
-		rxq->iovecs = NULL;
-	}
+
+	tap_rxq_pool_free(rxq->pool);
+	rte_free(rxq->iovecs);
+	rxq->pool = NULL;
+	rxq->iovecs = NULL;
+
+	if (dev->data->tx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static void
@@ -1225,12 +1221,10 @@ tap_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 
 	if (!txq)
 		return;
-	process_private = rte_eth_devices[txq->out_port].process_private;
 
-	if (process_private->txq_fds[txq->queue_id] != -1) {
-		close(process_private->txq_fds[txq->queue_id]);
-		process_private->txq_fds[txq->queue_id] = -1;
-	}
+	process_private = rte_eth_devices[txq->out_port].process_private;
+	if (dev->data->rx_queues[qid] == NULL)
+		tap_queue_close(process_private, qid);
 }
 
 static int
@@ -1482,52 +1476,31 @@ tap_setup_queue(struct rte_eth_dev *dev,
 		uint16_t qid,
 		int is_rx)
 {
-	int ret;
-	int *fd;
-	int *other_fd;
-	const char *dir;
+	int fd, ret;
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct pmd_process_private *process_private = dev->process_private;
 	struct rx_queue *rx = &internals->rxq[qid];
 	struct tx_queue *tx = &internals->txq[qid];
-	struct rte_gso_ctx *gso_ctx;
+	struct rte_gso_ctx *gso_ctx = is_rx ? NULL : &tx->gso_ctx;
+	const char *dir = is_rx ? "rx" : "tx";
 
-	if (is_rx) {
-		fd = &process_private->rxq_fds[qid];
-		other_fd = &process_private->txq_fds[qid];
-		dir = "rx";
-		gso_ctx = NULL;
-	} else {
-		fd = &process_private->txq_fds[qid];
-		other_fd = &process_private->rxq_fds[qid];
-		dir = "tx";
-		gso_ctx = &tx->gso_ctx;
-	}
-	if (*fd != -1) {
+	fd = process_private->fds[qid];
+	if (fd != -1) {
 		/* fd for this queue already exists */
 		TAP_LOG(DEBUG, "%s: fd %d for %s queue qid %d exists",
-			pmd->name, *fd, dir, qid);
+			pmd->name, fd, dir, qid);
 		gso_ctx = NULL;
-	} else if (*other_fd != -1) {
-		/* Only other_fd exists. dup it */
-		*fd = dup(*other_fd);
-		if (*fd < 0) {
-			*fd = -1;
-			TAP_LOG(ERR, "%s: dup() failed.", pmd->name);
-			return -1;
-		}
-		TAP_LOG(DEBUG, "%s: dup fd %d for %s queue qid %d (%d)",
-			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
-		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0, 0);
-		if (*fd < 0) {
-			*fd = -1; /* restore original value */
+		fd = tun_alloc(pmd, 0, 0);
+		if (fd < 0) {
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
 			return -1;
 		}
+
 		TAP_LOG(DEBUG, "%s: add %s queue for qid %d fd %d",
-			pmd->name, dir, qid, *fd);
+			pmd->name, dir, qid, fd);
+
+		process_private->fds[qid] = fd;
 	}
 
 	tx->mtu = &dev->data->mtu;
@@ -1540,7 +1513,7 @@ tap_setup_queue(struct rte_eth_dev *dev,
 
 	tx->type = pmd->type;
 
-	return *fd;
+	return fd;
 }
 
 static int
@@ -1620,7 +1593,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 
 	TAP_LOG(DEBUG, "  RX TUNTAP device name %s, qid %d on fd %d",
 		internals->name, rx_queue_id,
-		process_private->rxq_fds[rx_queue_id]);
+		process_private->fds[rx_queue_id]);
 
 	return 0;
 
@@ -1664,7 +1637,7 @@ tap_tx_queue_setup(struct rte_eth_dev *dev,
 	TAP_LOG(DEBUG,
 		"  TX TUNTAP device name %s, qid %d on fd %d csum %s",
 		internals->name, tx_queue_id,
-		process_private->txq_fds[tx_queue_id],
+		process_private->fds[tx_queue_id],
 		txq->csum ? "on" : "off");
 
 	return 0;
@@ -2001,10 +1974,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	dev->intr_handle = pmd->intr_handle;
 
 	/* Presetup the fds to -1 as being not valid */
-	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		process_private->rxq_fds[i] = -1;
-		process_private->txq_fds[i] = -1;
-	}
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++)
+		process_private->fds[i] = -1;
+
 
 	if (pmd->type == ETH_TUNTAP_TYPE_TAP) {
 		if (rte_is_zero_ether_addr(mac_addr))
@@ -2332,7 +2304,6 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	struct ipc_queues *request_param = (struct ipc_queues *)request.param;
 	struct ipc_queues *reply_param;
 	struct pmd_process_private *process_private = dev->process_private;
-	int queue, fd_iterator;
 
 	/* Prepare the request */
 	memset(&request, 0, sizeof(request));
@@ -2352,18 +2323,17 @@ tap_mp_attach_queues(const char *port_name, struct rte_eth_dev *dev)
 	TAP_LOG(DEBUG, "Received IPC reply for %s", reply_param->port_name);
 
 	/* Attach the queues from received file descriptors */
-	if (reply_param->rxq_count + reply_param->txq_count != reply->num_fds) {
+	if (reply_param->q_count != reply->num_fds) {
 		TAP_LOG(ERR, "Unexpected number of fds received");
 		return -1;
 	}
 
-	dev->data->nb_rx_queues = reply_param->rxq_count;
-	dev->data->nb_tx_queues = reply_param->txq_count;
-	fd_iterator = 0;
-	for (queue = 0; queue < reply_param->rxq_count; queue++)
-		process_private->rxq_fds[queue] = reply->fds[fd_iterator++];
-	for (queue = 0; queue < reply_param->txq_count; queue++)
-		process_private->txq_fds[queue] = reply->fds[fd_iterator++];
+	dev->data->nb_rx_queues = reply_param->q_count;
+	dev->data->nb_tx_queues = reply_param->q_count;
+
+	for (int q = 0; q < reply_param->q_count; q++)
+		process_private->fds[q] = reply->fds[q];
+
 	free(reply);
 	return 0;
 }
@@ -2393,25 +2363,19 @@ tap_mp_sync_queues(const struct rte_mp_msg *request, const void *peer)
 
 	/* Fill file descriptors for all queues */
 	reply.num_fds = 0;
-	reply_param->rxq_count = 0;
-	if (dev->data->nb_rx_queues + dev->data->nb_tx_queues >
-			RTE_MP_MAX_FD_NUM){
-		TAP_LOG(ERR, "Number of rx/tx queues exceeds max number of fds");
+	reply_param->q_count = 0;
+
+	RTE_ASSERT(dev->data->nb_rx_queues == dev->data->nb_tx_queues);
+	if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
+		TAP_LOG(ERR, "Number of rx/tx queues %u exceeds max number of fds %u",
+			dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
 		return -1;
 	}
 
 	for (queue = 0; queue < dev->data->nb_rx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->rxq_fds[queue];
-		reply_param->rxq_count++;
-	}
-	RTE_ASSERT(reply_param->rxq_count == dev->data->nb_rx_queues);
-
-	reply_param->txq_count = 0;
-	for (queue = 0; queue < dev->data->nb_tx_queues; queue++) {
-		reply.fds[reply.num_fds++] = process_private->txq_fds[queue];
-		reply_param->txq_count++;
+		reply.fds[reply.num_fds++] = process_private->fds[queue];
+		reply_param->q_count++;
 	}
-	RTE_ASSERT(reply_param->txq_count == dev->data->nb_tx_queues);
 
 	/* Send reply */
 	strlcpy(reply.name, request->name, sizeof(reply.name));
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 5ac93f93e9..dc8201020b 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -96,8 +96,7 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	int rxq_fds[RTE_PMD_TAP_MAX_QUEUES];
-	int txq_fds[RTE_PMD_TAP_MAX_QUEUES];
+	int fds[RTE_PMD_TAP_MAX_QUEUES];
 };
 
 /* tap_intr.c */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 79cd6a12ca..a78fd50cd4 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1595,8 +1595,9 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 	 * If netdevice is there, setup appropriate flow rules immediately.
 	 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
 	 */
-	if (process_private->rxq_fds[0] == -1)
+	if (process_private->fds[0] == -1)
 		return 0;
+
 	if (set) {
 		struct rte_flow *remote_flow;
 
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index a9097def1a..1908f71f97 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -68,9 +68,11 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 	}
 	for (i = 0; i < n; i++) {
 		struct rx_queue *rxq = pmd->dev->data->rx_queues[i];
+		int fd = process_private->fds[i];
 
 		/* Skip queues that cannot request interrupts. */
-		if (!rxq || process_private->rxq_fds[i] == -1) {
+		if (!rxq || fd == -1) {
+			/* Use invalid intr_vec[] index to disable entry. */
 			/* Use invalid intr_vec[] index to disable entry. */
 			if (rte_intr_vec_list_index_set(intr_handle, i,
 			RTE_INTR_VEC_RXTX_OFFSET + RTE_MAX_RXTX_INTR_VEC_ID))
@@ -80,8 +82,7 @@ tap_rx_intr_vec_install(struct rte_eth_dev *dev)
 		if (rte_intr_vec_list_index_set(intr_handle, i,
 					RTE_INTR_VEC_RXTX_OFFSET + count))
 			return -rte_errno;
-		if (rte_intr_efds_index_set(intr_handle, count,
-						   process_private->rxq_fds[i]))
+		if (rte_intr_efds_index_set(intr_handle, count, fd))
 			return -rte_errno;
 		count++;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 03/12] net/tap: remove unused fields
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 01/12] net/tap: fix fd check in flow_isolate Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 02/12] net/tap: do not duplicate fd's Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 04/12] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver doesn't support these other hash types, and there
is no reason to implement these in future. The rss_flows list
was set but never used.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.h | 4 +---
 drivers/net/tap/tap_flow.c    | 1 -
 drivers/net/tap/tap_rss.h     | 6 ------
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..1bcf92ce80 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -77,14 +77,12 @@ struct pmd_internals {
 	int ioctl_sock;                   /* socket for ioctl calls */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int flower_support;               /* 1 if kernel supports, else 0 */
-	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index a78fd50cd4..8fccd599f0 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -1958,7 +1958,6 @@ static int rss_enable(struct pmd_internals *pmd,
 				errno, strerror(errno));
 			return err;
 		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
 	}
 
 	pmd->rss_enabled = 1;
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index dff46a012f..8766ffc244 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -21,12 +21,6 @@ enum hash_field {
 	HASH_FIELD_IPV4_L3_L4,	/* IPv4 src/dst addr + L4 src/dst ports */
 	HASH_FIELD_IPV6_L3,	/* IPv6 src/dst addr */
 	HASH_FIELD_IPV6_L3_L4,	/* IPv6 src/dst addr + L4 src/dst ports */
-	HASH_FIELD_L2_SRC,	/* Ethernet src addr */
-	HASH_FIELD_L2_DST,	/* Ethernet dst addr */
-	HASH_FIELD_L3_SRC,	/* L3 src addr */
-	HASH_FIELD_L3_DST,	/* L3 dst addr */
-	HASH_FIELD_L4_SRC,	/* TCP/UDP src ports */
-	HASH_FIELD_L4_DST,	/* TCP/UDP dst ports */
 };
 
 struct rss_key {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 04/12] net/tap: validate and setup parameters for BPF RSS
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (2 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 03/12] net/tap: remove unused fields Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 05/12] net/tap: do not build flow support if header is out of date Stephen Hemminger
                     ` (7 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The flow RSS support via BPF was not using the key, or
hash type parameters. Which is good because they were never
properly setup.

Fix the setup and validate the flow parameters, the BPF
side gets fixed later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_flow.c | 65 +++++++++++++++++++++++++++++++++++---
 drivers/net/tap/tap_rss.h  |  5 ++-
 2 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8fccd599f0..8cf64364a7 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -11,9 +11,11 @@
 
 #include <rte_byteorder.h>
 #include <rte_jhash.h>
+#include <rte_thash.h>
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+
 #include <tap_flow.h>
 #include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
@@ -2061,6 +2063,21 @@ static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
 	return err;
 }
 
+
+/* Default RSS hash key also used by mlx devices */
+static const uint8_t rss_hash_default_key[] = {
+	0x2c, 0xc6, 0x81, 0xd1,
+	0x5b, 0xdb, 0xf4, 0xf7,
+	0xfc, 0xa2, 0x83, 0x19,
+	0xdb, 0x1a, 0x3e, 0x94,
+	0x6b, 0x9e, 0x38, 0xd9,
+	0x2c, 0x9c, 0x03, 0xd1,
+	0xad, 0x99, 0x44, 0xa7,
+	0xd9, 0x56, 0x3d, 0x59,
+	0x06, 0x3c, 0x25, 0xf3,
+	0xfc, 0x1f, 0xdc, 0x2a,
+};
+
 /**
  * Add RSS hash calculations and queue selection
  *
@@ -2079,11 +2096,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
-	/* 4096 is the maximum number of instructions for a BPF program */
+	struct rss_key rss_entry = { };
+	const uint8_t *key_in;
+	uint32_t hash_type = 0;
 	unsigned int i;
 	int err;
-	struct rss_key rss_entry = { .hash_fields = 0,
-				     .key_size = 0 };
 
 	/* Check supported RSS features */
 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
@@ -2095,6 +2112,41 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 			 "a nonzero RSS encapsulation level is not supported");
 
+	if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "invalid number of queues");
+
+	/* allow RSS key_len 0 in case of NULL (default) RSS key. */
+	if (rss->key_len == 0) {
+		if (rss->key != NULL)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						  &rss->key_len, "RSS hash key length 0");
+		key_in = rss_hash_default_key;
+	} else {
+		if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash invalid key length");
+		if (rss->key == NULL)
+			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						  NULL, "RSS hash key is NULL");
+		key_in = rss->key;
+	}
+
+	if (rss->types & TAP_RSS_HF_MASK)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "RSS hash type not supported");
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
+
+	if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
+	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
+		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
+
 	/* Get a new map key for a new RSS rule */
 	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 	if (err < 0) {
@@ -2109,8 +2161,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
-	rss_entry.hash_fields =
-		(1 << HASH_FIELD_IPV4_L3_L4) | (1 << HASH_FIELD_IPV6_L3_L4);
+
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
+
 
 	/* Add this RSS entry to map */
 	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 8766ffc244..6009be7031 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -24,11 +24,10 @@ enum hash_field {
 };
 
 struct rss_key {
-	 __u8 key[128];
 	__u32 hash_fields;
-	__u32 key_size;
-	__u32 queues[TAP_MAX_QUEUES];
+	__u8 key[TAP_RSS_HASH_KEY_SIZE];
 	__u32 nb_queues;
+	__u32 queues[TAP_MAX_QUEUES];
 } __attribute__((packed));
 
 #endif /* _TAP_RSS_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 05/12] net/tap: do not build flow support if header is out of date
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (3 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 04/12] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 06/12] net/tap: rewrite the RSS BPF program Stephen Hemminger
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The proper place for finding bpf structures and functions is
in linux/bpf.h. The original version was trying to workaround the
case where the build environment was running on old pre BPF
version of Glibc, but the target environment had BPF.

Having own private (and divergent) version headers leads to future
problems when BPF definitions evolve.

If the build infrastructure is so old that TC flower is not
supported, then the TAP device will build without any flow support.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/bpf_extract.py |   1 -
 drivers/net/tap/meson.build        |  17 ++--
 drivers/net/tap/rte_eth_tap.c      |  38 +++++++--
 drivers/net/tap/rte_eth_tap.h      |   7 +-
 drivers/net/tap/tap_bpf.h          | 121 -----------------------------
 drivers/net/tap/tap_bpf_api.c      |  20 +++--
 drivers/net/tap/tap_bpf_insns.h    |   2 -
 drivers/net/tap/tap_flow.c         |  90 ---------------------
 8 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf.h

diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
index b630c42b80..73c4dafe4e 100644
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ b/drivers/net/tap/bpf/bpf_extract.py
@@ -65,7 +65,6 @@ def write_header(out, source):
         print(f' * Auto-generated from {source}', file=out)
     print(" * This not the original source file. Do NOT edit it.", file=out)
     print(" */\n", file=out)
-    print("#include <tap_bpf.h>", file=out)
 
 
 def main():
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 5099ccdff1..66647a1c62 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,13 +7,19 @@ if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
-        'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
-        'tap_tcmsgs.c',
 )
 
+if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
+    cflags += '-DHAVE_TCA_FLOWER'
+    sources += files(
+        'tap_bpf_api.c',
+        'tap_flow.c',
+        'tap_tcmsgs.c',
+    )
+endif
+
 deps = ['bus_vdev', 'gso', 'hash']
 
 cflags += '-DTAP_MAX_QUEUES=16'
@@ -23,12 +29,7 @@ cflags += '-DTAP_MAX_QUEUES=16'
 #   "enum/define", "symbol to search" ]
 #
 args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
         [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
 ]
 config = configuration_data()
 foreach arg:args
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b84fc01856..9058a47295 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1133,12 +1133,15 @@ tap_dev_close(struct rte_eth_dev *dev)
 
 	if (!internals->persist)
 		tap_link_set_down(dev);
+
+#ifdef HAVE_TCA_FLOWER
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
 	}
+#endif
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
 		struct rx_queue *rxq = &internals->rxq[i];
@@ -1261,6 +1264,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
@@ -1274,7 +1278,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -1289,6 +1293,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->promiscuous = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
@@ -1302,6 +1307,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1317,6 +1323,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 1;
 		ret = tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
@@ -1330,6 +1337,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1345,6 +1353,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	if (ret != 0)
 		return ret;
 
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		dev->data->all_multicast = 0;
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
@@ -1358,6 +1367,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1403,6 +1413,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 	if (ret < 0)
 		return ret;
 	rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->remote_if_index && !pmd->flow_isolate) {
 		/* Replace MAC redirection rule after a MAC change */
 		ret = tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC);
@@ -1420,6 +1432,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			return ret;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -1894,7 +1907,9 @@ static const struct eth_dev_ops ops = {
 	.stats_reset            = tap_stats_reset,
 	.dev_supported_ptypes_get = tap_dev_supported_ptypes_get,
 	.rss_hash_update        = tap_rss_hash_update,
+#ifdef HAVE_TCA_FLOWER
 	.flow_ops_get           = tap_dev_flow_ops_get,
+#endif
 };
 
 static int
@@ -1934,7 +1949,9 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+#ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
+#endif
 	pmd->gso_ctx_mp = NULL;
 
 	pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -2014,6 +2031,14 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
+
+
+#ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2028,11 +2053,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
@@ -2043,6 +2063,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
@@ -2095,6 +2116,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_remote;
 		}
 	}
+#endif
 
 	rte_eth_dev_probing_finish(dev);
 	return 0;
@@ -2109,14 +2131,18 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	rte_eth_dev_probing_finish(dev);
 	return 0;
 
+#ifdef HAVE_TCA_FLOWER
 error_remote:
 	TAP_LOG(ERR, " Can't set up remote feature: %s(%d)",
 		strerror(errno), errno);
 	tap_flow_implicit_flush(pmd, NULL);
+#endif
 
 error_exit:
+#ifdef HAVE_TCA_FLOWER
 	if (pmd->nlsk_fd != -1)
 		close(pmd->nlsk_fd);
+#endif
 	if (pmd->ka_fd != -1)
 		close(pmd->ka_fd);
 	if (pmd->ioctl_sock != -1)
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 1bcf92ce80..af18b29090 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -16,6 +16,7 @@
 #include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_gso.h>
+
 #include "tap_log.h"
 
 #ifdef IFF_MULTI_QUEUE
@@ -70,15 +71,17 @@ struct pmd_internals {
 	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
+	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+
+#ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
@@ -86,6 +89,8 @@ struct pmd_internals {
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
+#endif
+
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
diff --git a/drivers/net/tap/tap_bpf.h b/drivers/net/tap/tap_bpf.h
deleted file mode 100644
index d8437927ef..0000000000
--- a/drivers/net/tap/tap_bpf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#ifndef __TAP_BPF_H__
-#define __TAP_BPF_H__
-
-#include <tap_autoconf.h>
-
-/* Do not #include <linux/bpf.h> since eBPF must compile on different
- * distros which may include partial definitions for eBPF (while the
- * kernel itself may support eBPF). Instead define here all that is needed
- */
-
-/* BPF_MAP_UPDATE_ELEM command flags */
-#define	BPF_ANY	0 /* create a new element or update an existing */
-
-/* BPF architecture instruction struct */
-struct bpf_insn {
-	__u8	code;
-	__u8	dst_reg:4;
-	__u8	src_reg:4;
-	__s16	off;
-	__s32	imm; /* immediate value */
-};
-
-/* BPF program types */
-enum bpf_prog_type {
-	BPF_PROG_TYPE_UNSPEC,
-	BPF_PROG_TYPE_SOCKET_FILTER,
-	BPF_PROG_TYPE_KPROBE,
-	BPF_PROG_TYPE_SCHED_CLS,
-	BPF_PROG_TYPE_SCHED_ACT,
-};
-
-/* BPF commands types */
-enum bpf_cmd {
-	BPF_MAP_CREATE,
-	BPF_MAP_LOOKUP_ELEM,
-	BPF_MAP_UPDATE_ELEM,
-	BPF_MAP_DELETE_ELEM,
-	BPF_MAP_GET_NEXT_KEY,
-	BPF_PROG_LOAD,
-};
-
-/* BPF maps types */
-enum bpf_map_type {
-	BPF_MAP_TYPE_UNSPEC,
-	BPF_MAP_TYPE_HASH,
-};
-
-/* union of anonymous structs used with TAP BPF commands */
-union __rte_aligned(8) bpf_attr {
-	/* BPF_MAP_CREATE command */
-	struct {
-		__u32	map_type;
-		__u32	key_size;
-		__u32	value_size;
-		__u32	max_entries;
-		__u32	map_flags;
-		__u32	inner_map_fd;
-	};
-
-	/* BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands */
-	struct {
-		__u32		map_fd;
-		__aligned_u64	key;
-		union {
-			__aligned_u64 value;
-			__aligned_u64 next_key;
-		};
-		__u64		flags;
-	};
-
-	/* BPF_PROG_LOAD command */
-	struct {
-		__u32		prog_type;
-		__u32		insn_cnt;
-		__aligned_u64	insns;
-		__aligned_u64	license;
-		__u32		log_level;
-		__u32		log_size;
-		__aligned_u64	log_buf;
-		__u32		kern_version;
-		__u32		prog_flags;
-	};
-};
-
-#ifndef __NR_bpf
-# if defined(__i386__)
-#  define __NR_bpf 357
-# elif defined(__x86_64__)
-#  define __NR_bpf 321
-# elif defined(__arm__)
-#  define __NR_bpf 386
-# elif defined(__aarch64__)
-#  define __NR_bpf 280
-# elif defined(__sparc__)
-#  define __NR_bpf 349
-# elif defined(__s390__)
-#  define __NR_bpf 351
-# elif defined(__powerpc__)
-#  define __NR_bpf 361
-# elif defined(__riscv)
-#  define __NR_bpf 280
-# elif defined(__loongarch__)
-#  define __NR_bpf 280
-# else
-#  error __NR_bpf not defined
-# endif
-#endif
-
-enum {
-	BPF_MAP_ID_KEY,
-	BPF_MAP_ID_SIMPLE,
-};
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-#endif /* __TAP_BPF_H__ */
diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
index 15283f8917..9e05e2ddf1 100644
--- a/drivers/net/tap/tap_bpf_api.c
+++ b/drivers/net/tap/tap_bpf_api.c
@@ -2,19 +2,19 @@
  * Copyright 2017 Mellanox Technologies, Ltd
  */
 
-#include <errno.h>
-#include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
+#include <syscall.h>
+#include <linux/bpf.h>
 
-#include <rte_malloc.h>
-#include <rte_eth_tap.h>
 #include <tap_flow.h>
 #include <tap_autoconf.h>
-#include <tap_tcmsgs.h>
-#include <tap_bpf.h>
+
 #include <tap_bpf_insns.h>
 
+
+static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
+		size_t insns_cnt, const char *license);
+
 /**
  * Load BPF program (section cls_q) into the kernel and return a bpf fd
  *
@@ -89,7 +89,13 @@ static inline __u64 ptr_to_u64(const void *ptr)
 static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
 			unsigned int size)
 {
+#ifdef __NR_bpf
 	return syscall(__NR_bpf, cmd, attr, size);
+#else
+	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
+	errno = ENOSYS;
+	return -1;
+#endif
 }
 
 /**
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
index 53fa76c4e6..cdf2febf05 100644
--- a/drivers/net/tap/tap_bpf_insns.h
+++ b/drivers/net/tap/tap_bpf_insns.h
@@ -3,8 +3,6 @@
  * This not the original source file. Do NOT edit it.
  */
 
-#include <tap_bpf.h>
-
 static struct bpf_insn cls_q_insns[] = {
 	{0x61,    2,    1,       52, 0x00000000},
 	{0x18,    3,    0,        0, 0xdeadbeef},
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 8cf64364a7..5a5a4ea048 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -21,96 +21,6 @@
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-#ifndef HAVE_TC_FLOWER
-/*
- * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
- * avoid sending TC messages the kernel cannot understand.
- */
-enum {
-	TCA_FLOWER_UNSPEC,
-	TCA_FLOWER_CLASSID,
-	TCA_FLOWER_INDEV,
-	TCA_FLOWER_ACT,
-	TCA_FLOWER_KEY_ETH_DST,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_DST_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC,         /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_SRC_MASK,    /* ETH_ALEN */
-	TCA_FLOWER_KEY_ETH_TYPE,        /* be16 */
-	TCA_FLOWER_KEY_IP_PROTO,        /* u8 */
-	TCA_FLOWER_KEY_IPV4_SRC,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_SRC_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST,        /* be32 */
-	TCA_FLOWER_KEY_IPV4_DST_MASK,   /* be32 */
-	TCA_FLOWER_KEY_IPV6_SRC,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_SRC_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST,        /* struct in6_addr */
-	TCA_FLOWER_KEY_IPV6_DST_MASK,   /* struct in6_addr */
-	TCA_FLOWER_KEY_TCP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_TCP_DST,         /* be16 */
-	TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
-	TCA_FLOWER_KEY_UDP_DST,         /* be16 */
-};
-#endif
-#ifndef HAVE_TC_VLAN_ID
-enum {
-	/* TCA_FLOWER_FLAGS, */
-	TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
-	TCA_FLOWER_KEY_VLAN_PRIO,       /* u8   */
-	TCA_FLOWER_KEY_VLAN_ETH_TYPE,   /* be16 */
-};
-#endif
-/*
- * For kernels < 4.2 BPF related enums may not be defined.
- * Runtime checks will be carried out to gracefully report on TC messages that
- * are rejected by the kernel. Rejection reasons may be due to:
- * 1. enum is not defined
- * 2. enum is defined but kernel is not configured to support BPF system calls,
- *    BPF classifications or BPF actions.
- */
-#ifndef HAVE_TC_BPF
-enum {
-	TCA_BPF_UNSPEC,
-	TCA_BPF_ACT,
-	TCA_BPF_POLICE,
-	TCA_BPF_CLASSID,
-	TCA_BPF_OPS_LEN,
-	TCA_BPF_OPS,
-};
-#endif
-#ifndef HAVE_TC_BPF_FD
-enum {
-	TCA_BPF_FD = TCA_BPF_OPS + 1,
-	TCA_BPF_NAME,
-};
-#endif
-#ifndef HAVE_TC_ACT_BPF
-#define tc_gen \
-	__u32                 index; \
-	__u32                 capab; \
-	int                   action; \
-	int                   refcnt; \
-	int                   bindcnt
-
-struct tc_act_bpf {
-	tc_gen;
-};
-
-enum {
-	TCA_ACT_BPF_UNSPEC,
-	TCA_ACT_BPF_TM,
-	TCA_ACT_BPF_PARMS,
-	TCA_ACT_BPF_OPS_LEN,
-	TCA_ACT_BPF_OPS,
-};
-
-#endif
-#ifndef HAVE_TC_ACT_BPF_FD
-enum {
-	TCA_ACT_BPF_FD = TCA_ACT_BPF_OPS + 1,
-	TCA_ACT_BPF_NAME,
-};
-#endif
-
 /* RSS key management */
 enum bpf_rss_key_e {
 	KEY_CMD_GET = 1,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 06/12] net/tap: rewrite the RSS BPF program
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (4 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 05/12] net/tap: do not build flow support if header is out of date Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 07/12] net/tap: use libbpf to load new " Stephen Hemminger
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Rewrite of the BPF program used to do queue based RSS.

Important changes:
	- uses newer BPF map format BTF
	- accepts key as parameter rather than constant default
	- can do L3 or L4 hashing
	- supports IPv4 options
	- supports IPv6 extension headers
	- restructured for readability

The usage of BPF is different as well:
	- the incoming configuration is looked up based on
	  class parameters rather than patching the BPF code.
	- the resulting queue is placed in skb by using skb mark
	  than requiring a second pass through classifier step.

Note: This version only works with later patch to enable it on
the DPDK driver side. It is submitted as an incremental patch
to allow for easier review. Bisection still works because
the old instruction are still present for now.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 .gitignore                            |   3 -
 drivers/net/tap/bpf/Makefile          |  19 --
 drivers/net/tap/bpf/README            |  49 +++++
 drivers/net/tap/bpf/bpf_api.h         | 276 --------------------------
 drivers/net/tap/bpf/bpf_elf.h         |  53 -----
 drivers/net/tap/bpf/bpf_extract.py    |  85 --------
 drivers/net/tap/bpf/meson.build       |  81 ++++++++
 drivers/net/tap/bpf/tap_bpf_program.c | 255 ------------------------
 drivers/net/tap/bpf/tap_rss.c         | 267 +++++++++++++++++++++++++
 9 files changed, 397 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/net/tap/bpf/Makefile
 create mode 100644 drivers/net/tap/bpf/README
 delete mode 100644 drivers/net/tap/bpf/bpf_api.h
 delete mode 100644 drivers/net/tap/bpf/bpf_elf.h
 delete mode 100644 drivers/net/tap/bpf/bpf_extract.py
 create mode 100644 drivers/net/tap/bpf/meson.build
 delete mode 100644 drivers/net/tap/bpf/tap_bpf_program.c
 create mode 100644 drivers/net/tap/bpf/tap_rss.c

diff --git a/.gitignore b/.gitignore
index 3f444dcace..01a47a7606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,9 +36,6 @@ TAGS
 # ignore python bytecode files
 *.pyc
 
-# ignore BPF programs
-drivers/net/tap/bpf/tap_bpf_program.o
-
 # DTS results
 dts/output
 
diff --git a/drivers/net/tap/bpf/Makefile b/drivers/net/tap/bpf/Makefile
deleted file mode 100644
index 9efeeb1bc7..0000000000
--- a/drivers/net/tap/bpf/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# This file is not built as part of normal DPDK build.
-# It is used to generate the eBPF code for TAP RSS.
-
-CLANG=clang
-CLANG_OPTS=-O2
-TARGET=../tap_bpf_insns.h
-
-all: $(TARGET)
-
-clean:
-	rm tap_bpf_program.o $(TARGET)
-
-tap_bpf_program.o: tap_bpf_program.c
-	$(CLANG) $(CLANG_OPTS) -emit-llvm -c $< -o - | \
-	llc -march=bpf -filetype=obj -o $@
-
-$(TARGET): tap_bpf_program.o
-	python3 bpf_extract.py -stap_bpf_program.c -o $@ $<
diff --git a/drivers/net/tap/bpf/README b/drivers/net/tap/bpf/README
new file mode 100644
index 0000000000..6d323d2051
--- /dev/null
+++ b/drivers/net/tap/bpf/README
@@ -0,0 +1,49 @@
+This is the BPF program used to implement Receive Side Scaling (RSS)
+across multiple queues if required by a flow action. The program is
+loaded into the kernel when first RSS flow rule is created and is never unloaded.
+
+When flow rules with the TAP device, packets are first handled by the
+ingress queue discipline that then runs a series of classifier filter rules.
+The first stage is the flow based classifier (flower); for RSS queue
+action the second stage is an the kernel skbedit action which sets
+the skb mark to a key based on the flow id; the final stage
+is this BPF program which then maps flow id and packet header
+into a queue id.
+
+This version is built the BPF Compile Once — Run Everywhere (CO-RE)
+framework and uses libbpf and bpftool.
+
+Limitations
+-----------
+- requires libbpf to run
+
+- rebuilding the BPF requires the clang compiler with bpf available
+  as a target architecture and bpftool to convert object to headers.
+
+  Some older versions of Ubuntu do not have a working bpftool package.
+
+- only standard Toeplitz hash with standard 40 byte key is supported.
+
+- the number of flow rules using RSS is limited to 32.
+
+Building
+--------
+During the DPDK build process the meson build file checks that
+libbpf, bpftool, and clang are available. If everything works then
+BPF RSS is enabled.
+
+The steps are:
+
+1. Uses clang to compile tap_rss.c to produce tap_rss.bpf.o
+
+2. Uses bpftool generate a skeleton header file tap_rss.skel.h
+   from tap_rss.bpf.o. This header contains wrapper functions for
+   managing the BPF and the actual BPF code as a large byte array.
+
+3. The header file is include in tap_flow.c so that it can load
+   the BPF code (via libbpf).
+
+References
+----------
+BPF and XDP reference guide
+https://docs.cilium.io/en/latest/bpf/progtypes/
diff --git a/drivers/net/tap/bpf/bpf_api.h b/drivers/net/tap/bpf/bpf_api.h
deleted file mode 100644
index 4cd25fa593..0000000000
--- a/drivers/net/tap/bpf/bpf_api.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-
-#ifndef __BPF_API__
-#define __BPF_API__
-
-/* Note:
- *
- * This file can be included into eBPF kernel programs. It contains
- * a couple of useful helper functions, map/section ABI (bpf_elf.h),
- * misc macros and some eBPF specific LLVM built-ins.
- */
-
-#include <stdint.h>
-
-#include <linux/pkt_cls.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-
-#include <asm/byteorder.h>
-
-#include "bpf_elf.h"
-
-/** libbpf pin type. */
-enum libbpf_pin_type {
-	LIBBPF_PIN_NONE,
-	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
-	LIBBPF_PIN_BY_NAME,
-};
-
-/** Type helper macros. */
-
-#define __uint(name, val) int (*name)[val]
-#define __type(name, val) typeof(val) *name
-#define __array(name, val) typeof(val) *name[]
-
-/** Misc macros. */
-
-#ifndef __stringify
-# define __stringify(X)		#X
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused		__attribute__((__unused__))
-#endif
-
-#ifndef offsetof
-# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
-#endif
-
-#ifndef likely
-# define likely(X)		__builtin_expect(!!(X), 1)
-#endif
-
-#ifndef unlikely
-# define unlikely(X)		__builtin_expect(!!(X), 0)
-#endif
-
-#ifndef htons
-# define htons(X)		__constant_htons((X))
-#endif
-
-#ifndef ntohs
-# define ntohs(X)		__constant_ntohs((X))
-#endif
-
-#ifndef htonl
-# define htonl(X)		__constant_htonl((X))
-#endif
-
-#ifndef ntohl
-# define ntohl(X)		__constant_ntohl((X))
-#endif
-
-#ifndef __inline__
-# define __inline__		__attribute__((always_inline))
-#endif
-
-/** Section helper macros. */
-
-#ifndef __section
-# define __section(NAME)						\
-	__attribute__((section(NAME), used))
-#endif
-
-#ifndef __section_tail
-# define __section_tail(ID, KEY)					\
-	__section(__stringify(ID) "/" __stringify(KEY))
-#endif
-
-#ifndef __section_xdp_entry
-# define __section_xdp_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_cls_entry
-# define __section_cls_entry						\
-	__section(ELF_SECTION_CLASSIFIER)
-#endif
-
-#ifndef __section_act_entry
-# define __section_act_entry						\
-	__section(ELF_SECTION_ACTION)
-#endif
-
-#ifndef __section_lwt_entry
-# define __section_lwt_entry						\
-	__section(ELF_SECTION_PROG)
-#endif
-
-#ifndef __section_license
-# define __section_license						\
-	__section(ELF_SECTION_LICENSE)
-#endif
-
-#ifndef __section_maps
-# define __section_maps							\
-	__section(ELF_SECTION_MAPS)
-#endif
-
-/** Declaration helper macros. */
-
-#ifndef BPF_LICENSE
-# define BPF_LICENSE(NAME)						\
-	char ____license[] __section_license = NAME
-#endif
-
-/** Classifier helper */
-
-#ifndef BPF_H_DEFAULT
-# define BPF_H_DEFAULT	-1
-#endif
-
-/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
-
-#ifndef __BPF_FUNC
-# define __BPF_FUNC(NAME, ...)						\
-	(* NAME)(__VA_ARGS__) __maybe_unused
-#endif
-
-#ifndef BPF_FUNC
-# define BPF_FUNC(NAME, ...)						\
-	__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
-#endif
-
-/* Map access/manipulation */
-static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
-static int BPF_FUNC(map_update_elem, void *map, const void *key,
-		    const void *value, uint32_t flags);
-static int BPF_FUNC(map_delete_elem, void *map, const void *key);
-
-/* Time access */
-static uint64_t BPF_FUNC(ktime_get_ns);
-
-/* Debugging */
-
-/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
- * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
- * It would require ____fmt to be made const, which generates a reloc
- * entry (non-map).
- */
-static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
-
-#ifndef printt
-# define printt(fmt, ...)						\
-	__extension__ ({						\
-		char ____fmt[] = fmt;					\
-		trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__);	\
-	})
-#endif
-
-/* Random numbers */
-static uint32_t BPF_FUNC(get_prandom_u32);
-
-/* Tail calls */
-static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
-		     uint32_t index);
-
-/* System helpers */
-static uint32_t BPF_FUNC(get_smp_processor_id);
-static uint32_t BPF_FUNC(get_numa_node_id);
-
-/* Packet misc meta data */
-static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
-static int BPF_FUNC(skb_under_cgroup, void *map, uint32_t index);
-
-static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(get_hash_recalc, struct __sk_buff *skb);
-static uint32_t BPF_FUNC(set_hash_invalid, struct __sk_buff *skb);
-
-/* Packet redirection */
-static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
-static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
-		    uint32_t flags);
-
-/* Packet manipulation */
-static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
-		    void *to, uint32_t len);
-static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
-		    const void *from, uint32_t len, uint32_t flags);
-
-static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
-		    uint32_t from, uint32_t to, uint32_t flags);
-static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size,
-		    const void *to, uint32_t to_size, uint32_t seed);
-static int BPF_FUNC(csum_update, struct __sk_buff *skb, uint32_t wsum);
-
-static int BPF_FUNC(skb_change_type, struct __sk_buff *skb, uint32_t type);
-static int BPF_FUNC(skb_change_proto, struct __sk_buff *skb, uint32_t proto,
-		    uint32_t flags);
-static int BPF_FUNC(skb_change_tail, struct __sk_buff *skb, uint32_t nlen,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_pull_data, struct __sk_buff *skb, uint32_t len);
-
-/* Event notification */
-static int __BPF_FUNC(skb_event_output, struct __sk_buff *skb, void *map,
-		      uint64_t index, const void *data, uint32_t size) =
-		      (void *) BPF_FUNC_perf_event_output;
-
-/* Packet vlan encap/decap */
-static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
-		    uint16_t vlan_tci);
-static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
-
-/* Packet tunnel encap/decap */
-static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
-		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
-static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
-		    const struct bpf_tunnel_key *from, uint32_t size,
-		    uint32_t flags);
-
-static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb,
-		    void *to, uint32_t size);
-static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb,
-		    const void *from, uint32_t size);
-
-/** LLVM built-ins, mem*() routines work for constant size */
-
-#ifndef lock_xadd
-# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
-#endif
-
-#ifndef memset
-# define memset(s, c, n)	__builtin_memset((s), (c), (n))
-#endif
-
-#ifndef memcpy
-# define memcpy(d, s, n)	__builtin_memcpy((d), (s), (n))
-#endif
-
-#ifndef memmove
-# define memmove(d, s, n)	__builtin_memmove((d), (s), (n))
-#endif
-
-/* FIXME: __builtin_memcmp() is not yet fully usable unless llvm bug
- * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
- * this one would generate a reloc entry (non-map), otherwise.
- */
-#if 0
-#ifndef memcmp
-# define memcmp(a, b, n)	__builtin_memcmp((a), (b), (n))
-#endif
-#endif
-
-unsigned long long load_byte(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.byte");
-
-unsigned long long load_half(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.half");
-
-unsigned long long load_word(void *skb, unsigned long long off)
-	asm ("llvm.bpf.load.word");
-
-#endif /* __BPF_API__ */
diff --git a/drivers/net/tap/bpf/bpf_elf.h b/drivers/net/tap/bpf/bpf_elf.h
deleted file mode 100644
index ea8a11c95c..0000000000
--- a/drivers/net/tap/bpf/bpf_elf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
-#ifndef __BPF_ELF__
-#define __BPF_ELF__
-
-#include <asm/types.h>
-
-/* Note:
- *
- * Below ELF section names and bpf_elf_map structure definition
- * are not (!) kernel ABI. It's rather a "contract" between the
- * application and the BPF loader in tc. For compatibility, the
- * section names should stay as-is. Introduction of aliases, if
- * needed, are a possibility, though.
- */
-
-/* ELF section names, etc */
-#define ELF_SECTION_LICENSE	"license"
-#define ELF_SECTION_MAPS	"maps"
-#define ELF_SECTION_PROG	"prog"
-#define ELF_SECTION_CLASSIFIER	"classifier"
-#define ELF_SECTION_ACTION	"action"
-
-#define ELF_MAX_MAPS		64
-#define ELF_MAX_LICENSE_LEN	128
-
-/* Object pinning settings */
-#define PIN_NONE		0
-#define PIN_OBJECT_NS		1
-#define PIN_GLOBAL_NS		2
-
-/* ELF map definition */
-struct bpf_elf_map {
-	__u32 type;
-	__u32 size_key;
-	__u32 size_value;
-	__u32 max_elem;
-	__u32 flags;
-	__u32 id;
-	__u32 pinning;
-	__u32 inner_id;
-	__u32 inner_idx;
-};
-
-#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\
-	struct ____btf_map_##name {				\
-		type_key key;					\
-		type_val value;					\
-	};							\
-	struct ____btf_map_##name				\
-	    __attribute__ ((section(".maps." #name), used))	\
-	    ____btf_map_##name = { }
-
-#endif /* __BPF_ELF__ */
diff --git a/drivers/net/tap/bpf/bpf_extract.py b/drivers/net/tap/bpf/bpf_extract.py
deleted file mode 100644
index 73c4dafe4e..0000000000
--- a/drivers/net/tap/bpf/bpf_extract.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright (c) 2023 Stephen Hemminger <stephen@networkplumber.org>
-
-import argparse
-import sys
-import struct
-from tempfile import TemporaryFile
-from elftools.elf.elffile import ELFFile
-
-
-def load_sections(elffile):
-    """Get sections of interest from ELF"""
-    result = []
-    parts = [("cls_q", "cls_q_insns"), ("l3_l4", "l3_l4_hash_insns")]
-    for name, tag in parts:
-        section = elffile.get_section_by_name(name)
-        if section:
-            insns = struct.iter_unpack('<BBhL', section.data())
-            result.append([tag, insns])
-    return result
-
-
-def dump_section(name, insns, out):
-    """Dump the array of BPF instructions"""
-    print(f'\nstatic struct bpf_insn {name}[] = {{', file=out)
-    for bpf in insns:
-        code = bpf[0]
-        src = bpf[1] >> 4
-        dst = bpf[1] & 0xf
-        off = bpf[2]
-        imm = bpf[3]
-        print(f'\t{{{code:#04x}, {dst:4d}, {src:4d}, {off:8d}, {imm:#010x}}},',
-              file=out)
-    print('};', file=out)
-
-
-def parse_args():
-    """Parse command line arguments"""
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-s',
-                        '--source',
-                        type=str,
-                        help="original source file")
-    parser.add_argument('-o', '--out', type=str, help="output C file path")
-    parser.add_argument("file",
-                        nargs='+',
-                        help="object file path or '-' for stdin")
-    return parser.parse_args()
-
-
-def open_input(path):
-    """Open the file or stdin"""
-    if path == "-":
-        temp = TemporaryFile()
-        temp.write(sys.stdin.buffer.read())
-        return temp
-    return open(path, 'rb')
-
-
-def write_header(out, source):
-    """Write file intro header"""
-    print("/* SPDX-License-Identifier: BSD-3-Clause", file=out)
-    if source:
-        print(f' * Auto-generated from {source}', file=out)
-    print(" * This not the original source file. Do NOT edit it.", file=out)
-    print(" */\n", file=out)
-
-
-def main():
-    '''program main function'''
-    args = parse_args()
-
-    with open(args.out, 'w',
-              encoding="utf-8") if args.out else sys.stdout as out:
-        write_header(out, args.source)
-        for path in args.file:
-            elffile = ELFFile(open_input(path))
-            sections = load_sections(elffile)
-            for name, insns in sections:
-                dump_section(name, insns, out)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
new file mode 100644
index 0000000000..f2c03a19fd
--- /dev/null
+++ b/drivers/net/tap/bpf/meson.build
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
+
+enable_tap_rss = false
+
+libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+if not libbpf.found()
+    message('net/tap: no RSS support missing libbpf')
+    subdir_done()
+endif
+
+# Debian install this in /usr/sbin which is not in $PATH
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
+if not bpftool.found()
+    message('net/tap: no RSS support missing bpftool')
+    subdir_done()
+endif
+
+clang_supports_bpf = false
+clang = find_program('clang', required: false)
+if clang.found()
+    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus',
+                                     check: false).returncode() == 0
+endif
+
+if not clang_supports_bpf
+    message('net/tap: no RSS support missing clang BPF')
+    subdir_done()
+endif
+
+enable_tap_rss = true
+
+libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
+
+# The include files <linux/bpf.h> and others include <asm/types.h>
+# but <asm/types.h> is not defined for multi-lib environment target.
+# Workaround by using include directoriy from the host build environment.
+machine_name = run_command('uname', '-m').stdout().strip()
+march_include_dir = '/usr/include/' + machine_name + '-linux-gnu'
+
+clang_flags = [
+    '-O2',
+    '-Wall',
+    '-Wextra',
+    '-target',
+    'bpf',
+    '-g',
+    '-c',
+]
+
+bpf_o_cmd = [
+    clang,
+    clang_flags,
+    '-idirafter',
+    libbpf_include_dir,
+    '-idirafter',
+    march_include_dir,
+    '@INPUT@',
+    '-o',
+    '@OUTPUT@'
+]
+
+skel_h_cmd = [
+    bpftool,
+    'gen',
+    'skeleton',
+    '@INPUT@'
+]
+
+tap_rss_o = custom_target(
+    'tap_rss.bpf.o',
+    input: 'tap_rss.c',
+    output: 'tap_rss.o',
+    command: bpf_o_cmd)
+
+tap_rss_skel_h = custom_target(
+    'tap_rss.skel.h',
+    input: tap_rss_o,
+    output: 'tap_rss.skel.h',
+    command: skel_h_cmd,
+    capture: true)
diff --git a/drivers/net/tap/bpf/tap_bpf_program.c b/drivers/net/tap/bpf/tap_bpf_program.c
deleted file mode 100644
index f05aed021c..0000000000
--- a/drivers/net/tap/bpf/tap_bpf_program.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-#include <linux/filter.h>
-
-#include "bpf_api.h"
-#include "bpf_elf.h"
-#include "../tap_rss.h"
-
-/** Create IPv4 address */
-#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
-		(((b) & 0xff) << 16) | \
-		(((c) & 0xff) << 8)  | \
-		((d) & 0xff))
-
-#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
-		((b) & 0xff))
-
-/*
- * The queue number is offset by a unique QUEUE_OFFSET, to distinguish
- * packets that have gone through this rule (skb->cb[1] != 0) from others.
- */
-#define QUEUE_OFFSET		0x7cafe800
-#define PIN_GLOBAL_NS		2
-
-#define KEY_IDX			0
-#define BPF_MAP_ID_KEY	1
-
-struct vlan_hdr {
-	__be16 proto;
-	__be16 tci;
-};
-
-struct bpf_elf_map __attribute__((section("maps"), used))
-map_keys = {
-	.type           =       BPF_MAP_TYPE_HASH,
-	.id             =       BPF_MAP_ID_KEY,
-	.size_key       =       sizeof(__u32),
-	.size_value     =       sizeof(struct rss_key),
-	.max_elem       =       256,
-	.pinning        =       PIN_GLOBAL_NS,
-};
-
-__section("cls_q") int
-match_q(struct __sk_buff *skb)
-{
-	__u32 queue = skb->cb[1];
-	/* queue is set by tap_flow_bpf_cls_q() before load */
-	volatile __u32 q = 0xdeadbeef;
-	__u32 match_queue = QUEUE_OFFSET + q;
-
-	/* printt("match_q$i() queue = %d\n", queue); */
-
-	if (queue != match_queue)
-		return TC_ACT_OK;
-
-	/* queue match */
-	skb->cb[1] = 0;
-	return TC_ACT_UNSPEC;
-}
-
-
-struct ipv4_l3_l4_tuple {
-	__u32    src_addr;
-	__u32    dst_addr;
-	__u16    dport;
-	__u16    sport;
-} __attribute__((packed));
-
-struct ipv6_l3_l4_tuple {
-	__u8        src_addr[16];
-	__u8        dst_addr[16];
-	__u16       dport;
-	__u16       sport;
-} __attribute__((packed));
-
-static const __u8 def_rss_key[TAP_RSS_HASH_KEY_SIZE] = {
-	0xd1, 0x81, 0xc6, 0x2c,
-	0xf7, 0xf4, 0xdb, 0x5b,
-	0x19, 0x83, 0xa2, 0xfc,
-	0x94, 0x3e, 0x1a, 0xdb,
-	0xd9, 0x38, 0x9e, 0x6b,
-	0xd1, 0x03, 0x9c, 0x2c,
-	0xa7, 0x44, 0x99, 0xad,
-	0x59, 0x3d, 0x56, 0xd9,
-	0xf3, 0x25, 0x3c, 0x06,
-	0x2a, 0xdc, 0x1f, 0xfc,
-};
-
-static __u32  __attribute__((always_inline))
-rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
-		__u8 input_len)
-{
-	__u32 i, j, hash = 0;
-#pragma unroll
-	for (j = 0; j < input_len; j++) {
-#pragma unroll
-		for (i = 0; i < 32; i++) {
-			if (input_tuple[j] & (1U << (31 - i))) {
-				hash ^= ((const __u32 *)def_rss_key)[j] << i |
-				(__u32)((uint64_t)
-				(((const __u32 *)def_rss_key)[j + 1])
-					>> (32 - i));
-			}
-		}
-	}
-	return hash;
-}
-
-static int __attribute__((always_inline))
-rss_l3_l4(struct __sk_buff *skb)
-{
-	void *data_end = (void *)(long)skb->data_end;
-	void *data = (void *)(long)skb->data;
-	__u16 proto = (__u16)skb->protocol;
-	__u32 key_idx = 0xdeadbeef;
-	__u32 hash;
-	struct rss_key *rsskey;
-	__u64 off = ETH_HLEN;
-	int j;
-	__u8 *key = 0;
-	__u32 len;
-	__u32 queue = 0;
-	bool mf = 0;
-	__u16 frag_off = 0;
-
-	rsskey = map_lookup_elem(&map_keys, &key_idx);
-	if (!rsskey) {
-		printt("hash(): rss key is not configured\n");
-		return TC_ACT_OK;
-	}
-	key = (__u8 *)rsskey->key;
-
-	/* Get correct proto for 802.1ad */
-	if (skb->vlan_present && skb->vlan_proto == htons(ETH_P_8021AD)) {
-		if (data + ETH_ALEN * 2 + sizeof(struct vlan_hdr) +
-		    sizeof(proto) > data_end)
-			return TC_ACT_OK;
-		proto = *(__u16 *)(data + ETH_ALEN * 2 +
-				   sizeof(struct vlan_hdr));
-		off += sizeof(struct vlan_hdr);
-	}
-
-	if (proto == htons(ETH_P_IP)) {
-		if (data + off + sizeof(struct iphdr) + sizeof(__u32)
-			> data_end)
-			return TC_ACT_OK;
-
-		__u8 *src_dst_addr = data + off + offsetof(struct iphdr, saddr);
-		__u8 *frag_off_addr = data + off + offsetof(struct iphdr, frag_off);
-		__u8 *prot_addr = data + off + offsetof(struct iphdr, protocol);
-		__u8 *src_dst_port = data + off + sizeof(struct iphdr);
-		struct ipv4_l3_l4_tuple v4_tuple = {
-			.src_addr = IPv4(*(src_dst_addr + 0),
-					*(src_dst_addr + 1),
-					*(src_dst_addr + 2),
-					*(src_dst_addr + 3)),
-			.dst_addr = IPv4(*(src_dst_addr + 4),
-					*(src_dst_addr + 5),
-					*(src_dst_addr + 6),
-					*(src_dst_addr + 7)),
-			.sport = 0,
-			.dport = 0,
-		};
-		/** Fetch the L4-payer port numbers only in-case of TCP/UDP
-		 ** and also if the packet is not fragmented. Since fragmented
-		 ** chunks do not have L4 TCP/UDP header.
-		 **/
-		if (*prot_addr == IPPROTO_UDP || *prot_addr == IPPROTO_TCP) {
-			frag_off = PORT(*(frag_off_addr + 0),
-					*(frag_off_addr + 1));
-			mf = frag_off & 0x2000;
-			frag_off = frag_off & 0x1fff;
-			if (mf == 0 && frag_off == 0) {
-				v4_tuple.sport = PORT(*(src_dst_port + 0),
-						*(src_dst_port + 1));
-				v4_tuple.dport = PORT(*(src_dst_port + 2),
-						*(src_dst_port + 3));
-			}
-		}
-		__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV4_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
-	} else if (proto == htons(ETH_P_IPV6)) {
-		if (data + off + sizeof(struct ipv6hdr) +
-					sizeof(__u32) > data_end)
-			return TC_ACT_OK;
-		__u8 *src_dst_addr = data + off +
-					offsetof(struct ipv6hdr, saddr);
-		__u8 *src_dst_port = data + off +
-					sizeof(struct ipv6hdr);
-		__u8 *next_hdr = data + off +
-					offsetof(struct ipv6hdr, nexthdr);
-
-		struct ipv6_l3_l4_tuple v6_tuple;
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.src_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + j));
-		for (j = 0; j < 4; j++)
-			*((uint32_t *)&v6_tuple.dst_addr + j) =
-				__builtin_bswap32(*((uint32_t *)
-						src_dst_addr + 4 + j));
-
-		/** Fetch the L4 header port-numbers only if next-header
-		 * is TCP/UDP **/
-		if (*next_hdr == IPPROTO_UDP || *next_hdr == IPPROTO_TCP) {
-			v6_tuple.sport = PORT(*(src_dst_port + 0),
-				      *(src_dst_port + 1));
-			v6_tuple.dport = PORT(*(src_dst_port + 2),
-				      *(src_dst_port + 3));
-		} else {
-			v6_tuple.sport = 0;
-			v6_tuple.dport = 0;
-		}
-
-		__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
-		if (rsskey->hash_fields & (1 << HASH_FIELD_IPV6_L3))
-			input_len--;
-		hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
-	} else {
-		return TC_ACT_PIPE;
-	}
-
-	queue = rsskey->queues[(hash % rsskey->nb_queues) &
-				       (TAP_MAX_QUEUES - 1)];
-	skb->cb[1] = QUEUE_OFFSET + queue;
-	/* printt(">>>>> rss_l3_l4 hash=0x%x queue=%u\n", hash, queue); */
-
-	return TC_ACT_RECLASSIFY;
-}
-
-#define RSS(L)						\
-	__section(#L) int				\
-		L ## _hash(struct __sk_buff *skb)	\
-	{						\
-		return rss_ ## L (skb);			\
-	}
-
-RSS(l3_l4)
-
-BPF_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/tap/bpf/tap_rss.c b/drivers/net/tap/bpf/tap_rss.c
new file mode 100644
index 0000000000..025b831b5c
--- /dev/null
+++ b/drivers/net/tap/bpf/tap_rss.c
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ * Copyright 2017 Mellanox Technologies, Ltd
+ */
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "../tap_rss.h"
+
+/*
+ * This map provides configuration information about flows which need BPF RSS.
+ *
+ * The hash is indexed by the skb mark.
+ */
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u32));
+	__uint(value_size, sizeof(struct rss_key));
+	__uint(max_entries, TAP_RSS_MAX);
+} rss_map SEC(".maps");
+
+#define IP_MF		0x2000		/** IP header Flags **/
+#define IP_OFFSET	0x1FFF		/** IP header fragment offset **/
+
+/*
+ * Compute Toeplitz hash over the input tuple.
+ * This is same as rte_softrss_be in lib/hash
+ * but loop needs to be setup to match BPF restrictions.
+ */
+static __always_inline __u32
+softrss_be(const __u32 *input_tuple, __u32 input_len, const __u32 *key)
+{
+	__u32 i, j, hash = 0;
+
+#pragma unroll
+	for (j = 0; j < input_len; j++) {
+#pragma unroll
+		for (i = 0; i < 32; i++) {
+			if (input_tuple[j] & (1U << (31 - i)))
+				hash ^= key[j] << i | key[j + 1] >> (32 - i);
+		}
+	}
+	return hash;
+}
+
+/*
+ * Compute RSS hash for IPv4 packet.
+ * return in 0 if RSS not specified
+ */
+static __always_inline __u32
+parse_ipv4(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct iphdr iph;
+	__u32 off = 0;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &iph, sizeof(iph), BPF_HDR_START_NET))
+		return 0;	/* no IP header present */
+
+	struct {
+		__u32    src_addr;
+		__u32    dst_addr;
+		__u16    dport;
+		__u16    sport;
+	} v4_tuple = {
+		.src_addr = bpf_ntohl(iph.saddr),
+		.dst_addr = bpf_ntohl(iph.daddr),
+	};
+
+	/* If only calculating L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV4_L3))
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32) - 1, key);
+
+	/* If packet is fragmented then no L4 hash is possible */
+	if ((iph.frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
+		return 0;
+
+	/* Do RSS on UDP or TCP protocols */
+	if (iph.protocol == IPPROTO_UDP || iph.protocol == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		off += iph.ihl * 4;
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0; /* TCP or UDP header missing */
+
+		v4_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v4_tuple.dport = bpf_ntohs(src_dst_port[1]);
+		return softrss_be((__u32 *)&v4_tuple, sizeof(v4_tuple) / sizeof(__u32), key);
+	}
+
+	/* Other protocol */
+	return 0;
+}
+
+/*
+ * Parse Ipv6 extended headers, update offset and return next proto.
+ * returns next proto on success, -1 on malformed header
+ */
+static __always_inline int
+skip_ip6_ext(__u16 proto, const struct __sk_buff *skb, __u32 *off, int *frag)
+{
+	struct ext_hdr {
+		__u8 next_hdr;
+		__u8 len;
+	} xh;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+#pragma unroll
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += (xh.len + 1) * 8;
+			proto = xh.next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			if (bpf_skb_load_bytes_relative(skb, *off, &xh, sizeof(xh),
+							BPF_HDR_START_NET))
+				return -1;
+
+			*off += 8;
+			proto = xh.next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		default:
+			return proto;
+		}
+	}
+
+	/* too many extension headers give up */
+	return -1;
+}
+
+/*
+ * Compute RSS hash for IPv6 packet.
+ * return in 0 if RSS not specified
+ */
+static __always_inline __u32
+parse_ipv6(const struct __sk_buff *skb, __u32 hash_type, const __u32 *key)
+{
+	struct {
+		__u32       src_addr[4];
+		__u32       dst_addr[4];
+		__u16       dport;
+		__u16       sport;
+	} v6_tuple = { };
+	struct ipv6hdr ip6h;
+	__u32 off = 0, j;
+	int proto, frag;
+
+	if (bpf_skb_load_bytes_relative(skb, off, &ip6h, sizeof(ip6h), BPF_HDR_START_NET))
+		return 0;	/* missing IPv6 header */
+
+#pragma unroll
+	for (j = 0; j < 4; j++) {
+		v6_tuple.src_addr[j] = bpf_ntohl(ip6h.saddr.in6_u.u6_addr32[j]);
+		v6_tuple.dst_addr[j] = bpf_ntohl(ip6h.daddr.in6_u.u6_addr32[j]);
+	}
+
+	/* If only doing L3 hash, do it now */
+	if (hash_type & (1 << HASH_FIELD_IPV6_L3))
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32) - 1, key);
+
+	/* Skip extension headers if present */
+	off += sizeof(ip6h);
+	proto = skip_ip6_ext(ip6h.nexthdr, skb, &off, &frag);
+	if (proto < 0)
+		return 0;
+
+	/* If packet is a fragment then no L4 hash is possible */
+	if (frag)
+		return 0;
+
+	/* Do RSS on UDP or TCP */
+	if (proto == IPPROTO_UDP || proto == IPPROTO_TCP) {
+		__u16 src_dst_port[2];
+
+		if (bpf_skb_load_bytes_relative(skb, off, &src_dst_port, sizeof(src_dst_port),
+						BPF_HDR_START_NET))
+			return 0;
+
+		v6_tuple.sport = bpf_ntohs(src_dst_port[0]);
+		v6_tuple.dport = bpf_ntohs(src_dst_port[1]);
+
+		return softrss_be((__u32 *)&v6_tuple, sizeof(v6_tuple) / sizeof(__u32), key);
+	}
+
+	return 0;
+}
+
+/*
+ * Scale value to be into range [0, n)
+ * Assumes val is large (ie hash covers whole u32 range)
+ */
+static __always_inline __u32
+reciprocal_scale(__u32 val, __u32 n)
+{
+	return (__u32)(((__u64)val * n) >> 32);
+}
+
+/*
+ * When this BPF program is run by tc from the filter classifier,
+ * it is able to read skb metadata and packet data.
+ *
+ * For packets where RSS is not possible, then just return TC_ACT_OK.
+ * When RSS is desired, change the skb->queue_mapping and set TC_ACT_PIPE
+ * to continue processing.
+ *
+ * This should be BPF_PROG_TYPE_SCHED_ACT so section needs to be "action"
+ */
+SEC("action") int
+rss_flow_action(struct __sk_buff *skb)
+{
+	const struct rss_key *rsskey;
+	const __u32 *key;
+	__be16 proto;
+	__u32 mark;
+	__u32 hash;
+	__u16 queue;
+
+	__builtin_preserve_access_index(({
+		mark = skb->mark;
+		proto = skb->protocol;
+	}));
+
+	/* Lookup RSS configuration for that BPF class */
+	rsskey = bpf_map_lookup_elem(&rss_map, &mark);
+	if (rsskey == NULL)
+		return TC_ACT_OK;
+
+	key = (const __u32 *)rsskey->key;
+
+	if (proto == bpf_htons(ETH_P_IP))
+		hash = parse_ipv4(skb, rsskey->hash_fields, key);
+	else if (proto == bpf_htons(ETH_P_IPV6))
+		hash = parse_ipv6(skb, rsskey->hash_fields, key);
+	else
+		hash = 0;
+
+	if (hash == 0)
+		return TC_ACT_OK;
+
+	/* Fold hash to the number of queues configured */
+	queue = reciprocal_scale(hash, rsskey->nb_queues);
+
+	__builtin_preserve_access_index(({
+		skb->queue_mapping = queue;
+	}));
+	return TC_ACT_PIPE;
+}
+
+char _license[] SEC("license") = "Dual BSD/GPL";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 07/12] net/tap: use libbpf to load new BPF program
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (5 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 06/12] net/tap: rewrite the RSS BPF program Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 08/12] net/tap: remove no longer used files Stephen Hemminger
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It also fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Bugzilla ID: 1329

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  36 ++-
 drivers/net/tap/meson.build     |  35 ++-
 drivers/net/tap/rte_eth_tap.c   |  14 +-
 drivers/net/tap/rte_eth_tap.h   |   6 +-
 drivers/net/tap/tap_flow.c      | 416 ++++++++------------------------
 drivers/net/tap/tap_flow.h      |  17 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 8 files changed, 165 insertions(+), 373 deletions(-)

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..45e8c3b498 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -1,17 +1,26 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright 2024 Stephen Hemminger <stephen@networkplumber.org>
 
-enable_tap_rss = false
-
-libbpf = dependency('libbpf', required: false, method: 'pkg-config')
+# Loading BPF requires libbpf
+# and the bpf_map__XXX API's were introduced in 0.8.0
+libbpf = dependency('libbpf', version: '>= 1.0',
+                    required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu versions have non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@ clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
@@ -67,6 +77,22 @@ skel_h_cmd = [
     '@INPUT@'
 ]
 
+vmlinux_h_cmd = [
+    bpftool,
+    'btf',
+    'dump',
+    'file',
+    '/sys/kernel/btf/vmlinux',
+    'format',
+    'c'
+]
+
+vmlinux_h = custom_target(
+    'vmlinux.h',
+    output: 'vmlinux.h',
+    command: vmlinux_h_cmd,
+    capture: true)
+
 tap_rss_o = custom_target(
     'tap_rss.bpf.o',
     input: 'tap_rss.c',
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 66647a1c62..26074059fa 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -5,36 +5,33 @@ if not is_linux
     build = false
     reason = 'only supported on Linux'
 endif
+
 sources = files(
         'rte_eth_tap.c',
         'tap_intr.c',
         'tap_netlink.c',
 )
 
+deps = ['bus_vdev', 'gso', 'hash']
+
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
+
+require_iova_in_mbuf = false
+
 if cc.has_header_symbol('linux/pkt_cls.h', 'TCA_FLOWER_ACT')
     cflags += '-DHAVE_TCA_FLOWER'
     sources += files(
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_tcmsgs.c',
     )
-endif
-
-deps = ['bus_vdev', 'gso', 'hash']
 
-cflags += '-DTAP_MAX_QUEUES=16'
-
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+    enable_tap_rss = false
 
-require_iova_in_mbuf = false
+    subdir('bpf')
+    if enable_tap_rss
+        cflags += '-DHAVE_BPF_RSS'
+        ext_deps += libbpf
+        sources += tap_rss_skel_h
+    endif
+endif
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 9058a47295..d847565073 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1140,6 +1140,7 @@ tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 #endif
 
@@ -1949,6 +1950,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+
 #ifdef HAVE_TCA_FLOWER
 	pmd->nlsk_fd = -1;
 #endif
@@ -2031,13 +2033,6 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
-	pmd->if_index = if_nametoindex(pmd->name);
-	if (!pmd->if_index) {
-		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
-		goto disable_rte_flow;
-	}
-
-
 #ifdef HAVE_TCA_FLOWER
 	/*
 	 * Set up everything related to rte_flow:
@@ -2053,6 +2048,11 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			pmd->name);
 		goto disable_rte_flow;
 	}
+	pmd->if_index = if_nametoindex(pmd->name);
+	if (!pmd->if_index) {
+		TAP_LOG(ERR, "%s: failed to get if_index.", pmd->name);
+		goto disable_rte_flow;
+	}
 	if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
 		TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
 			pmd->name);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index af18b29090..ce4322ad04 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -81,10 +81,8 @@ struct pmd_internals {
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
+
+	struct tap_rss *rss;		  /* BPF program */
 
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 5a5a4ea048..679cffe528 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,25 +15,19 @@
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -41,8 +35,6 @@ enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -69,12 +61,16 @@ struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
+#ifdef HAVE_BPF_RSS
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
+#endif
 	};
 };
 
@@ -112,13 +108,12 @@ tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -853,11 +848,13 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
+#ifdef HAVE_BPF_RSS
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
 			   strlen(adata->bpf.annotation) + 1,
@@ -865,7 +862,12 @@ add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_PARMS,
 			   sizeof(adata->bpf.bpf),
 			   &adata->bpf.bpf);
+#else
+		TAP_LOG(ERR, "Internal error: bpf requested but not supported");
+		return -1;
+#endif
 	} else {
+		TAP_LOG(ERR, "Internal error: unknown action: %s", adata->id);
 		return -1;
 	}
 	tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
@@ -1104,8 +1106,7 @@ priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1135,6 +1136,7 @@ priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1143,13 +1145,14 @@ priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1246,26 +1249,17 @@ tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1733,14 +1727,18 @@ tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1755,225 +1753,32 @@ static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
-
-		return -ENOTSUP;
-	}
-
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
+	int err;
 
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2006,9 +1811,11 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2057,34 +1864,24 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2093,47 +1890,28 @@ static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..8b19347a93 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,11 +45,6 @@ enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
-
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
@@ -57,10 +56,6 @@ int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..9411626661 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,10 @@
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
+#ifdef HAVE_BPF_RSS
 #include <linux/tc_act/tc_bpf.h>
 #endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 08/12] net/tap: remove no longer used files
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (6 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 07/12] net/tap: use libbpf to load new " Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 09/12] net/tap: simplify internals Stephen Hemminger
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The BPF api was replaced by use of libbpf.
And the BPF instruction header was replaced by the skeleton.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/tap_bpf_api.c   |  196 ----
 drivers/net/tap/tap_bpf_insns.h | 1741 -------------------------------
 2 files changed, 1937 deletions(-)
 delete mode 100644 drivers/net/tap/tap_bpf_api.c
 delete mode 100644 drivers/net/tap/tap_bpf_insns.h

diff --git a/drivers/net/tap/tap_bpf_api.c b/drivers/net/tap/tap_bpf_api.c
deleted file mode 100644
index 9e05e2ddf1..0000000000
--- a/drivers/net/tap/tap_bpf_api.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2017 Mellanox Technologies, Ltd
- */
-
-#include <unistd.h>
-#include <syscall.h>
-#include <linux/bpf.h>
-
-#include <tap_flow.h>
-#include <tap_autoconf.h>
-
-#include <tap_bpf_insns.h>
-
-
-static int bpf_load(enum bpf_prog_type type, const struct bpf_insn *insns,
-		size_t insns_cnt, const char *license);
-
-/**
- * Load BPF program (section cls_q) into the kernel and return a bpf fd
- *
- * @param queue_idx
- *   Queue index matching packet cb
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_cls_q(__u32 queue_idx)
-{
-	cls_q_insns[1].imm = queue_idx;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_CLS,
-		(struct bpf_insn *)cls_q_insns,
-		RTE_DIM(cls_q_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Load BPF program (section l3_l4) into the kernel and return a bpf fd.
- *
- * @param[in] key_idx
- *   RSS MAP key index
- *
- * @param[in] map_fd
- *   BPF RSS map file descriptor
- *
- * @return
- *   -1 if the BPF program couldn't be loaded. An fd (int) otherwise.
- */
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd)
-{
-	l3_l4_hash_insns[4].imm = key_idx;
-	l3_l4_hash_insns[9].imm = map_fd;
-
-	return bpf_load(BPF_PROG_TYPE_SCHED_ACT,
-		(struct bpf_insn *)l3_l4_hash_insns,
-		RTE_DIM(l3_l4_hash_insns),
-		"Dual BSD/GPL");
-}
-
-/**
- * Helper function to convert a pointer to unsigned 64 bits
- *
- * @param[in] ptr
- *   pointer to address
- *
- * @return
- *   64 bit unsigned long type of pointer address
- */
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-	return (__u64)(unsigned long)ptr;
-}
-
-/**
- * Call BPF system call
- *
- * @param[in] cmd
- *   BPF command for program loading, map creation, map entry update, etc
- *
- * @param[in] attr
- *   System call attributes relevant to system call command
- *
- * @param[in] size
- *   size of attr parameter
- *
- * @return
- *   -1 if BPF system call failed, 0 otherwise
- */
-static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-			unsigned int size)
-{
-#ifdef __NR_bpf
-	return syscall(__NR_bpf, cmd, attr, size);
-#else
-	TAP_LOG(ERR, "No bpf syscall, kernel headers too old?\n");
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-/**
- * Load BPF instructions to kernel
- *
- * @param[in] type
- *   BPF program type: classifier or action
- *
- * @param[in] insns
- *   Array of BPF instructions (equivalent to BPF instructions)
- *
- * @param[in] insns_cnt
- *   Number of BPF instructions (size of array)
- *
- * @param[in] license
- *   License string that must be acknowledged by the kernel
- *
- * @return
- *   -1 if the BPF program couldn't be loaded, fd (file descriptor) otherwise
- */
-static int bpf_load(enum bpf_prog_type type,
-		  const struct bpf_insn *insns,
-		  size_t insns_cnt,
-		  const char *license)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.prog_type = type;
-	attr.insn_cnt = (__u32)insns_cnt;
-	attr.insns = ptr_to_u64(insns);
-	attr.license = ptr_to_u64(license);
-	attr.log_buf = ptr_to_u64(NULL);
-	attr.log_level = 0;
-	attr.kern_version = 0;
-
-	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-}
-
-/**
- * Create BPF map for RSS rules
- *
- * @param[in] key_size
- *   map RSS key size
- *
- * @param[in] value_size
- *   Map RSS value size
- *
- * @param[in] max_entries
- *   Map max number of RSS entries (limit on max RSS rules)
- *
- * @return
- *   -1 if BPF map couldn't be created, map fd otherwise
- */
-int tap_flow_bpf_rss_map_create(unsigned int key_size,
-		unsigned int value_size,
-		unsigned int max_entries)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-	attr.map_type    = BPF_MAP_TYPE_HASH;
-	attr.key_size    = key_size;
-	attr.value_size  = value_size;
-	attr.max_entries = max_entries;
-
-	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-/**
- * Update RSS entry in BPF map
- *
- * @param[in] fd
- *   RSS map fd
- *
- * @param[in] key
- *   Pointer to RSS key whose entry is updated
- *
- * @param[in] value
- *   Pointer to RSS new updated value
- *
- * @return
- *   -1 if RSS entry failed to be updated, 0 otherwise
- */
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value)
-{
-	union bpf_attr attr = {};
-
-	bzero(&attr, sizeof(attr));
-
-	attr.map_type = BPF_MAP_TYPE_HASH;
-	attr.map_fd = fd;
-	attr.key = ptr_to_u64(key);
-	attr.value = ptr_to_u64(value);
-	attr.flags = BPF_ANY;
-
-	return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
diff --git a/drivers/net/tap/tap_bpf_insns.h b/drivers/net/tap/tap_bpf_insns.h
deleted file mode 100644
index cdf2febf05..0000000000
--- a/drivers/net/tap/tap_bpf_insns.h
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Auto-generated from tap_bpf_program.c
- * This not the original source file. Do NOT edit it.
- */
-
-static struct bpf_insn cls_q_insns[] = {
-	{0x61,    2,    1,       52, 0x00000000},
-	{0x18,    3,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    3,       -4, 0x00000000},
-	{0xb7,    0,    0,        0, 0x00000000},
-	{0x61,    3,   10,       -4, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x5d,    2,    3,        4, 0x00000000},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x63,    1,    2,       52, 0x00000000},
-	{0x18,    0,    0,        0, 0xffffffff},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-
-static struct bpf_insn l3_l4_hash_insns[] = {
-	{0xbf,    7,    1,        0, 0x00000000},
-	{0x61,    6,    7,       16, 0x00000000},
-	{0x61,    8,    7,       76, 0x00000000},
-	{0x61,    9,    7,       80, 0x00000000},
-	{0x18,    1,    0,        0, 0xdeadbeef},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x63,   10,    1,       -4, 0x00000000},
-	{0xbf,    2,   10,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0xfffffffc},
-	{0x18,    1,    0,        0, 0x00000000},
-	{0x00,    0,    0,        0, 0x00000000},
-	{0x85,    0,    0,        0, 0x00000001},
-	{0x55,    0,    0,       21, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000a64},
-	{0x6b,   10,    1,      -16, 0x00000000},
-	{0x18,    1,    0,        0, 0x69666e6f},
-	{0x00,    0,    0,        0, 0x65727567},
-	{0x7b,   10,    1,      -24, 0x00000000},
-	{0x18,    1,    0,        0, 0x6e207369},
-	{0x00,    0,    0,        0, 0x6320746f},
-	{0x7b,   10,    1,      -32, 0x00000000},
-	{0x18,    1,    0,        0, 0x20737372},
-	{0x00,    0,    0,        0, 0x2079656b},
-	{0x7b,   10,    1,      -40, 0x00000000},
-	{0x18,    1,    0,        0, 0x68736168},
-	{0x00,    0,    0,        0, 0x203a2928},
-	{0x7b,   10,    1,      -48, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0x73,   10,    7,      -14, 0x00000000},
-	{0xbf,    1,   10,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0xffffffd0},
-	{0xb7,    2,    0,        0, 0x00000023},
-	{0x85,    0,    0,        0, 0x00000006},
-	{0x05,    0,    0,     1680, 0x00000000},
-	{0xb7,    1,    0,        0, 0x0000000e},
-	{0x61,    2,    7,       20, 0x00000000},
-	{0x15,    2,    0,       10, 0x00000000},
-	{0x61,    2,    7,       28, 0x00000000},
-	{0x55,    2,    0,        8, 0x0000a888},
-	{0xbf,    2,    7,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000012},
-	{0x2d,    1,    9,     1670, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000012},
-	{0x69,    6,    8,       16, 0x00000000},
-	{0xbf,    7,    2,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x0000ffff},
-	{0x7b,   10,    7,      -56, 0x00000000},
-	{0x15,    6,    0,      443, 0x0000dd86},
-	{0xb7,    7,    0,        0, 0x00000003},
-	{0x55,    6,    0,     1662, 0x00000008},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x00000018},
-	{0x2d,    1,    9,     1657, 0x00000000},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x71,    3,    8,       12, 0x00000000},
-	{0x71,    2,    8,        9, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000011},
-	{0x55,    2,    0,       21, 0x00000006},
-	{0x71,    2,    8,        7, 0x00000000},
-	{0x71,    4,    8,        6, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000008},
-	{0x57,    5,    0,        0, 0x00001f00},
-	{0x4f,    5,    2,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x4f,    4,    5,        0, 0x00000000},
-	{0x55,    4,    0,       12, 0x00000000},
-	{0xbf,    2,    8,        0, 0x00000000},
-	{0x07,    2,    0,        0, 0x00000014},
-	{0x71,    4,    2,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    2,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    2,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    2,    2,        2, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000008},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0x65,    4,    0,        1, 0xffffffff},
-	{0xb7,    7,    0,        0, 0x2cc681d1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x598d03a2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb31a0745},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x66340e8a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcc681d15},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x98d03a2b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x31a07456},
-	{0x71,    4,    8,       13, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc681d15b},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a07456f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x340e8ade},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x681d15bd},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa07456f6},
-	{0x71,    3,    8,       14, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x40e8aded},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x81d15bdb},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x03a2b7b7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x07456f6f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0e8adedf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1d15bdbf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3a2b7b7e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7456f6fd},
-	{0x71,    4,    8,       15, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd15bdbf4},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x15bdbf4f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2b7b7e9e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x56f6fd3d},
-	{0x71,    3,    8,       16, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xadedfa7b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000038},
-	{0xc7,    4,    0,        0, 0x00000038},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000004},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000002},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6fd3dff},
-	{0x71,    4,    8,       17, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xedfa7bfe},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0x71,    3,    8,       18, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x67,    6,    0,        0, 0x00000038},
-	{0xc7,    6,    0,        0, 0x00000038},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf4f7fca2},
-	{0x6d,    2,    6,        1, 0x00000000},
-	{0xbf,    4,    5,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe9eff945},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd3dff28a},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa7bfe514},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x4f7fca28},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9eff9450},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3dff28a0},
-	{0x71,    5,    8,       19, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7bfe5141},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000038},
-	{0xc7,    3,    0,        0, 0x00000038},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf7fca283},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    7,    4,        0, 0x00000000},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xeff94506},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xdff28a0c},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xbfe51418},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7fca2831},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000004},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff945063},
-	{0xbf,    3,    5,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000002},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xff28a0c6},
-	{0x57,    5,    0,        0, 0x00000001},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfe51418c},
-	{0xbf,    4,    1,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000020},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    3,    7,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9450633},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf28a0c67},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe51418ce},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xca28319d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9450633b},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28a0c676},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x51418ced},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa28319db},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x450633b6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8a0c676c},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1418ced8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x28319db1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x50633b63},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xa0c676c6},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x418ced8d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8319db1a},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0633b634},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c676c68},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18ced8d1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x319db1a3},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x633b6347},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc676c68f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8ced8d1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x19db1a3e},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x33b6347d},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x676c68fa},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xced8d1f4},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9db1a3e9},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3b6347d2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x76c68fa5},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,     1194, 0x00000000},
-	{0xa7,    3,    0,        0, 0xed8d1f4a},
-	{0x05,    0,    0,     1192, 0x00000000},
-	{0x0f,    8,    1,        0, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000000},
-	{0xbf,    1,    8,        0, 0x00000000},
-	{0x07,    1,    0,        0, 0x0000002c},
-	{0x2d,    1,    9,     1216, 0x00000000},
-	{0x61,    2,    8,        8, 0x00000000},
-	{0xdc,    2,    0,        0, 0x00000040},
-	{0xc7,    2,    0,        0, 0x00000020},
-	{0x71,    3,    8,        6, 0x00000000},
-	{0x15,    3,    0,        2, 0x00000011},
-	{0xb7,    1,    0,        0, 0x00000000},
-	{0x55,    3,    0,       12, 0x00000006},
-	{0xbf,    3,    8,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x00000028},
-	{0x71,    4,    3,        0, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x71,    1,    3,        1, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000010},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    4,    3,        3, 0x00000000},
-	{0x4f,    1,    4,        0, 0x00000000},
-	{0x71,    3,    3,        2, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000008},
-	{0x4f,    1,    3,        0, 0x00000000},
-	{0xbf,    4,    2,        0, 0x00000000},
-	{0x77,    4,    0,        0, 0x0000001f},
-	{0x57,    4,    0,        0, 0x2cc681d1},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x598d03a2},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb31a0745},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x66340e8a},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcc681d15},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x98d03a2b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x31a07456},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6340e8ad},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc681d15b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8d03a2b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1a07456f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x340e8ade},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x681d15bd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd03a2b7b},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa07456f6},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x40e8aded},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x81d15bdb},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x03a2b7b7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x07456f6f},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x0e8adedf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1d15bdbf},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3a2b7b7e},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7456f6fd},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xe8adedfa},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd15bdbf4},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xa2b7b7e9},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x456f6fd3},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8adedfa7},
-	{0xbf,    3,    2,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x15bdbf4f},
-	{0x61,    3,    8,       12, 0x00000000},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2b7b7e9e},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    2,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56f6fd3d},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    2,    0,        0, 0x00000001},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xadedfa7b},
-	{0xb7,    2,    0,        0, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x5bdbf4f7},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7b7e9ef},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6f6fd3df},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdedfa7bf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbdbf4f7f},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7b7e9eff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf6fd3dff},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xedfa7bfe},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdbf4f7fc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb7e9eff9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6fd3dff2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdfa7bfe5},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbf4f7fca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7e9eff94},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfd3dff28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa7bfe51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4f7fca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe9eff945},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd3dff28a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa7bfe514},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4f7fca28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9eff9450},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3dff28a0},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7bfe5141},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf7fca283},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xeff94506},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdff28a0c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xbfe51418},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7fca2831},
-	{0x61,    4,    8,       16, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff945063},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xff28a0c6},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfe51418c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfca28319},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf9450633},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf28a0c67},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe51418ce},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca28319d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9450633b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28a0c676},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x51418ced},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa28319db},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x450633b6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8a0c676c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1418ced8},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x28319db1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x50633b63},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa0c676c6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x418ced8d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8319db1a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0633b634},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x0c676c68},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x18ced8d1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x319db1a3},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x633b6347},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc676c68f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8ced8d1f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x19db1a3e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x33b6347d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x676c68fa},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xced8d1f4},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9db1a3e9},
-	{0x61,    3,    8,       20, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3b6347d2},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x76c68fa5},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xed8d1f4a},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0xdb1a3e94},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb6347d28},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6c68fa51},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd8d1f4a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb1a3e946},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6347d28d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc68fa51a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d1f4a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1a3e946b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x347d28d7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x68fa51ae},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1f4a35c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa3e946b9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x47d28d73},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8fa51ae7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1f4a35cf},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3e946b9e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7d28d73c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xfa51ae78},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf4a35cf1},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe946b9e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd28d73c7},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa51ae78e},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4a35cf1c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x946b9e38},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x28d73c71},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x51ae78e3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35cf1c6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b9e38d},
-	{0x61,    4,    8,       24, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d73c71b},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ae78e36},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35cf1c6c},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6b9e38d9},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd73c71b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xae78e364},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5cf1c6c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb9e38d92},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x73c71b25},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe78e364b},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcf1c6c96},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9e38d92c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3c71b259},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x78e364b2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf1c6c964},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe38d92c9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc71b2593},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8e364b27},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1c6c964e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x38d92c9c},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x71b25938},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xe364b270},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc6c964e0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x8d92c9c0},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x1b259380},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x364b2700},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6c964e01},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd92c9c03},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb2593807},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x64b2700f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xc964e01e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x92c9c03d},
-	{0x61,    3,    8,       28, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2593807a},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4b2700f4},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x964e01e8},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2c9c03d1},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    5,    7,        0, 0x00000000},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x40000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x593807a3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x20000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xb2700f46},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x10000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x64e01e8d},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x08000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc9c03d1a},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x04000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x93807a35},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x02000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x2700f46b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x01000000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x4e01e8d6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00800000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x9c03d1ad},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00400000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3807a35b},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00200000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x700f46b6},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00100000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe01e8d6c},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00080000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xc03d1ad9},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00040000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x807a35b3},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00020000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x00f46b66},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00010000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x01e8d6cc},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00008000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x03d1ad99},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00004000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x07a35b32},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00002000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x0f46b665},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00001000},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1e8d6cca},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000800},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x3d1ad994},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000400},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x7a35b328},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000200},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xf46b6651},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000100},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xe8d6cca2},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000080},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd1ad9944},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000040},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xa35b3289},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000020},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x46b66512},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000010},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x8d6cca25},
-	{0xbf,    4,    3,        0, 0x00000000},
-	{0x57,    4,    0,        0, 0x00000008},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x1ad9944a},
-	{0x61,    4,    8,       32, 0x00000000},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000004},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x35b32894},
-	{0xdc,    4,    0,        0, 0x00000040},
-	{0xbf,    6,    3,        0, 0x00000000},
-	{0x57,    6,    0,        0, 0x00000002},
-	{0x15,    6,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0x6b665129},
-	{0xc7,    4,    0,        0, 0x00000020},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    5,    0,        0, 0xd6cca253},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xa7,    7,    0,        0, 0xad9944a7},
-	{0x6d,    2,    4,        1, 0x00000000},
-	{0xbf,    7,    5,        0, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x40000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5b32894f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x20000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb665129f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x10000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x6cca253e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x08000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xd9944a7d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x04000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xb32894fb},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x02000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x665129f6},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x01000000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xcca253ec},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00800000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9944a7d9},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00400000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x32894fb2},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00200000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x65129f65},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00100000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xca253eca},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00080000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x944a7d95},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00040000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x2894fb2a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00020000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x5129f655},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00010000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa253ecab},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00008000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x44a7d956},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00004000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x894fb2ac},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00002000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x129f6558},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00001000},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x253ecab1},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000800},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4a7d9563},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000400},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x94fb2ac7},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000200},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x29f6558f},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000100},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x53ecab1e},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000080},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xa7d9563d},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000040},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x4fb2ac7a},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000020},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x9f6558f5},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000010},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x3ecab1ea},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x00000008},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0x7d9563d5},
-	{0x61,    3,    8,       36, 0x00000000},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xfb2ac7ab},
-	{0xdc,    3,    0,        0, 0x00000040},
-	{0xbf,    5,    4,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xf6558f56},
-	{0xc7,    3,    0,        0, 0x00000020},
-	{0x57,    4,    0,        0, 0x00000001},
-	{0x15,    4,    0,        1, 0x00000000},
-	{0xa7,    7,    0,        0, 0xecab1eac},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd9563d59},
-	{0x6d,    2,    3,        1, 0x00000000},
-	{0xbf,    4,    7,        0, 0x00000000},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x40000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb2ac7ab2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x20000000},
-	{0x79,    6,   10,      -56, 0x00000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6558f564},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x10000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xcab1eac8},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x08000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9563d590},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x04000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x2ac7ab20},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x02000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x558f5641},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x01000000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab1eac83},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00800000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x563d5906},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00400000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac7ab20c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00200000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x58f56418},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00100000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb1eac831},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00080000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x63d59063},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00040000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc7ab20c7},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00020000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x8f56418f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00010000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x1eac831e},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00008000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x3d59063c},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00004000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x7ab20c78},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00002000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xf56418f0},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00001000},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xeac831e1},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000800},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xd59063c2},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000400},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xab20c784},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000200},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x56418f09},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000100},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xac831e12},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000080},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x59063c25},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000040},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xb20c784b},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000020},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x6418f097},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000010},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0xc831e12f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000008},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x9063c25f},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000004},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x20c784be},
-	{0xbf,    5,    3,        0, 0x00000000},
-	{0x57,    5,    0,        0, 0x00000002},
-	{0x15,    5,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x418f097c},
-	{0x57,    3,    0,        0, 0x00000001},
-	{0x15,    3,    0,        1, 0x00000000},
-	{0xa7,    4,    0,        0, 0x831e12f9},
-	{0xbf,    5,    1,        0, 0x00000000},
-	{0x67,    5,    0,        0, 0x00000020},
-	{0xc7,    5,    0,        0, 0x00000020},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xa7,    3,    0,        0, 0x063c25f3},
-	{0x6d,    2,    5,        1, 0x00000000},
-	{0xbf,    3,    4,        0, 0x00000000},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x40000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x0c784be7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x20000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x18f097cf},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x10000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x31e12f9f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x08000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x63c25f3f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x04000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc784be7f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x02000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x8f097cff},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x01000000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x1e12f9fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00800000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3c25f3fc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00400000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x784be7f8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00200000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf097cff0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00100000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe12f9fe0},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00080000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xc25f3fc1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00040000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x84be7f83},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00020000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x097cff07},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00010000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x12f9fe0f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00008000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x25f3fc1f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00004000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x4be7f83f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00002000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x97cff07f},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00001000},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x2f9fe0fe},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000800},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x5f3fc1fd},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000400},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xbe7f83fb},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000200},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7cff07f7},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000100},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf9fe0fee},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000080},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xf3fc1fdc},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000040},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xe7f83fb8},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000020},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xcff07f70},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000010},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x9fe0fee1},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000008},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x3fc1fdc2},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000004},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0x7f83fb85},
-	{0xbf,    2,    1,        0, 0x00000000},
-	{0x57,    2,    0,        0, 0x00000002},
-	{0x15,    2,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xff07f70a},
-	{0x57,    1,    0,        0, 0x00000001},
-	{0x15,    1,    0,        1, 0x00000000},
-	{0xa7,    3,    0,        0, 0xfe0fee15},
-	{0x71,    1,    0,      201, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      200, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      202, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    4,    0,      203, 0x00000000},
-	{0x67,    4,    0,        0, 0x00000018},
-	{0x4f,    4,    2,        0, 0x00000000},
-	{0x4f,    4,    1,        0, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000020},
-	{0x77,    3,    0,        0, 0x00000020},
-	{0x9f,    3,    4,        0, 0x00000000},
-	{0x57,    3,    0,        0, 0x0000000f},
-	{0x67,    3,    0,        0, 0x00000002},
-	{0x0f,    0,    3,        0, 0x00000000},
-	{0x71,    1,    0,      137, 0x00000000},
-	{0x67,    1,    0,        0, 0x00000008},
-	{0x71,    2,    0,      136, 0x00000000},
-	{0x4f,    1,    2,        0, 0x00000000},
-	{0x71,    2,    0,      138, 0x00000000},
-	{0x67,    2,    0,        0, 0x00000010},
-	{0x71,    3,    0,      139, 0x00000000},
-	{0x67,    3,    0,        0, 0x00000018},
-	{0x4f,    3,    2,        0, 0x00000000},
-	{0x4f,    3,    1,        0, 0x00000000},
-	{0x07,    3,    0,        0, 0x7cafe800},
-	{0x63,    6,    3,       52, 0x00000000},
-	{0xb7,    7,    0,        0, 0x00000001},
-	{0xbf,    0,    7,        0, 0x00000000},
-	{0x95,    0,    0,        0, 0x00000000},
-};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 09/12] net/tap: simplify internals
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (7 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 08/12] net/tap: remove no longer used files Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 10/12] net/tap: remove extraneous newlines Stephen Hemminger
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The names of Linux network devices are IFNAMSIZ(16) not the
same as DPDK which has up to 64 characters. Don't need to
hold onto the whole ifreq to save the remote interface flags.

Make sure packet and byte counters are read once, so that global
and per-queue values add up. No need for separate rx_nombuf counter
since there is an alloc_failed value in ethdev.

Keep only the statistics that are used. I.e no ipackets on
tx queues etc.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 138 ++++++++++++++++++----------------
 drivers/net/tap/rte_eth_tap.h |  22 +++---
 2 files changed, 83 insertions(+), 77 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index d847565073..3614aaf1dc 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -46,6 +46,11 @@
 #include <tap_netlink.h>
 #include <tap_tcmsgs.h>
 
+/* Used to snapshot statistics */
+#ifndef READ_ONCE
+#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
+#endif
+
 /* Linux based path to the TUN device */
 #define TUN_TAP_DEV_PATH        "/dev/net/tun"
 #define DEFAULT_TAP_NAME        "dtap"
@@ -212,7 +217,7 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 	 * and need to find the resulting device.
 	 */
 	TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name);
-	strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(pmd->name, ifr.ifr_name, IFNAMSIZ);
 
 	if (is_keepalive) {
 		/*
@@ -454,7 +459,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 		/* Packet couldn't fit in the provided mbuf */
 		if (unlikely(rxq->pi.flags & TUN_PKT_STRIP)) {
-			rxq->stats.ierrors++;
+			rxq->stats.errors++;
 			continue;
 		}
 
@@ -466,7 +471,8 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			struct rte_mbuf *buf = rte_pktmbuf_alloc(rxq->mp);
 
 			if (unlikely(!buf)) {
-				rxq->stats.rx_nombuf++;
+				rte_eth_devices[rxq->in_port].data->rx_mbuf_alloc_failed++;
+
 				/* No new buf has been allocated: do nothing */
 				if (!new_tail || !seg)
 					goto end;
@@ -511,8 +517,8 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		num_rx_bytes += mbuf->pkt_len;
 	}
 end:
-	rxq->stats.ipackets += num_rx;
-	rxq->stats.ibytes += num_rx_bytes;
+	rxq->stats.packets += num_rx;
+	rxq->stats.bytes += num_rx_bytes;
 
 	if (trigger && num_rx < nb_pkts)
 		rxq->trigger_seen = trigger;
@@ -692,7 +698,7 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			tso_segsz = mbuf_in->tso_segsz + hdrs_len;
 			if (unlikely(tso_segsz == hdrs_len) ||
 				tso_segsz > *txq->mtu) {
-				txq->stats.errs++;
+				txq->stats.errors++;
 				break;
 			}
 			gso_ctx->gso_size = tso_segsz;
@@ -730,7 +736,7 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		ret = tap_write_mbufs(txq, num_mbufs, mbuf,
 				&num_packets, &num_tx_bytes);
 		if (ret == -1) {
-			txq->stats.errs++;
+			txq->stats.errors++;
 			/* free tso mbufs */
 			if (num_tso_mbufs > 0)
 				rte_pktmbuf_free_bulk(mbuf, num_tso_mbufs);
@@ -748,9 +754,8 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		}
 	}
 
-	txq->stats.opackets += num_packets;
-	txq->stats.errs += nb_pkts - num_tx;
-	txq->stats.obytes += num_tx_bytes;
+	txq->stats.packets += num_packets;
+	txq->stats.bytes += num_tx_bytes;
 
 	return num_tx;
 }
@@ -1047,43 +1052,44 @@ tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 static int
 tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
 {
-	unsigned int i, imax;
-	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
-	unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
-	unsigned long rx_nombuf = 0, ierrors = 0;
+	unsigned int i;
 	const struct pmd_internals *pmd = dev->data->dev_private;
+	uint64_t bytes, packets;
 
 	/* rx queue statistics */
-	imax = (dev->data->nb_rx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_rx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
-		tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
-		rx_total += tap_stats->q_ipackets[i];
-		rx_bytes_total += tap_stats->q_ibytes[i];
-		rx_nombuf += pmd->rxq[i].stats.rx_nombuf;
-		ierrors += pmd->rxq[i].stats.ierrors;
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		const struct rx_queue *rxq = &pmd->rxq[i];
+
+		packets = READ_ONCE(rxq->stats.packets);
+		bytes = READ_ONCE(rxq->stats.bytes);
+
+		tap_stats->ipackets += packets;
+		tap_stats->ibytes += bytes;
+		tap_stats->ierrors += rxq->stats.errors;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_ipackets[i] = packets;
+			tap_stats->q_ibytes[i] = bytes;
+		}
 	}
 
 	/* tx queue statistics */
-	imax = (dev->data->nb_tx_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
-		dev->data->nb_tx_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
-
-	for (i = 0; i < imax; i++) {
-		tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
-		tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
-		tx_total += tap_stats->q_opackets[i];
-		tx_err_total += pmd->txq[i].stats.errs;
-		tx_bytes_total += tap_stats->q_obytes[i];
-	}
-
-	tap_stats->ipackets = rx_total;
-	tap_stats->ibytes = rx_bytes_total;
-	tap_stats->ierrors = ierrors;
-	tap_stats->rx_nombuf = rx_nombuf;
-	tap_stats->opackets = tx_total;
-	tap_stats->oerrors = tx_err_total;
-	tap_stats->obytes = tx_bytes_total;
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		const struct tx_queue *txq = &pmd->txq[i];
+
+		packets = READ_ONCE(txq->stats.packets);
+		bytes = READ_ONCE(txq->stats.bytes);
+
+		tap_stats->opackets += packets;
+		tap_stats->obytes += bytes;
+		tap_stats->oerrors += txq->stats.errors;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			tap_stats->q_opackets[i] = packets;
+			tap_stats->q_obytes[i] = bytes;
+		}
+	}
+
 	return 0;
 }
 
@@ -1094,14 +1100,8 @@ tap_stats_reset(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
-		pmd->rxq[i].stats.ipackets = 0;
-		pmd->rxq[i].stats.ibytes = 0;
-		pmd->rxq[i].stats.ierrors = 0;
-		pmd->rxq[i].stats.rx_nombuf = 0;
-
-		pmd->txq[i].stats.opackets = 0;
-		pmd->txq[i].stats.errs = 0;
-		pmd->txq[i].stats.obytes = 0;
+		memset(&pmd->rxq[i].stats, 0, sizeof(struct pkt_stats));
+		memset(&pmd->txq[i].stats, 0, sizeof(struct pkt_stats));
 	}
 
 	return 0;
@@ -1156,9 +1156,13 @@ tap_dev_close(struct rte_eth_dev *dev)
 	}
 
 	if (internals->remote_if_index) {
+		struct ifreq remote_ifr;
+
+		strlcpy(remote_ifr.ifr_name, internals->remote_iface, IFNAMSIZ);
+		remote_ifr.ifr_flags = internals->remote_flags;
+
 		/* Restore initial remote state */
-		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS,
-				&internals->remote_initial_flags);
+		int ret = ioctl(internals->ioctl_sock, SIOCSIFFLAGS, &remote_ifr);
 		if (ret)
 			TAP_LOG(ERR, "restore remote state failed: %d", ret);
 
@@ -2067,16 +2071,22 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	LIST_INIT(&pmd->flows);
 
 	if (strlen(remote_iface)) {
+		struct ifreq remote_ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index) {
 			TAP_LOG(ERR, "%s: failed to get %s if_index.",
 				pmd->name, remote_iface);
 			goto error_remote;
 		}
-		strlcpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(pmd->remote_iface, remote_iface, IFNAMSIZ);
+
+		memset(&remote_ifr, 0, sizeof(ifr));
+		strlcpy(remote_ifr.ifr_name, remote_iface, IFNAMSIZ);
 
 		/* Save state of remote device */
-		tap_ioctl(pmd, SIOCGIFFLAGS, &pmd->remote_initial_flags, 0, REMOTE_ONLY);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &remote_ifr, 0, REMOTE_ONLY);
+		pmd->remote_flags = remote_ifr.ifr_flags;
 
 		/* Replicate remote MAC address */
 		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
@@ -2190,10 +2200,10 @@ set_interface_name(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	} else {
 		/* use tap%d which causes kernel to choose next available */
-		strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
 	}
 	return 0;
 }
@@ -2211,7 +2221,7 @@ set_remote_iface(const char *key __rte_unused,
 				value);
 			return -1;
 		}
-		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
+		strlcpy(name, value, IFNAMSIZ);
 	}
 
 	return 0;
@@ -2262,13 +2272,13 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	const char *name, *params;
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
-	char tun_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tun_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_eth_dev *eth_dev;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
 	    strlen(params) == 0) {
@@ -2284,7 +2294,7 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	}
 
 	/* use tun%d which causes kernel to choose next available */
-	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tun_name, DEFAULT_TUN_NAME "%d", IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
@@ -2424,8 +2434,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	int ret;
 	struct rte_kvargs *kvlist = NULL;
 	int speed;
-	char tap_name[RTE_ETH_NAME_MAX_LEN];
-	char remote_iface[RTE_ETH_NAME_MAX_LEN];
+	char tap_name[IFNAMSIZ];
+	char remote_iface[IFNAMSIZ];
 	struct rte_ether_addr user_mac = { .addr_bytes = {0} };
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
@@ -2479,8 +2489,8 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	speed = RTE_ETH_SPEED_NUM_10G;
 
 	/* use tap%d which causes kernel to choose next available */
-	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
-	memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+	strlcpy(tap_name, DEFAULT_TAP_NAME "%d", IFNAMSIZ);
+	memset(remote_iface, 0, IFNAMSIZ);
 
 	if (params && (params[0] != '\0')) {
 		TAP_LOG(DEBUG, "parameters (%s)", params);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index ce4322ad04..8f9ab613c7 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -34,13 +34,9 @@ enum rte_tuntap_type {
 };
 
 struct pkt_stats {
-	uint64_t opackets;              /* Number of output packets */
-	uint64_t ipackets;              /* Number of input packets */
-	uint64_t obytes;                /* Number of bytes on output */
-	uint64_t ibytes;                /* Number of bytes on input */
-	uint64_t errs;                  /* Number of TX error packets */
-	uint64_t ierrors;               /* Number of RX error packets */
-	uint64_t rx_nombuf;             /* Nb of RX mbuf alloc failures */
+	uint64_t packets;       /* Number of packets */
+	uint64_t bytes;         /* Number of bytes */
+	uint64_t errors;        /* Number of errors */
 };
 
 struct rx_queue {
@@ -68,15 +64,16 @@ struct tx_queue {
 
 struct pmd_internals {
 	struct rte_eth_dev *dev;          /* Ethernet device. */
-	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
-	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
+	char remote_iface[IFNAMSIZ];	  /* Remote netdevice name */
+	char name[IFNAMSIZ];		  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
 	int persist;			  /* 1 if keep link up, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
-	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
+	uint16_t remote_flags;		  /* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int ioctl_sock;                   /* socket for ioctl calls */
+	int ka_fd;                        /* keep-alive file descriptor */
 
 #ifdef HAVE_TCA_FLOWER
 	int nlsk_fd;                      /* Netlink socket fd */
@@ -88,12 +85,11 @@ struct pmd_internals {
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 #endif
+	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
+	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 
 	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
 	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
-	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
-	int ka_fd;                        /* keep-alive file descriptor */
-	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
 
 struct pmd_process_private {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 10/12] net/tap: remove extraneous newlines
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (8 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 09/12] net/tap: simplify internals Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 11/12] net/tap: do not mark queue full as error Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 12/12] net/tap: update documentation Stephen Hemminger
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Some log messages contained extra newlines.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 3614aaf1dc..2484a82ccb 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -235,9 +235,8 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 
 	flags = fcntl(fd, F_GETFL);
 	if (flags == -1) {
-		TAP_LOG(WARNING,
-			"Unable to get %s current flags\n",
-			ifr.ifr_name);
+		TAP_LOG(WARNING, "Unable to get %s current flags: %s",
+			ifr.ifr_name, strerror(errno));
 		goto error;
 	}
 
@@ -279,7 +278,7 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 
 		if (sigaction(signo, &sa, NULL) == -1) {
 			TAP_LOG(WARNING,
-				"Unable to set rt-signal %d handler\n", signo);
+				"Unable to set rt-signal %d handler", signo);
 			goto error;
 		}
 
@@ -290,11 +289,11 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 	}
 
 	if (signo == SIGRTMAX) {
-		TAP_LOG(WARNING, "All rt-signals are in use\n");
+		TAP_LOG(WARNING, "All rt-signals are in use");
 
 		/* Disable trigger globally in case of error */
 		tap_trigger = 0;
-		TAP_LOG(NOTICE, "No Rx trigger signal available\n");
+		TAP_LOG(NOTICE, "No Rx trigger signal available");
 	} else {
 		/* Enable signal on file descriptor */
 		if (fcntl(fd, F_SETSIG, signo) < 0) {
@@ -920,7 +919,7 @@ tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 	}
 
 	process_private = dev->process_private;
-	TAP_LOG(DEBUG, "tap_attach q:%d\n", request_param->q_count);
+	TAP_LOG(DEBUG, "tap_attach q:%d", request_param->q_count);
 
 	for (int q = 0; q < request_param->q_count; q++)
 		process_private->fds[q] = request->fds[q];
@@ -1463,7 +1462,7 @@ tap_gso_ctx_setup(struct rte_gso_ctx *gso_ctx, struct rte_eth_dev *dev)
 		if (ret < 0 || ret >= (int)sizeof(pool_name)) {
 			TAP_LOG(ERR,
 				"%s: failed to create mbuf pool name for device %s,"
-				"device name too long or output error, ret: %d\n",
+				"device name too long or output error, ret: %d",
 				pmd->name, dev->device->name, ret);
 			return -ENAMETOOLONG;
 		}
@@ -1473,7 +1472,7 @@ tap_gso_ctx_setup(struct rte_gso_ctx *gso_ctx, struct rte_eth_dev *dev)
 			SOCKET_ID_ANY);
 		if (!pmd->gso_ctx_mp) {
 			TAP_LOG(ERR,
-				"%s: failed to create mbuf pool for device %s\n",
+				"%s: failed to create mbuf pool for device %s",
 				pmd->name, dev->device->name);
 			return -1;
 		}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 11/12] net/tap: do not mark queue full as error
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (9 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 10/12] net/tap: remove extraneous newlines Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  2024-05-02 21:31   ` [PATCH v12 12/12] net/tap: update documentation Stephen Hemminger
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

If tap device in kernel returns EAGAIN that means it is full.
That is not an error.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/rte_eth_tap.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 2484a82ccb..485bd35912 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -542,7 +542,6 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		struct rte_mbuf *seg = mbuf;
 		uint64_t l4_ol_flags;
 		int proto;
-		int n;
 		int j;
 		int k; /* current index in iovecs for copying segments */
 
@@ -647,14 +646,18 @@ tap_write_mbufs(struct tx_queue *txq, uint16_t num_mbufs,
 		}
 
 		/* copy the tx frame data */
-		n = writev(process_private->fds[txq->queue_id], iovecs, k);
-		if (n <= 0)
-			return -1;
+		if (unlikely(writev(process_private->fds[txq->queue_id], iovecs, k) < 0)) {
+			TAP_LOG(DEBUG, "writev (qid=%u fd=%d) %s",
+				txq->queue_id, process_private->fds[txq->queue_id],
+				strerror(errno));
+			return (errno == EAGAIN) ? 0 : -1;
+		}
 
 		(*num_packets)++;
 		(*num_tx_bytes) += rte_pktmbuf_pkt_len(mbuf);
 	}
-	return 0;
+
+	return 1;
 }
 
 /* Callback to handle sending packets from the tap interface
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v12 12/12] net/tap: update documentation
  2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
                     ` (10 preceding siblings ...)
  2024-05-02 21:31   ` [PATCH v12 11/12] net/tap: do not mark queue full as error Stephen Hemminger
@ 2024-05-02 21:31   ` Stephen Hemminger
  11 siblings, 0 replies; 133+ messages in thread
From: Stephen Hemminger @ 2024-05-02 21:31 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

The driver support of flows has changed and the wording in
the guide was awkward.

Drop references to DPDK pktgen in this documentation since
it is not required and confusing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/nics/tap.rst                | 274 +++++++------------------
 doc/guides/rel_notes/release_24_07.rst |   7 +
 2 files changed, 84 insertions(+), 197 deletions(-)

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index d4f45c02a1..55e38fb25b 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,47 +1,51 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tun|Tap Poll Mode Driver
-========================
+TAP Poll Mode Driver
+====================
 
-The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
-local host. The PMD allows for DPDK and the host to communicate using a raw
-device interface on the host and in the DPDK application.
+The TAP Poll Mode Driver (PMD) is a virtual device for injecting packets to be processed
+by the Linux kernel. This PMD is useful when writing DPDK application
+for offloading network functionality (such as tunneling) from the kernel.
 
-The device created is a TAP device, which sends/receives packet in a raw
-format with a L2 header. The usage for a TAP PMD is for connectivity to the
-local host using a TAP interface. When the TAP PMD is initialized it will
-create a number of tap devices in the host accessed via ``ifconfig -a`` or
-``ip`` command. The commands can be used to assign and query the virtual like
-device.
+From the kernel point of view, the TAP device looks like a regular network interface.
+The network device can be managed by standard tools such as ``ip`` and ``ethtool`` commands.
+It is also possible to use existing packet tools such as  ``wireshark`` or ``tcpdump``.
 
-These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
-along with being able to be used as a network connection to the DPDK
-application. The method enable one or more interfaces is to use the
-``--vdev=net_tap0`` option on the DPDK application command line. Each
-``--vdev=net_tap1`` option given will create an interface named dtap0, dtap1,
-and so on.
+From the DPDK application, the TAP device looks like a DPDK ethdev.
+Packets are sent and received in L2 (Ethernet) format. The standare DPDK
+API's to query for information, statistics and send and receive packets
+work as expected.
 
-The interface name can be changed by adding the ``iface=foo0``, for example::
+Requirements
+~~~~~~~~~~~~
+
+The TAP PMD requires kernel support for multiple queues in TAP device as
+well as the multi-queue ``multiq`` and incoming ``ingress`` queue disciplines.
+These are standard kernel features in most Linux distributions.
+
+Arguments
+---------
+
+TAP devices are created with the command line
+``--vdev=net_tap0`` option. This option maybe specified more the once by repeating
+with a different ``net_tapX`` device.
+
+By default, the Linux interfaces are named ``dtap0``, ``dtap1``, etc.
+The interface name can be specified by adding the ``iface=foo0``, for example::
 
    --vdev=net_tap0,iface=foo0 --vdev=net_tap1,iface=foo1, ...
 
-Normally the PMD will generate a random MAC address, but when testing or with
-a static configuration the developer may need a fixed MAC address style.
-Using the option ``mac=fixed`` you can create a fixed known MAC address::
+Normally the PMD will generate a random MAC address.
+If a static address is desired instead, the ``mac=fixed`` can be used.
 
    --vdev=net_tap0,mac=fixed
 
-The MAC address will have a fixed value with the last octet incrementing by one
-for each interface string containing ``mac=fixed``. The MAC address is formatted
-as 02:'d':'t':'a':'p':[00-FF]. Convert the characters to hex and you get the
-actual MAC address: ``02:64:74:61:70:[00-FF]``.
-
-   --vdev=net_tap0,mac="02:64:74:61:70:11"
+With the fixed option, the MAC address will have the first octets:
+as 02:'d':'t':'a':'p':[00-FF] and the last octets are the interface number.
 
-The MAC address will have a user value passed as string. The MAC address is in
-format with delimiter ``:``. The string is byte converted to hex and you get
-the actual MAC address: ``02:64:74:61:70:11``.
+To specify a specific MAC address use the conventional representation.
+The string is byte converted to hex, the result is MAC address: ``02:64:74:61:70:11``.
 
 It is possible to specify a remote netdevice to capture packets from by adding
 ``remote=foo1``, for example::
@@ -59,40 +63,20 @@ netdevice that has no support in the DPDK. It is possible to add explicit
 rte_flow rules on the tap PMD to capture specific traffic (see next section for
 examples).
 
-After the DPDK application is started you can send and receive packets on the
-interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
-point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
-and others to communicate with the DPDK application. The DPDK application may
-not understand network protocols like IPv4/6, UDP or TCP unless the
-application has been written to understand these protocols.
-
-If you need the interface as a real network interface meaning running and has
-a valid IP address then you can do this with the following commands::
-
-   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Please change the IP addresses as you see fit.
-
-If routing is enabled on the host you can also communicate with the DPDK App
-over the internet via a standard socket layer application as long as you
-account for the protocol handling in the application.
-
-If you have a Network Stack in your DPDK application or something like it you
-can utilize that stack to handle the network protocols. Plus you would be able
-to address the interface using an IP address assigned to the internal
-interface.
-
 Normally, when the DPDK application exits,
 the TAP device is marked down and is removed.
-But this behaviour can be overridden by the use of the persist flag, example::
+But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
-The TUN PMD allows user to create a TUN device on host. The PMD allows user
-to transmit and receive packets via DPDK API calls with L3 header and payload.
-The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
-interfaces are passed to DPDK ``rte_eal_init`` arguments as ``--vdev=net_tunX``,
+TUN devices
+-----------
+
+The TAP device can be used an L3 tunnel only device (TUN).
+This type of device does not include the Ethernet (L2) header; all packets
+are sent and received as IP packets.
+
+TUN devices are created with the command line arguments ``--vdev=net_tunX``,
 where X stands for unique id, example::
 
    --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
@@ -103,27 +87,33 @@ options. Default interface name is ``dtunX``, where X stands for unique id.
 Flow API support
 ----------------
 
-The tap PMD supports major flow API pattern items and actions, when running on
-linux kernels above 4.2 ("Flower" classifier required).
-The kernel support can be checked with this command::
+The TAP PMD supports major flow API pattern items and actions.
+
+Requirements
+~~~~~~~~~~~~
 
-   zcat /proc/config.gz | ( grep 'CLS_FLOWER=' || echo 'not supported' ) |
-   tee -a /dev/stderr | grep -q '=m' &&
-   lsmod | ( grep cls_flower || echo 'try modprobe cls_flower' )
+Flow support in TAP driver requires the Linux kernel support of flow based
+traffic control filter ``flower``. This was added in Linux 4.3 kernel.
 
-Supported items:
+The implementation of RSS action uses an eBPF module that requires additional
+libraries and tools. Building the RSS support requires the ``clang``
+compiler to compile the C code to BPF target; ``bpftool`` to convert the
+compiled BPF object to a header file; and ``libbpf`` to load the eBPF
+action into the kernel.
 
-- eth: src and dst (with variable masks), and eth_type (0xffff mask).
-- vlan: vid, pcp, but not eid. (requires kernel 4.9)
-- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
-- udp/tcp: src and dst port (0xffff) mask.
+Supported match items:
+
+  - eth: src and dst (with variable masks), and eth_type (0xffff mask).
+  - vlan: vid, pcp, but not eid. (requires kernel 4.9)
+  - ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
+  - udp/tcp: src and dst port (0xffff) mask.
 
 Supported actions:
 
 - DROP
 - QUEUE
 - PASSTHRU
-- RSS (requires kernel 4.9)
+- RSS
 
 It is generally not possible to provide a "last" item. However, if the "last"
 item, once masked, is identical to the masked spec, then it is supported.
@@ -133,7 +123,7 @@ full mask (exact match).
 
 As rules are translated to TC, it is possible to show them with something like::
 
-   tc -s filter show dev tap1 parent 1:
+   tc -s filter show dev dtap1 parent 1:
 
 Examples of testpmd flow rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,135 +164,25 @@ The IPC synchronization of Rx/Tx queues is currently limited:
   - Maximum 8 queues shared
   - Synchronized on probing, but not on later port update
 
-Example
--------
-
-The following is a simple example of using the TAP PMD with the Pktgen
-packet generator. It requires that the ``socat`` utility is installed on the
-test system.
-
-Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
-used to build the dpdk you pulled down.
-
-Run pktgen from the pktgen directory in a terminal with a commandline like the
-following::
-
-    sudo ./app/app/x86_64-native-linux-gcc/app/pktgen -l 1-5 -n 4        \
-     --proc-type auto --log-level debug --socket-mem 512,512 --file-prefix pg   \
-     --vdev=net_tap0 --vdev=net_tap1 -b 05:00.0 -b 05:00.1                  \
-     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
-     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
-     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
-     -f themes/black-yellow.theme
-
-.. Note:
-
-   Change the ``-b`` options to exclude all of your physical ports. The
-   following command line is all one line.
-
-   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
-   work on your system configuration. See the Pktgen docs for more
-   information.
-
-Verify with ``ifconfig -a`` command in a different xterm window, should have a
-``dtap0`` and ``dtap1`` interfaces created.
-
-Next set the links for the two interfaces to up via the commands below::
-
-    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
-    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
-
-Then use socat to create a loopback for the two interfaces::
-
-    sudo socat interface:dtap0 interface:dtap1
-
-Then on the Pktgen command line interface you can start sending packets using
-the commands ``start 0`` and ``start 1`` or you can start both at the same
-time with ``start all``. The command ``str`` is an alias for ``start all`` and
-``stp`` is an alias for ``stop all``.
-
-While running you should see the 64 byte counters increasing to verify the
-traffic is being looped back. You can use ``set all size XXX`` to change the
-size of the packets after you stop the traffic. Use pktgen ``help``
-command to see a list of all commands. You can also use the ``-f`` option to
-load commands at startup in command line or Lua script in pktgen.
 
 RSS specifics
 -------------
-Packet distribution in TAP is done by the kernel which has a default
-distribution. This feature is adding RSS distribution based on eBPF code.
-The default eBPF code calculates RSS hash based on Toeplitz algorithm for
-a fixed RSS key. It is calculated on fixed packet offsets. For IPv4 and IPv6 it
-is calculated over src/dst addresses (8 or 32 bytes for IPv4 or IPv6
-respectively) and src/dst TCP/UDP ports (4 bytes).
-
-The RSS algorithm is written in file ``tap_bpf_program.c`` which
-does not take part in TAP PMD compilation. Instead this file is compiled
-in advance to eBPF object file. The eBPF object file is then parsed and
-translated into eBPF byte code in the format of C arrays of eBPF
-instructions. The C array of eBPF instructions is part of TAP PMD tree and
-is taking part in TAP PMD compilation. At run time the C arrays are uploaded to
-the kernel via BPF system calls and the RSS hash is calculated by the
-kernel.
-
-It is possible to support different RSS hash algorithms by updating file
-``tap_bpf_program.c``  In order to add a new RSS hash algorithm follow these
-steps:
-
-#. Write the new RSS implementation in file ``tap_bpf_program.c``
-
-   BPF programs which are uploaded to the kernel correspond to
-   C functions under different ELF sections.
-
-#. Install ``LLVM`` library and ``clang`` compiler versions 3.7 and above
-
-#. Use make to compile  `tap_bpf_program.c`` via ``LLVM`` into an object file
-   and extract the resulting instructions into ``tap_bpf_insn.h``::
-
-    cd bpf; make
-
-#. Recompile the TAP PMD.
-
-The C arrays are uploaded to the kernel using BPF system calls.
-
-``tc`` (traffic control) is a well known user space utility program used to
-configure the Linux kernel packet scheduler. It is usually packaged as
-part of the ``iproute2`` package.
-Since commit 11c39b5e9 ("tc: add eBPF support to f_bpf") ``tc`` can be used
-to uploads eBPF code to the kernel and can be patched in order to print the
-C arrays of eBPF instructions just before calling the BPF system call.
-Please refer to ``iproute2`` package file ``lib/bpf.c`` function
-``bpf_prog_load()``.
-
-An example utility for eBPF instruction generation in the format of C arrays will
-be added in next releases
-
-TAP reports on supported RSS functions as part of dev_infos_get callback:
-``RTE_ETH_RSS_IP``, ``RTE_ETH_RSS_UDP`` and ``RTE_ETH_RSS_TCP``.
-**Known limitation:** TAP supports all of the above hash functions together
-and not in partial combinations.
-
-Systems supporting flow API
----------------------------
-
-- "tc flower" classifier requires linux kernel above 4.2
-- eBPF/RSS requires linux kernel above 4.9
-
-+--------------------+-----------------------+
-| RH7.3              | No flow rule support  |
-+--------------------+-----------------------+
-| RH7.4              | No RSS action support |
-+--------------------+-----------------------+
-| RH7.5              | No RSS action support |
-+--------------------+-----------------------+
-| SLES 15,           | No limitation         |
-| kernel 4.12        |                       |
-+--------------------+-----------------------+
-| Azure Ubuntu 16.04,| No limitation         |
-| kernel 4.13        |                       |
-+--------------------+-----------------------+
+The default packet distribution in TAP without flow rules is done by the
+kernel which has a default flow based distribution.
+When flow rules are used to distribute packets across a set of queues
+an eBPF program is used to calculate the RSS based on Toeplitz algorithm for
+with the given key.
+
+The hash is calculated for IPv4 and IPv6, over src/dst addresses
+(8 or 32 bytes for IPv4 or IPv6 respectively) and
+optionally the src/dst TCP/UDP ports (4 bytes).
+
 
 Limitations
 -----------
 
-* Rx/Tx must have the same number of queues.
+- Since TAP device uses a file descriptors to talk to the kernel.
+  The same number of queues must be specified for receive and transmit.
+
+- The RSS algorithm only support L3 or L4 functions. It does not support
+  finer grain selections (for example: only IPV6 packets with extension headers).
diff --git a/doc/guides/rel_notes/release_24_07.rst b/doc/guides/rel_notes/release_24_07.rst
index a69f24cf99..8652271ed2 100644
--- a/doc/guides/rel_notes/release_24_07.rst
+++ b/doc/guides/rel_notes/release_24_07.rst
@@ -55,6 +55,13 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **TAP PMD updates.**
+
+  * Fixed support of RSS flow action to work with current Linux
+    kernels and BPF tooling. Will only be enabled if clang and bpftool
+    are available.
+
+  * Support up to 8 queues when used by secondary process
 
 Removed Items
 -------------
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 133+ messages in thread

end of thread, other threads:[~2024-05-02 21:38 UTC | newest]

Thread overview: 133+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-30  3:46 [RFC 0/2] net/tap RSS BPF rewrite Stephen Hemminger
2024-01-30  3:46 ` [RFC 1/2] tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-01-30  3:46 ` [RFC 2/2] tap: rework BPF handling Stephen Hemminger
2024-02-07 22:11 ` [PATCH v2 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 3/7] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 5/7] net/tap: use libbpf to load new " Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 6/7] net/tap: remove no longer used files Stephen Hemminger
2024-02-07 22:11   ` [PATCH v2 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
2024-02-08  7:01     ` Morten Brørup
2024-02-08 17:41 ` [PATCH v3 0/7] net/tap: RSS using BPF overhaul Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 5/7] net/tap: use libbpf to load new " Stephen Hemminger
2024-02-08 18:02     ` Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 6/7] net/tap: remove no longer used files Stephen Hemminger
2024-02-08 17:41   ` [PATCH v3 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
2024-02-08 19:05 ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 1/7] net/tap: remove unused RSS hash types Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 2/7] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 3/7] tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 4/7] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-02-10  0:54     ` Ferruh Yigit
2024-02-10  2:09       ` Stephen Hemminger
2024-02-28 17:27         ` Ferruh Yigit
2024-02-29 23:39           ` Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 5/7] net/tap: use libbpf to load new " Stephen Hemminger
2024-02-08 20:39     ` Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 6/7] net/tap: remove no longer used files Stephen Hemminger
2024-02-08 19:05   ` [PATCH v4 7/7] MAINTAINERS: add maintainer for TAP device Stephen Hemminger
2024-02-12 16:47   ` [PATCH v4 0/7] net/tap: queue flow action RSS using BPF redo Stephen Hemminger
2024-04-02 17:12 ` [PATCH v5 0/8] net/tap: cleanups and fix BPF flow Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 1/8] net/tap: do not duplicate fd's Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 3/8] net/tap: remove unused RSS hash types Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-04-02 17:12   ` [PATCH v5 7/8] net/tap: use libbpf to load new " Stephen Hemminger
2024-04-03 11:50     ` Luca Boccassi
2024-04-03 14:53       ` Stephen Hemminger
2024-04-03 15:55       ` Stephen Hemminger
2024-04-03 21:19         ` Luca Boccassi
2024-04-03 23:41           ` Stephen Hemminger
2024-04-04  0:49             ` Luca Boccassi
2024-04-04 15:51               ` Stephen Hemminger
2024-04-04 16:12                 ` Luca Boccassi
2024-04-04 15:30           ` Stephen Hemminger
2024-04-04 16:11             ` Luca Boccassi
2024-04-02 17:12   ` [PATCH v5 8/8] net/tap: remove no longer used files Stephen Hemminger
2024-04-02 20:43     ` Stephen Hemminger
2024-04-05 21:14 ` [PATCH v6 0/8] net/tap: cleanup and fix BPF flow support Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 1/8] net/tap: do not duplicate fd's Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 2/8] doc: fix the requirements and building of TAP flow Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 3/8] net/tap: remove unused fields Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 4/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 5/8] net/tap: stop "vendoring" linux bpf headers Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 6/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-04-05 21:14   ` [PATCH v6 7/8] net/tap: use libbpf to load new " Stephen Hemminger
2024-04-05 21:15   ` [PATCH v6 8/8] net/tap: remove no longer used files Stephen Hemminger
2024-04-08 21:18 ` [PATCH v7 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 1/8] net/tap: do not duplicate fd's Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 2/8] net/tap: remove unused fields Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 6/8] net/tap: use libbpf to load new " Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 7/8] net/tap: remove no longer used files Stephen Hemminger
2024-04-08 21:18   ` [PATCH v7 8/8] doc: update documentation of TAP PMD Stephen Hemminger
2024-04-09  3:40 ` [PATCH v8 0/8] net/tap: cleanups and fix BPF support Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 1/8] net/tap: do not duplicate fd's Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 2/8] net/tap: remove unused fields Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 3/8] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 4/8] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 5/8] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 6/8] net/tap: use libbpf to load new " Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 7/8] net/tap: remove no longer used files Stephen Hemminger
2024-04-09  3:40   ` [PATCH v8 8/8] doc: update documentation of TAP PMD Stephen Hemminger
2024-04-26 15:48 ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 1/9] net/tap: do not duplicate fd's Stephen Hemminger
2024-05-01 11:13     ` Ferruh Yigit
2024-05-01 23:53       ` Stephen Hemminger
2024-05-02 14:51         ` Ferruh Yigit
2024-05-02 16:22           ` Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 2/9] net/tap: remove unused fields Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-05-01 11:14     ` Ferruh Yigit
2024-04-26 15:48   ` [PATCH v9 6/9] net/tap: use libbpf to load new " Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 7/9] net/tap: remove no longer used files Stephen Hemminger
2024-04-26 15:48   ` [PATCH v9 8/9] doc: update documentation of TAP PMD Stephen Hemminger
2024-05-01 12:36     ` Ferruh Yigit
2024-04-26 15:48   ` [PATCH v9 9/9] net/tap: simplify the internal structure Stephen Hemminger
2024-05-01 11:18   ` [PATCH v9 0/9] net/tap: fix RSS (BPF) support Ferruh Yigit
2024-05-01 15:41     ` Stephen Hemminger
2024-05-01 16:11 ` [PATCH v10 0/9] net/tap: fix RSS (BPF) flow support Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 1/9] net/tap: do not duplicate fd's Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 2/9] net/tap: remove unused fields Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 6/9] net/tap: use libbpf to load new " Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 7/9] net/tap: remove no longer used files Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 8/9] net/tap: simplify internals Stephen Hemminger
2024-05-01 16:12   ` [PATCH v10 9/9] net/tap: update documentation Stephen Hemminger
2024-05-02  2:49 ` [PATCH v11 0/9] net/tap fix RSS (BPF) flow support Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 1/9] net/tap: do not duplicate fd's Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 2/9] net/tap: remove unused fields Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 3/9] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 4/9] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 5/9] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 6/9] net/tap: use libbpf to load new " Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 7/9] net/tap: remove no longer used files Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 8/9] net/tap: simplify internals Stephen Hemminger
2024-05-02  2:49   ` [PATCH v11 9/9] net/tap: update documentation Stephen Hemminger
2024-05-02 21:31 ` [PATCH v12 00/12] net/tap: RSS and other fixes Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 01/12] net/tap: fix fd check in flow_isolate Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 02/12] net/tap: do not duplicate fd's Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 03/12] net/tap: remove unused fields Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 04/12] net/tap: validate and setup parameters for BPF RSS Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 05/12] net/tap: do not build flow support if header is out of date Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 06/12] net/tap: rewrite the RSS BPF program Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 07/12] net/tap: use libbpf to load new " Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 08/12] net/tap: remove no longer used files Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 09/12] net/tap: simplify internals Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 10/12] net/tap: remove extraneous newlines Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 11/12] net/tap: do not mark queue full as error Stephen Hemminger
2024-05-02 21:31   ` [PATCH v12 12/12] net/tap: update documentation Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).