diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 22:13:02 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 22:13:02 +0000 |
commit | e244c93d21bcacf1a0eedefdcc3018a362274796 (patch) | |
tree | 857e0d7bcf20546b38fff97a8702c2c1240bc23b /src | |
parent | Initial commit. (diff) | |
download | nwipe-af2761cb2be46141e09d4d066d9bac9fab3904f8.tar.xz nwipe-af2761cb2be46141e09d4d066d9bac9fab3904f8.zip |
Adding upstream version 0.36.upstream/0.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
64 files changed, 25190 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..7d9bb44 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,10 @@ +# what flags you want to pass to the C compiler & linker +#CFLAGS = -lncurses -lparted +AM_CFLAGS = +AM_LDFLAGS = + +# this lists the binaries to produce, the (non-PHONY, binary) targets in +# the previous manual Makefile +bin_PROGRAMS = nwipe +nwipe_SOURCES = context.h logging.h options.h prng.h version.h temperature.h nwipe.c gui.c method.h pass.c device.c gui.h isaac_rand/isaac_standard.h isaac_rand/isaac_rand.h isaac_rand/isaac_rand.c isaac_rand/isaac64.h isaac_rand/isaac64.c mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c temperature.c PDFGen/pdfgen.h PDFGen/pdfgen.c create_pdf.c create_pdf.h embedded_images/shred_db.jpg.c embedded_images/shred_db.jpg.h embedded_images/tick_erased.jpg.c embedded_images/tick_erased.jpg.h embedded_images/redcross.c embedded_images/redcross.h hpa_dco.h hpa_dco.c miscellaneous.h miscellaneous.c embedded_images/nwipe_exclamation.jpg.h embedded_images/nwipe_exclamation.jpg.c conf.h conf.c customers.h customers.c hddtemp_scsi/hddtemp.h hddtemp_scsi/scsi.h hddtemp_scsi/scsicmds.h hddtemp_scsi/get_scsi_temp.c hddtemp_scsi/scsi.c hddtemp_scsi/scsicmds.c +nwipe_LDADD = $(PARTED_LIBS) $(LIBCONFIG) diff --git a/src/PDFGen/pdfgen.c b/src/PDFGen/pdfgen.c new file mode 100644 index 0000000..4d9cf45 --- /dev/null +++ b/src/PDFGen/pdfgen.c @@ -0,0 +1,4057 @@ +/* pdfgen.c provided courtesy of https://github.com/AndreRenaud/PDFGen + * + * Thank You ! + */ + +/** + * Simple engine for creating PDF files. + * It supports text, shapes, images etc... + * Capable of handling millions of objects without too much performance + * penalty. + * Public domain license - no warrenty implied; use at your own risk. + */ + +/** + * PDF HINTS & TIPS + * The specification can be found at + * https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf + * The following sites have various bits & pieces about PDF document + * generation + * http://www.mactech.com/articles/mactech/Vol.15/15.09/PDFIntro/index.html + * http://gnupdf.org/Introduction_to_PDF + * http://www.planetpdf.com/mainpage.asp?WebPageID=63 + * http://archive.vector.org.uk/art10008970 + * http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf + * https://blog.idrsolutions.com/2013/01/understanding-the-pdf-file-format-overview/ + * + * To validate the PDF output, there are several online validators: + * http://www.validatepdfa.com/online.htm + * http://www.datalogics.com/products/callas/callaspdfA-onlinedemo.asp + * http://www.pdf-tools.com/pdf/validate-pdfa-online.aspx + * + * In addition the 'pdftk' server can be used to analyse the output: + * https://www.pdflabs.com/docs/pdftk-cli-examples/ + * + * PDF page markup operators: + * b closepath, fill,and stroke path. + * B fill and stroke path. + * b* closepath, eofill,and stroke path. + * B* eofill and stroke path. + * BI begin image. + * BMC begin marked content. + * BT begin text object. + * BX begin section allowing undefined operators. + * c curveto. + * cm concat. Concatenates the matrix to the current transform. + * cs setcolorspace for fill. + * CS setcolorspace for stroke. + * d setdash. + * Do execute the named XObject. + * DP mark a place in the content stream, with a dictionary. + * EI end image. + * EMC end marked content. + * ET end text object. + * EX end section that allows undefined operators. + * f fill path. + * f* eofill Even/odd fill path. + * g setgray (fill). + * G setgray (stroke). + * gs set parameters in the extended graphics state. + * h closepath. + * i setflat. + * ID begin image data. + * j setlinejoin. + * J setlinecap. + * k setcmykcolor (fill). + * K setcmykcolor (stroke). + * l lineto. + * m moveto. + * M setmiterlimit. + * n end path without fill or stroke. + * q save graphics state. + * Q restore graphics state. + * re rectangle. + * rg setrgbcolor (fill). + * RG setrgbcolor (stroke). + * s closepath and stroke path. + * S stroke path. + * sc setcolor (fill). + * SC setcolor (stroke). + * sh shfill (shaded fill). + * Tc set character spacing. + * Td move text current point. + * TD move text current point and set leading. + * Tf set font name and size. + * Tj show text. + * TJ show text, allowing individual character positioning. + * TL set leading. + * Tm set text matrix. + * Tr set text rendering mode. + * Ts set super/subscripting text rise. + * Tw set word spacing. + * Tz set horizontal scaling. + * T* move to start of next line. + * v curveto. + * w setlinewidth. + * W clip. + * y curveto. + */ + +#if defined(_MSC_VER) +#define _CRT_SECURE_NO_WARNINGS 1 // Drop the MSVC complaints about snprintf +#define _USE_MATH_DEFINES +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#else + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE /* For localtime_r */ +#endif + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 /* for M_SQRT2 */ +#endif + +#include <sys/types.h> /* for ssize_t */ +#endif + +#include <ctype.h> +#include <errno.h> +#include <inttypes.h> +#include <locale.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> + +#include "pdfgen.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define PDF_RGB_R(c) (float)((((c) >> 16) & 0xff) / 255.0) +#define PDF_RGB_G(c) (float)((((c) >> 8) & 0xff) / 255.0) +#define PDF_RGB_B(c) (float)((((c) >> 0) & 0xff) / 255.0) +#define PDF_IS_TRANSPARENT(c) (((c) >> 24) == 0xff) + +#if defined(_MSC_VER) +#define inline __inline +#define snprintf _snprintf +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#ifdef stat +#undef stat +#endif +#define stat _stat +#define SKIP_ATTRIBUTE +#else +#include <strings.h> // strcasecmp +#endif + +/** + * Try and support big & little endian machines + */ +static inline uint32_t bswap32(uint32_t x) +{ + return (((x & 0xff000000u) >> 24) | ((x & 0x00ff0000u) >> 8) | + ((x & 0x0000ff00u) << 8) | ((x & 0x000000ffu) << 24)); +} + +#ifdef __has_include // C++17, supported as extension to C++11 in clang, GCC + // 5+, vs2015 +#if __has_include(<endian.h>) +#include <endian.h> // gnu libc normally provides, linux +#elif __has_include(<machine/endian.h>) +#include <machine/endian.h> //open bsd, macos +#elif __has_include(<sys/param.h>) +#include <sys/param.h> // mingw, some bsd (not open/macos) +#elif __has_include(<sys/isadefs.h>) +#include <sys/isadefs.h> // solaris +#endif +#endif + +#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +#ifndef __BYTE_ORDER__ +/* Fall back to little endian by default */ +#define __LITTLE_ENDIAN__ +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || __BYTE_ORDER == __BIG_ENDIAN +#define __BIG_ENDIAN__ +#else +#define __LITTLE_ENDIAN__ +#endif +#endif + +#if defined(__LITTLE_ENDIAN__) +#define ntoh32(x) bswap32((x)) +#elif defined(__BIG_ENDIAN__) +#define ntoh32(x) (x) +#endif + +// Limits on image sizes for sanity checking & to avoid plausible overflow +// issues +#define MAX_IMAGE_WIDTH (16 * 1024) +#define MAX_IMAGE_HEIGHT (16 * 1024) + +// Signatures for various image formats +static const uint8_t bmp_signature[] = {'B', 'M'}; +static const uint8_t png_signature[] = {0x89, 0x50, 0x4E, 0x47, + 0x0D, 0x0A, 0x1A, 0x0A}; +static const uint8_t jpeg_signature[] = {0xff, 0xd8}; +static const uint8_t ppm_signature[] = {'P', '6'}; +static const uint8_t pgm_signature[] = {'P', '5'}; + +// Special signatures for PNG chunks +static const char png_chunk_header[] = "IHDR"; +static const char png_chunk_palette[] = "PLTE"; +static const char png_chunk_data[] = "IDAT"; +static const char png_chunk_end[] = "IEND"; + +typedef struct pdf_object pdf_object; + +enum { + OBJ_none, /* skipped */ + OBJ_info, + OBJ_stream, + OBJ_font, + OBJ_page, + OBJ_bookmark, + OBJ_outline, + OBJ_catalog, + OBJ_pages, + OBJ_image, + OBJ_link, + + OBJ_count, +}; + +struct flexarray { + void ***bins; + int item_count; + int bin_count; +}; + +/** + * Simple dynamic string object. Tries to store a reasonable amount on the + * stack before falling back to malloc once things get large + */ +struct dstr { + char static_data[128]; + char *data; + size_t alloc_len; + size_t used_len; +}; + +struct pdf_object { + int type; /* See OBJ_xxxx */ + int index; /* PDF output index */ + int offset; /* Byte position within the output file */ + struct pdf_object *prev; /* Previous of this type */ + struct pdf_object *next; /* Next of this type */ + union { + struct { + struct pdf_object *page; + char name[64]; + struct pdf_object *parent; + struct flexarray children; + } bookmark; + struct dstr stream; + struct { + float width; + float height; + struct flexarray children; + struct flexarray annotations; + } page; + struct pdf_info *info; + struct { + char name[64]; + int index; + } font; + struct { + struct pdf_object *page; /* Page containing link */ + float llx; /* Clickable rectangle */ + float lly; + float urx; + float ury; + struct pdf_object *target_page; /* Target page */ + float target_x; /* Target location */ + float target_y; + } link; + }; +}; + +struct pdf_doc { + char errstr[128]; + int errval; + struct flexarray objects; + + float width; + float height; + + struct pdf_object *current_font; + + struct pdf_object *last_objects[OBJ_count]; + struct pdf_object *first_objects[OBJ_count]; +}; + +/** + * Since we're casting random areas of memory to these, make sure + * they're packed properly to match the image format requirements + */ +#pragma pack(push, 1) +struct png_chunk { + uint32_t length; + // chunk type, see png_chunk_header, png_chunk_data, png_chunk_end + char type[4]; +}; + +#pragma pack(pop) + +// Simple data container to store a single 24 Bit RGB value, used for +// processing PNG images +struct rgb_value { + uint8_t red; + uint8_t blue; + uint8_t green; +}; + +/** + * Simple flexible resizing array implementation + * The bins get larger in powers of two + * bin 0 = 1024 items + * 1 = 2048 items + * 2 = 4096 items + * etc... + */ +/* What is the first index that will be in the given bin? */ +#define MIN_SHIFT 10 +#define MIN_OFFSET ((1 << MIN_SHIFT) - 1) +static int bin_offset[] = { + (1 << (MIN_SHIFT + 0)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 1)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 2)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 3)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 4)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 5)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 6)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 7)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 8)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 9)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 10)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 11)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 12)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 13)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 14)) - 1 - MIN_OFFSET, + (1 << (MIN_SHIFT + 15)) - 1 - MIN_OFFSET, +}; + +static inline int flexarray_get_bin(const struct flexarray *flex, int index) +{ + (void)flex; + for (size_t i = 0; i < ARRAY_SIZE(bin_offset); i++) + if (index < bin_offset[i]) + return i - 1; + return -1; +} + +static inline int flexarray_get_bin_size(const struct flexarray *flex, + int bin) +{ + (void)flex; + if (bin >= (int)ARRAY_SIZE(bin_offset) - 1) + return -1; + int next = bin_offset[bin + 1]; + return next - bin_offset[bin]; +} + +static inline int flexarray_get_bin_offset(const struct flexarray *flex, + int bin, int index) +{ + (void)flex; + return index - bin_offset[bin]; +} + +static void flexarray_clear(struct flexarray *flex) +{ + for (int i = 0; i < flex->bin_count; i++) + free(flex->bins[i]); + free(flex->bins); + flex->bin_count = 0; + flex->item_count = 0; +} + +static inline int flexarray_size(const struct flexarray *flex) +{ + return flex->item_count; +} + +static int flexarray_set(struct flexarray *flex, int index, void *data) +{ + int bin = flexarray_get_bin(flex, index); + if (bin < 0) + return -EINVAL; + if (bin >= flex->bin_count) { + void ***bins = (void ***)realloc(flex->bins, (flex->bin_count + 1) * + sizeof(*flex->bins)); + if (!bins) + return -ENOMEM; + flex->bin_count++; + flex->bins = bins; + flex->bins[flex->bin_count - 1] = + (void **)calloc(flexarray_get_bin_size(flex, flex->bin_count - 1), + sizeof(void *)); + if (!flex->bins[flex->bin_count - 1]) { + flex->bin_count--; + return -ENOMEM; + } + } + flex->item_count++; + flex->bins[bin][flexarray_get_bin_offset(flex, bin, index)] = data; + return flex->item_count - 1; +} + +static inline int flexarray_append(struct flexarray *flex, void *data) +{ + return flexarray_set(flex, flexarray_size(flex), data); +} + +static inline void *flexarray_get(const struct flexarray *flex, int index) +{ + int bin; + + if (index >= flex->item_count) + return NULL; + bin = flexarray_get_bin(flex, index); + if (bin < 0 || bin >= flex->bin_count) + return NULL; + return flex->bins[bin][flexarray_get_bin_offset(flex, bin, index)]; +} + +/** + * Simple dynamic string object. Tries to store a reasonable amount on the + * stack before falling back to malloc once things get large + */ + +#define INIT_DSTR \ + (struct dstr) \ + { \ + .static_data = {0}, .data = NULL, .alloc_len = 0, .used_len = 0 \ + } + +static char *dstr_data(struct dstr *str) +{ + return str->data ? str->data : str->static_data; +} + +static size_t dstr_len(const struct dstr *str) +{ + return str->used_len; +} + +static ssize_t dstr_ensure(struct dstr *str, size_t len) +{ + if (len <= str->alloc_len) + return 0; + if (!str->data && len <= sizeof(str->static_data)) + str->alloc_len = len; + else if (str->alloc_len < len) { + size_t new_len; + + new_len = len + 4096; + + if (str->data) { + char *new_data = (char *)realloc((void *)str->data, new_len); + if (!new_data) + return -ENOMEM; + str->data = new_data; + } else { + str->data = (char *)malloc(new_len); + if (!str->data) + return -ENOMEM; + if (str->used_len) + memcpy(str->data, str->static_data, str->used_len + 1); + } + + str->alloc_len = new_len; + } + return 0; +} + +// Locales can replace the decimal character with a ','. +// This breaks the PDF output, so we force a 'safe' locale. +static void force_locale(char *buf, int len) +{ + char *saved_locale = setlocale(LC_ALL, NULL); + + if (!saved_locale) { + *buf = '\0'; + } else { + strncpy(buf, saved_locale, len - 1); + buf[len - 1] = '\0'; + } + + setlocale(LC_NUMERIC, "POSIX"); +} + +static void restore_locale(char *buf) +{ + setlocale(LC_ALL, buf); +} + +#ifndef SKIP_ATTRIBUTE +static int dstr_printf(struct dstr *str, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#endif +static int dstr_printf(struct dstr *str, const char *fmt, ...) +{ + va_list ap, aq; + int len; + char saved_locale[32]; + + force_locale(saved_locale, sizeof(saved_locale)); + + va_start(ap, fmt); + va_copy(aq, ap); + len = vsnprintf(NULL, 0, fmt, ap); + if (dstr_ensure(str, str->used_len + len + 1) < 0) { + va_end(ap); + va_end(aq); + restore_locale(saved_locale); + return -ENOMEM; + } + vsprintf(dstr_data(str) + str->used_len, fmt, aq); + str->used_len += len; + va_end(ap); + va_end(aq); + restore_locale(saved_locale); + + return len; +} + +static ssize_t dstr_append_data(struct dstr *str, const void *extend, + size_t len) +{ + if (dstr_ensure(str, str->used_len + len + 1) < 0) + return -ENOMEM; + memcpy(dstr_data(str) + str->used_len, extend, len); + str->used_len += len; + dstr_data(str)[str->used_len] = '\0'; + return len; +} + +static ssize_t dstr_append(struct dstr *str, const char *extend) +{ + return dstr_append_data(str, extend, strlen(extend)); +} + +static void dstr_free(struct dstr *str) +{ + if (str->data) + free(str->data); + *str = INIT_DSTR; +} + +/** + * PDF Implementation + */ + +#ifndef SKIP_ATTRIBUTE +static int pdf_set_err(struct pdf_doc *doc, int errval, const char *buffer, + ...) __attribute__((format(printf, 3, 4))); +#endif +static int pdf_set_err(struct pdf_doc *doc, int errval, const char *buffer, + ...) +{ + va_list ap; + int len; + + va_start(ap, buffer); + len = vsnprintf(doc->errstr, sizeof(doc->errstr) - 1, buffer, ap); + va_end(ap); + + if (len < 0) { + doc->errstr[0] = '\0'; + return errval; + } + + if (len >= (int)(sizeof(doc->errstr) - 1)) + len = (int)(sizeof(doc->errstr) - 1); + + doc->errstr[len] = '\0'; + doc->errval = errval; + + return errval; +} + +const char *pdf_get_err(const struct pdf_doc *pdf, int *errval) +{ + if (!pdf) + return NULL; + if (pdf->errstr[0] == '\0') + return NULL; + if (errval) + *errval = pdf->errval; + return pdf->errstr; +} + +void pdf_clear_err(struct pdf_doc *pdf) +{ + if (!pdf) + return; + pdf->errstr[0] = '\0'; + pdf->errval = 0; +} + +static int pdf_get_errval(struct pdf_doc *pdf) +{ + if (!pdf) + return 0; + return pdf->errval; +} + +static struct pdf_object *pdf_get_object(const struct pdf_doc *pdf, int index) +{ + return (struct pdf_object *)flexarray_get(&pdf->objects, index); +} + +static int pdf_append_object(struct pdf_doc *pdf, struct pdf_object *obj) +{ + int index = flexarray_append(&pdf->objects, obj); + + if (index < 0) + return index; + obj->index = index; + + if (pdf->last_objects[obj->type]) { + obj->prev = pdf->last_objects[obj->type]; + pdf->last_objects[obj->type]->next = obj; + } + pdf->last_objects[obj->type] = obj; + + if (!pdf->first_objects[obj->type]) + pdf->first_objects[obj->type] = obj; + + return 0; +} + +static void pdf_object_destroy(struct pdf_object *object) +{ + switch (object->type) { + case OBJ_stream: + case OBJ_image: + dstr_free(&object->stream); + break; + case OBJ_page: + flexarray_clear(&object->page.children); + flexarray_clear(&object->page.annotations); + break; + case OBJ_info: + free(object->info); + break; + case OBJ_bookmark: + flexarray_clear(&object->bookmark.children); + break; + } + free(object); +} + +static struct pdf_object *pdf_add_object(struct pdf_doc *pdf, int type) +{ + struct pdf_object *obj; + + if (!pdf) + return NULL; + + obj = (struct pdf_object *)calloc(1, sizeof(*obj)); + if (!obj) { + pdf_set_err(pdf, -errno, + "Unable to allocate object %d of type %d: %s", + flexarray_size(&pdf->objects) + 1, type, strerror(errno)); + return NULL; + } + + obj->type = type; + + if (pdf_append_object(pdf, obj) < 0) { + free(obj); + return NULL; + } + + return obj; +} + +static void pdf_del_object(struct pdf_doc *pdf, struct pdf_object *obj) +{ + int type = obj->type; + flexarray_set(&pdf->objects, obj->index, NULL); + if (pdf->last_objects[type] == obj) { + pdf->last_objects[type] = NULL; + for (int i = 0; i < flexarray_size(&pdf->objects); i++) { + struct pdf_object *o = pdf_get_object(pdf, i); + if (o && o->type == type) + pdf->last_objects[type] = o; + } + } + + if (pdf->first_objects[type] == obj) { + pdf->first_objects[type] = NULL; + for (int i = 0; i < flexarray_size(&pdf->objects); i++) { + struct pdf_object *o = pdf_get_object(pdf, i); + if (o && o->type == type) { + pdf->first_objects[type] = o; + break; + } + } + } + + pdf_object_destroy(obj); +} + +struct pdf_doc *pdf_create(float width, float height, + const struct pdf_info *info) +{ + struct pdf_doc *pdf; + struct pdf_object *obj; + + pdf = (struct pdf_doc *)calloc(1, sizeof(*pdf)); + if (!pdf) + return NULL; + pdf->width = width; + pdf->height = height; + + /* We don't want to use ID 0 */ + pdf_add_object(pdf, OBJ_none); + + /* Create the 'info' object */ + obj = pdf_add_object(pdf, OBJ_info); + if (!obj) { + pdf_destroy(pdf); + return NULL; + } + obj->info = (struct pdf_info *)calloc(sizeof(*obj->info), 1); + if (!obj->info) { + pdf_destroy(pdf); + return NULL; + } + if (info) { + *obj->info = *info; + obj->info->creator[sizeof(obj->info->creator) - 1] = '\0'; + obj->info->producer[sizeof(obj->info->producer) - 1] = '\0'; + obj->info->title[sizeof(obj->info->title) - 1] = '\0'; + obj->info->author[sizeof(obj->info->author) - 1] = '\0'; + obj->info->subject[sizeof(obj->info->subject) - 1] = '\0'; + obj->info->date[sizeof(obj->info->date) - 1] = '\0'; + } + /* FIXME: Should be quoting PDF strings? */ + if (!obj->info->date[0]) { + time_t now = time(NULL); + struct tm tm; +#ifdef _WIN32 + struct tm *tmp; + tmp = localtime(&now); + tm = *tmp; +#else + localtime_r(&now, &tm); +#endif + strftime(obj->info->date, sizeof(obj->info->date), "%Y%m%d%H%M%SZ", + &tm); + } + + if (!pdf_add_object(pdf, OBJ_pages)) { + pdf_destroy(pdf); + return NULL; + } + if (!pdf_add_object(pdf, OBJ_catalog)) { + pdf_destroy(pdf); + return NULL; + } + + if (pdf_set_font(pdf, "Times-Roman") < 0) { + pdf_destroy(pdf); + return NULL; + } + + return pdf; +} + +float pdf_width(const struct pdf_doc *pdf) +{ + return pdf->width; +} + +float pdf_height(const struct pdf_doc *pdf) +{ + return pdf->height; +} + +float pdf_page_width(const struct pdf_object *page) +{ + return page->page.width; +} + +float pdf_page_height(const struct pdf_object *page) +{ + return page->page.height; +} + +void pdf_destroy(struct pdf_doc *pdf) +{ + if (pdf) { + for (int i = 0; i < flexarray_size(&pdf->objects); i++) + pdf_object_destroy(pdf_get_object(pdf, i)); + flexarray_clear(&pdf->objects); + free(pdf); + } +} + +static struct pdf_object *pdf_find_first_object(const struct pdf_doc *pdf, + int type) +{ + if (!pdf) + return NULL; + return pdf->first_objects[type]; +} + +static struct pdf_object *pdf_find_last_object(const struct pdf_doc *pdf, + int type) +{ + if (!pdf) + return NULL; + return pdf->last_objects[type]; +} + +int pdf_set_font(struct pdf_doc *pdf, const char *font) +{ + struct pdf_object *obj; + int last_index = 0; + + /* See if we've used this font before */ + for (obj = pdf_find_first_object(pdf, OBJ_font); obj; obj = obj->next) { + if (strcmp(obj->font.name, font) == 0) + break; + last_index = obj->font.index; + } + + /* Create a new font object if we need it */ + if (!obj) { + obj = pdf_add_object(pdf, OBJ_font); + if (!obj) + return pdf->errval; + strncpy(obj->font.name, font, sizeof(obj->font.name) - 1); + obj->font.name[sizeof(obj->font.name) - 1] = '\0'; + obj->font.index = last_index + 1; + } + + pdf->current_font = obj; + + return 0; +} + +struct pdf_object *pdf_append_page(struct pdf_doc *pdf) +{ + struct pdf_object *page; + + page = pdf_add_object(pdf, OBJ_page); + + if (!page) + return NULL; + + page->page.width = pdf->width; + page->page.height = pdf->height; + + return page; +} + +int pdf_page_set_size(struct pdf_doc *pdf, struct pdf_object *page, + float width, float height) +{ + if (!page) + page = pdf_find_last_object(pdf, OBJ_page); + + if (!page || page->type != OBJ_page) + return pdf_set_err(pdf, -EINVAL, "Invalid PDF page"); + page->page.width = width; + page->page.height = height; + return 0; +} + +// Recursively scan for the number of children +static int pdf_get_bookmark_count(const struct pdf_object *obj) +{ + int count = 0; + if (obj->type == OBJ_bookmark) { + int nchildren = flexarray_size(&obj->bookmark.children); + count += nchildren; + for (int i = 0; i < nchildren; i++) { + count += pdf_get_bookmark_count( + (const struct pdf_object *)flexarray_get( + &obj->bookmark.children, i)); + } + } + return count; +} + +static int pdf_save_object(struct pdf_doc *pdf, FILE *fp, int index) +{ + struct pdf_object *object = pdf_get_object(pdf, index); + if (!object) + return -ENOENT; + + if (object->type == OBJ_none) + return -ENOENT; + + object->offset = ftell(fp); + + fprintf(fp, "%d 0 obj\r\n", index); + + switch (object->type) { + case OBJ_stream: + case OBJ_image: { + fwrite(dstr_data(&object->stream), dstr_len(&object->stream), 1, fp); + break; + } + case OBJ_info: { + struct pdf_info *info = object->info; + + fprintf(fp, "<<\r\n"); + if (info->creator[0]) + fprintf(fp, " /Creator (%s)\r\n", info->creator); + if (info->producer[0]) + fprintf(fp, " /Producer (%s)\r\n", info->producer); + if (info->title[0]) + fprintf(fp, " /Title (%s)\r\n", info->title); + if (info->author[0]) + fprintf(fp, " /Author (%s)\r\n", info->author); + if (info->subject[0]) + fprintf(fp, " /Subject (%s)\r\n", info->subject); + if (info->date[0]) + fprintf(fp, " /CreationDate (D:%s)\r\n", info->date); + fprintf(fp, ">>\r\n"); + break; + } + + case OBJ_page: { + struct pdf_object *pages = pdf_find_first_object(pdf, OBJ_pages); + struct pdf_object *image = pdf_find_first_object(pdf, OBJ_image); + + fprintf(fp, + "<<\r\n" + " /Type /Page\r\n" + " /Parent %d 0 R\r\n", + pages->index); + fprintf(fp, " /MediaBox [0 0 %f %f]\r\n", object->page.width, + object->page.height); + fprintf(fp, " /Resources <<\r\n"); + fprintf(fp, " /Font <<\r\n"); + for (struct pdf_object *font = pdf_find_first_object(pdf, OBJ_font); + font; font = font->next) + fprintf(fp, " /F%d %d 0 R\r\n", font->font.index, + font->index); + fprintf(fp, " >>\r\n"); + // We trim transparency to just 4-bits + fprintf(fp, " /ExtGState <<\r\n"); + for (int i = 0; i < 16; i++) { + fprintf(fp, " /GS%d <</ca %f>>\r\n", i, + (float)(15 - i) / 15); + } + fprintf(fp, " >>\r\n"); + + if (image) { + fprintf(fp, " /XObject <<"); + for (; image; image = image->next) + fprintf(fp, " /Image%d %d 0 R ", image->index, + image->index); + fprintf(fp, " >>\r\n"); + } + fprintf(fp, " >>\r\n"); + + fprintf(fp, " /Contents [\r\n"); + for (int i = 0; i < flexarray_size(&object->page.children); i++) { + struct pdf_object *child = + (struct pdf_object *)flexarray_get(&object->page.children, i); + fprintf(fp, "%d 0 R\r\n", child->index); + } + fprintf(fp, "]\r\n"); + + if (flexarray_size(&object->page.annotations)) { + fprintf(fp, " /Annots [\r\n"); + for (int i = 0; i < flexarray_size(&object->page.annotations); + i++) { + struct pdf_object *child = (struct pdf_object *)flexarray_get( + &object->page.annotations, i); + fprintf(fp, "%d 0 R\r\n", child->index); + } + fprintf(fp, "]\r\n"); + } + + fprintf(fp, ">>\r\n"); + break; + } + + case OBJ_bookmark: { + struct pdf_object *parent, *other; + + parent = object->bookmark.parent; + if (!parent) + parent = pdf_find_first_object(pdf, OBJ_outline); + if (!object->bookmark.page) + break; + fprintf(fp, + "<<\r\n" + " /Dest [%d 0 R /XYZ 0 %f null]\r\n" + " /Parent %d 0 R\r\n" + " /Title (%s)\r\n", + object->bookmark.page->index, pdf->height, parent->index, + object->bookmark.name); + int nchildren = flexarray_size(&object->bookmark.children); + if (nchildren > 0) { + struct pdf_object *f, *l; + f = (struct pdf_object *)flexarray_get(&object->bookmark.children, + 0); + l = (struct pdf_object *)flexarray_get(&object->bookmark.children, + nchildren - 1); + fprintf(fp, " /First %d 0 R\r\n", f->index); + fprintf(fp, " /Last %d 0 R\r\n", l->index); + fprintf(fp, " /Count %d\r\n", pdf_get_bookmark_count(object)); + } + // Find the previous bookmark with the same parent + for (other = object->prev; + other && other->bookmark.parent != object->bookmark.parent; + other = other->prev) + ; + if (other) + fprintf(fp, " /Prev %d 0 R\r\n", other->index); + // Find the next bookmark with the same parent + for (other = object->next; + other && other->bookmark.parent != object->bookmark.parent; + other = other->next) + ; + if (other) + fprintf(fp, " /Next %d 0 R\r\n", other->index); + fprintf(fp, ">>\r\n"); + break; + } + + case OBJ_outline: { + struct pdf_object *first, *last, *cur; + first = pdf_find_first_object(pdf, OBJ_bookmark); + last = pdf_find_last_object(pdf, OBJ_bookmark); + + if (first && last) { + int count = 0; + cur = first; + while (cur) { + if (!cur->bookmark.parent) + count += pdf_get_bookmark_count(cur) + 1; + cur = cur->next; + } + + /* Bookmark outline */ + fprintf(fp, + "<<\r\n" + " /Count %d\r\n" + " /Type /Outlines\r\n" + " /First %d 0 R\r\n" + " /Last %d 0 R\r\n" + ">>\r\n", + count, first->index, last->index); + } + break; + } + + case OBJ_font: + fprintf(fp, + "<<\r\n" + " /Type /Font\r\n" + " /Subtype /Type1\r\n" + " /BaseFont /%s\r\n" + " /Encoding /WinAnsiEncoding\r\n" + ">>\r\n", + object->font.name); + break; + + case OBJ_pages: { + int npages = 0; + + fprintf(fp, "<<\r\n" + " /Type /Pages\r\n" + " /Kids [ "); + for (struct pdf_object *page = pdf_find_first_object(pdf, OBJ_page); + page; page = page->next) { + npages++; + fprintf(fp, "%d 0 R ", page->index); + } + fprintf(fp, "]\r\n"); + fprintf(fp, " /Count %d\r\n", npages); + fprintf(fp, ">>\r\n"); + break; + } + + case OBJ_catalog: { + struct pdf_object *outline = pdf_find_first_object(pdf, OBJ_outline); + struct pdf_object *pages = pdf_find_first_object(pdf, OBJ_pages); + + fprintf(fp, "<<\r\n" + " /Type /Catalog\r\n"); + if (outline) + fprintf(fp, + " /Outlines %d 0 R\r\n" + " /PageMode /UseOutlines\r\n", + outline->index); + fprintf(fp, + " /Pages %d 0 R\r\n" + ">>\r\n", + pages->index); + break; + } + + case OBJ_link: { + fprintf(fp, + "<<\r\n" + " /Type /Annot\r\n" + " /Subtype /Link\r\n" + " /Rect [%f %f %f %f]\r\n" + " /Dest [%u 0 R /XYZ %f %f null]\r\n" + " /Border [0 0 0]\r\n" + ">>\r\n", + object->link.llx, object->link.lly, object->link.urx, + object->link.ury, object->link.target_page->index, + object->link.target_x, object->link.target_y); + break; + } + + default: + return pdf_set_err(pdf, -EINVAL, "Invalid PDF object type %d", + object->type); + } + + fprintf(fp, "endobj\r\n"); + + return 0; +} + +// Slightly modified djb2 hash algorithm to get pseudo-random ID +static uint64_t hash(uint64_t hash, const void *data, size_t len) +{ + const uint8_t *d8 = (const uint8_t *)data; + for (; len; len--) { + hash = (((hash & 0x03ffffffffffffff) << 5) + + (hash & 0x7fffffffffffffff)) + + *d8++; + } + return hash; +} + +int pdf_save_file(struct pdf_doc *pdf, FILE *fp) +{ + struct pdf_object *obj; + int xref_offset; + int xref_count = 0; + uint64_t id1, id2; + time_t now = time(NULL); + char saved_locale[32]; + + force_locale(saved_locale, sizeof(saved_locale)); + + fprintf(fp, "%%PDF-1.3\r\n"); + /* Hibit bytes */ + fprintf(fp, "%c%c%c%c%c\r\n", 0x25, 0xc7, 0xec, 0x8f, 0xa2); + + /* Dump all the objects & get their file offsets */ + for (int i = 0; i < flexarray_size(&pdf->objects); i++) + if (pdf_save_object(pdf, fp, i) >= 0) + xref_count++; + + /* xref */ + xref_offset = ftell(fp); + fprintf(fp, "xref\r\n"); + fprintf(fp, "0 %d\r\n", xref_count + 1); + fprintf(fp, "0000000000 65535 f\r\n"); + for (int i = 0; i < flexarray_size(&pdf->objects); i++) { + obj = pdf_get_object(pdf, i); + if (obj->type != OBJ_none) + fprintf(fp, "%10.10d 00000 n\r\n", obj->offset); + } + + fprintf(fp, + "trailer\r\n" + "<<\r\n" + "/Size %d\r\n", + xref_count + 1); + obj = pdf_find_first_object(pdf, OBJ_catalog); + fprintf(fp, "/Root %d 0 R\r\n", obj->index); + obj = pdf_find_first_object(pdf, OBJ_info); + fprintf(fp, "/Info %d 0 R\r\n", obj->index); + /* Generate document unique IDs */ + id1 = hash(5381, obj->info, sizeof(struct pdf_info)); + id1 = hash(id1, &xref_count, sizeof(xref_count)); + id2 = hash(5381, &now, sizeof(now)); + fprintf(fp, "/ID [<%16.16" PRIx64 "> <%16.16" PRIx64 ">]\r\n", id1, id2); + fprintf(fp, ">>\r\n" + "startxref\r\n"); + fprintf(fp, "%d\r\n", xref_offset); + fprintf(fp, "%%%%EOF\r\n"); + + restore_locale(saved_locale); + + return 0; +} + +int pdf_save(struct pdf_doc *pdf, const char *filename) +{ + FILE *fp; + int e; + + if (filename == NULL) + fp = stdout; + else if ((fp = fopen(filename, "wb")) == NULL) + return pdf_set_err(pdf, -errno, "Unable to open '%s': %s", filename, + strerror(errno)); + + e = pdf_save_file(pdf, fp); + + if (fp != stdout) + if (fclose(fp) != 0 && e >= 0) + return pdf_set_err(pdf, -errno, "Unable to close '%s': %s", + filename, strerror(errno)); + + return e; +} + +static int pdf_add_stream(struct pdf_doc *pdf, struct pdf_object *page, + const char *buffer) +{ + struct pdf_object *obj; + size_t len; + + if (!page) + page = pdf_find_last_object(pdf, OBJ_page); + + if (!page) + return pdf_set_err(pdf, -EINVAL, "Invalid pdf page"); + + len = strlen(buffer); + /* We don't want any trailing whitespace in the stream */ + while (len >= 1 && (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')) + len--; + + obj = pdf_add_object(pdf, OBJ_stream); + if (!obj) + return pdf->errval; + + dstr_printf(&obj->stream, "<< /Length %zu >>stream\r\n", len); + dstr_append_data(&obj->stream, buffer, len); + dstr_append(&obj->stream, "\r\nendstream\r\n"); + + return flexarray_append(&page->page.children, obj); +} + +int pdf_add_bookmark(struct pdf_doc *pdf, struct pdf_object *page, int parent, + const char *name) +{ + struct pdf_object *obj, *outline = NULL; + + if (!page) + page = pdf_find_last_object(pdf, OBJ_page); + + if (!page) + return pdf_set_err(pdf, -EINVAL, + "Unable to add bookmark, no pages available"); + + if (!pdf_find_first_object(pdf, OBJ_outline)) { + outline = pdf_add_object(pdf, OBJ_outline); + if (!outline) + return pdf->errval; + } + + obj = pdf_add_object(pdf, OBJ_bookmark); + if (!obj) { + if (outline) + pdf_del_object(pdf, outline); + return pdf->errval; + } + + strncpy(obj->bookmark.name, name, sizeof(obj->bookmark.name) - 1); + obj->bookmark.name[sizeof(obj->bookmark.name) - 1] = '\0'; + obj->bookmark.page = page; + if (parent >= 0) { + struct pdf_object *parent_obj = pdf_get_object(pdf, parent); + if (!parent_obj) + return pdf_set_err(pdf, -EINVAL, "Invalid parent ID %d supplied", + parent); + obj->bookmark.parent = parent_obj; + flexarray_append(&parent_obj->bookmark.children, obj); + } + + return obj->index; +} + +int pdf_add_link(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float width, float height, + struct pdf_object *target_page, float target_x, + float target_y) +{ + struct pdf_object *obj; + + if (!page) + page = pdf_find_last_object(pdf, OBJ_page); + + if (!page) + return pdf_set_err(pdf, -EINVAL, + "Unable to add link, no pages available"); + + if (!target_page) + return pdf_set_err(pdf, -EINVAL, "Unable to link, no target page"); + + obj = pdf_add_object(pdf, OBJ_link); + if (!obj) { + return pdf->errval; + } + + obj->link.target_page = target_page; + obj->link.target_x = target_x; + obj->link.target_y = target_y; + obj->link.llx = x; + obj->link.lly = y; + obj->link.urx = x + width; + obj->link.ury = y + height; + flexarray_append(&page->page.annotations, obj); + + return obj->index; +} + +static int utf8_to_utf32(const char *utf8, int len, uint32_t *utf32) +{ + uint32_t ch; + uint8_t mask; + + if (len <= 0 || !utf8 || !utf32) + return -EINVAL; + + ch = *(uint8_t *)utf8; + if ((ch & 0x80) == 0) { + len = 1; + mask = 0x7f; + } else if ((ch & 0xe0) == 0xc0 && len >= 2) { + len = 2; + mask = 0x1f; + } else if ((ch & 0xf0) == 0xe0 && len >= 3) { + len = 3; + mask = 0xf; + } else if ((ch & 0xf8) == 0xf0 && len >= 4) { + len = 4; + mask = 0x7; + } else + return -EINVAL; + + ch = 0; + for (int i = 0; i < len; i++) { + int shift = (len - i - 1) * 6; + if (!*utf8) + return -EINVAL; + if (i == 0) + ch |= ((uint32_t)(*utf8++) & mask) << shift; + else + ch |= ((uint32_t)(*utf8++) & 0x3f) << shift; + } + + *utf32 = ch; + + return len; +} + +static int utf8_to_pdfencoding(struct pdf_doc *pdf, const char *utf8, int len, + uint8_t *res) +{ + uint32_t code; + int code_len; + + *res = 0; + + code_len = utf8_to_utf32(utf8, len, &code); + if (code_len < 0) { + return pdf_set_err(pdf, -EINVAL, "Invalid UTF-8 encoding"); + } + + if (code > 255) { + /* We support *some* minimal UTF-8 characters */ + // See Appendix D of + // https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf + // These are all in WinAnsiEncoding + switch (code) { + case 0x160: // Latin Capital Letter S with Caron + *res = 0212; + break; + case 0x161: // Latin Small Letter S with Caron + *res = 0232; + break; + case 0x17d: // Latin Capital Letter Z with Caron + *res = 0216; + break; + case 0x17e: // Latin Small Letter Z with Caron + *res = 0236; + break; + case 0x2014: // emdash + *res = 0227; + break; + case 0x2018: // left single quote + *res = 0221; + break; + case 0x2019: // right single quote + *res = 0222; + break; + case 0x201c: // left double quote + *res = 0223; + break; + case 0x201d: // right double quote + *res = 0224; + break; + case 0x20ac: // Euro + *res = 0200; + break; + default: + return pdf_set_err(pdf, -EINVAL, + "Unsupported UTF-8 character: 0x%x 0o%o", code, + code); + } + } else { + *res = code; + } + return code_len; +} + +static int pdf_add_text_spacing(struct pdf_doc *pdf, struct pdf_object *page, + const char *text, float size, float xoff, + float yoff, uint32_t colour, float spacing) +{ + int ret; + size_t len = text ? strlen(text) : 0; + struct dstr str = INIT_DSTR; + int alpha = (colour >> 24) >> 4; + + /* Don't bother adding empty/null strings */ + if (!len) + return 0; + + dstr_append(&str, "BT "); + dstr_printf(&str, "/GS%d gs ", alpha); + dstr_printf(&str, "%f %f TD ", xoff, yoff); + dstr_printf(&str, "/F%d %f Tf ", pdf->current_font->font.index, size); + dstr_printf(&str, "%f %f %f rg ", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f Tc ", spacing); + dstr_append(&str, "("); + + /* Escape magic characters properly */ + for (size_t i = 0; i < len;) { + int code_len; + uint8_t pdf_char; + code_len = utf8_to_pdfencoding(pdf, &text[i], len - i, &pdf_char); + if (code_len < 0) { + dstr_free(&str); + return code_len; + } + + if (strchr("()\\", pdf_char)) { + char buf[3]; + /* Escape some characters */ + buf[0] = '\\'; + buf[1] = pdf_char; + buf[2] = '\0'; + dstr_append(&str, buf); + } else if (strrchr("\n\r\t\b\f", pdf_char)) { + /* Skip over these characters */ + ; + } else { + dstr_append_data(&str, &pdf_char, 1); + } + + i += code_len; + } + dstr_append(&str, ") Tj "); + dstr_append(&str, "ET"); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + return ret; +} + +int pdf_add_text(struct pdf_doc *pdf, struct pdf_object *page, + const char *text, float size, float xoff, float yoff, + uint32_t colour) +{ + return pdf_add_text_spacing(pdf, page, text, size, xoff, yoff, colour, 0); +} + +/* How wide is each character, in points, at size 14 */ +static const uint16_t helvetica_widths[256] = { + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 357, 560, 560, 896, 672, + 192, 335, 335, 392, 588, 280, 335, 280, 280, 560, 560, 560, 560, + 560, 560, 560, 560, 560, 560, 280, 280, 588, 588, 588, 560, 1023, + 672, 672, 727, 727, 672, 615, 784, 727, 280, 504, 672, 560, 839, + 727, 784, 672, 784, 727, 672, 615, 727, 672, 951, 672, 672, 615, + 280, 280, 280, 472, 560, 335, 560, 560, 504, 560, 560, 280, 560, + 560, 223, 223, 504, 223, 839, 560, 560, 560, 560, 335, 504, 280, + 560, 504, 727, 504, 504, 504, 336, 262, 336, 588, 352, 560, 352, + 223, 560, 335, 1008, 560, 560, 335, 1008, 672, 335, 1008, 352, 615, + 352, 352, 223, 223, 335, 335, 352, 560, 1008, 335, 1008, 504, 335, + 951, 352, 504, 672, 280, 335, 560, 560, 560, 560, 262, 560, 335, + 742, 372, 560, 588, 335, 742, 335, 403, 588, 335, 335, 335, 560, + 541, 280, 335, 335, 367, 560, 840, 840, 840, 615, 672, 672, 672, + 672, 672, 672, 1008, 727, 672, 672, 672, 672, 280, 280, 280, 280, + 727, 727, 784, 784, 784, 784, 784, 588, 784, 727, 727, 727, 727, + 672, 672, 615, 560, 560, 560, 560, 560, 560, 896, 504, 560, 560, + 560, 560, 280, 280, 280, 280, 560, 560, 560, 560, 560, 560, 560, + 588, 615, 560, 560, 560, 560, 504, 560, 504, +}; + +static const uint16_t helvetica_bold_widths[256] = { + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 335, 477, 560, 560, 896, 727, 239, 335, 335, + 392, 588, 280, 335, 280, 280, 560, 560, 560, 560, 560, 560, 560, 560, + 560, 560, 335, 335, 588, 588, 588, 615, 982, 727, 727, 727, 727, 672, + 615, 784, 727, 280, 560, 727, 615, 839, 727, 784, 672, 784, 727, 672, + 615, 727, 672, 951, 672, 672, 615, 335, 280, 335, 588, 560, 335, 560, + 615, 560, 615, 560, 335, 615, 615, 280, 280, 560, 280, 896, 615, 615, + 615, 615, 392, 560, 335, 615, 560, 784, 560, 560, 504, 392, 282, 392, + 588, 352, 560, 352, 280, 560, 504, 1008, 560, 560, 335, 1008, 672, 335, + 1008, 352, 615, 352, 352, 280, 280, 504, 504, 352, 560, 1008, 335, 1008, + 560, 335, 951, 352, 504, 672, 280, 335, 560, 560, 560, 560, 282, 560, + 335, 742, 372, 560, 588, 335, 742, 335, 403, 588, 335, 335, 335, 615, + 560, 280, 335, 335, 367, 560, 840, 840, 840, 615, 727, 727, 727, 727, + 727, 727, 1008, 727, 672, 672, 672, 672, 280, 280, 280, 280, 727, 727, + 784, 784, 784, 784, 784, 588, 784, 727, 727, 727, 727, 672, 672, 615, + 560, 560, 560, 560, 560, 560, 896, 560, 560, 560, 560, 560, 280, 280, + 280, 280, 615, 615, 615, 615, 615, 615, 615, 588, 615, 615, 615, 615, + 615, 560, 615, 560, +}; + +static const uint16_t helvetica_bold_oblique_widths[256] = { + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 335, 477, 560, 560, 896, 727, 239, 335, 335, + 392, 588, 280, 335, 280, 280, 560, 560, 560, 560, 560, 560, 560, 560, + 560, 560, 335, 335, 588, 588, 588, 615, 982, 727, 727, 727, 727, 672, + 615, 784, 727, 280, 560, 727, 615, 839, 727, 784, 672, 784, 727, 672, + 615, 727, 672, 951, 672, 672, 615, 335, 280, 335, 588, 560, 335, 560, + 615, 560, 615, 560, 335, 615, 615, 280, 280, 560, 280, 896, 615, 615, + 615, 615, 392, 560, 335, 615, 560, 784, 560, 560, 504, 392, 282, 392, + 588, 352, 560, 352, 280, 560, 504, 1008, 560, 560, 335, 1008, 672, 335, + 1008, 352, 615, 352, 352, 280, 280, 504, 504, 352, 560, 1008, 335, 1008, + 560, 335, 951, 352, 504, 672, 280, 335, 560, 560, 560, 560, 282, 560, + 335, 742, 372, 560, 588, 335, 742, 335, 403, 588, 335, 335, 335, 615, + 560, 280, 335, 335, 367, 560, 840, 840, 840, 615, 727, 727, 727, 727, + 727, 727, 1008, 727, 672, 672, 672, 672, 280, 280, 280, 280, 727, 727, + 784, 784, 784, 784, 784, 588, 784, 727, 727, 727, 727, 672, 672, 615, + 560, 560, 560, 560, 560, 560, 896, 560, 560, 560, 560, 560, 280, 280, + 280, 280, 615, 615, 615, 615, 615, 615, 615, 588, 615, 615, 615, 615, + 615, 560, 615, 560, +}; + +static const uint16_t helvetica_oblique_widths[256] = { + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 357, 560, 560, 896, 672, + 192, 335, 335, 392, 588, 280, 335, 280, 280, 560, 560, 560, 560, + 560, 560, 560, 560, 560, 560, 280, 280, 588, 588, 588, 560, 1023, + 672, 672, 727, 727, 672, 615, 784, 727, 280, 504, 672, 560, 839, + 727, 784, 672, 784, 727, 672, 615, 727, 672, 951, 672, 672, 615, + 280, 280, 280, 472, 560, 335, 560, 560, 504, 560, 560, 280, 560, + 560, 223, 223, 504, 223, 839, 560, 560, 560, 560, 335, 504, 280, + 560, 504, 727, 504, 504, 504, 336, 262, 336, 588, 352, 560, 352, + 223, 560, 335, 1008, 560, 560, 335, 1008, 672, 335, 1008, 352, 615, + 352, 352, 223, 223, 335, 335, 352, 560, 1008, 335, 1008, 504, 335, + 951, 352, 504, 672, 280, 335, 560, 560, 560, 560, 262, 560, 335, + 742, 372, 560, 588, 335, 742, 335, 403, 588, 335, 335, 335, 560, + 541, 280, 335, 335, 367, 560, 840, 840, 840, 615, 672, 672, 672, + 672, 672, 672, 1008, 727, 672, 672, 672, 672, 280, 280, 280, 280, + 727, 727, 784, 784, 784, 784, 784, 588, 784, 727, 727, 727, 727, + 672, 672, 615, 560, 560, 560, 560, 560, 560, 896, 504, 560, 560, + 560, 560, 280, 280, 280, 280, 560, 560, 560, 560, 560, 560, 560, + 588, 615, 560, 560, 560, 560, 504, 560, 504, +}; + +static const uint16_t symbol_widths[256] = { + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 335, 718, 504, 553, 839, 784, 442, 335, 335, + 504, 553, 252, 553, 252, 280, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 280, 280, 553, 553, 553, 447, 553, 727, 672, 727, 616, 615, + 769, 607, 727, 335, 636, 727, 691, 896, 727, 727, 774, 746, 560, 596, + 615, 695, 442, 774, 650, 801, 615, 335, 869, 335, 663, 504, 504, 636, + 553, 553, 497, 442, 525, 414, 607, 331, 607, 553, 553, 580, 525, 553, + 553, 525, 553, 607, 442, 580, 718, 691, 496, 691, 497, 483, 201, 483, + 553, 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, 756, 624, 248, 553, 168, 718, 504, 759, + 759, 759, 759, 1050, 994, 607, 994, 607, 403, 553, 414, 553, 553, 718, + 497, 463, 553, 553, 553, 553, 1008, 607, 1008, 663, 829, 691, 801, 994, + 774, 774, 829, 774, 774, 718, 718, 718, 718, 718, 718, 718, 774, 718, + 796, 796, 897, 829, 553, 252, 718, 607, 607, 1050, 994, 607, 994, 607, + 497, 331, 796, 796, 792, 718, 387, 387, 387, 387, 387, 387, 497, 497, + 497, 497, 0, 331, 276, 691, 691, 691, 387, 387, 387, 387, 387, 387, + 497, 497, 497, 0, +}; + +static const uint16_t times_widths[256] = { + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 335, 411, 504, 504, 839, 784, 181, 335, 335, + 504, 568, 252, 335, 252, 280, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 280, 280, 568, 568, 568, 447, 928, 727, 672, 672, 727, 615, + 560, 727, 727, 335, 392, 727, 615, 896, 727, 727, 560, 727, 672, 560, + 615, 727, 727, 951, 727, 727, 615, 335, 280, 335, 472, 504, 335, 447, + 504, 447, 504, 447, 335, 504, 504, 280, 280, 504, 280, 784, 504, 504, + 504, 504, 335, 392, 280, 504, 504, 727, 504, 504, 447, 483, 201, 483, + 545, 352, 504, 352, 335, 504, 447, 1008, 504, 504, 335, 1008, 560, 335, + 896, 352, 615, 352, 352, 335, 335, 447, 447, 352, 504, 1008, 335, 987, + 392, 335, 727, 352, 447, 727, 252, 335, 504, 504, 504, 504, 201, 504, + 335, 766, 278, 504, 568, 335, 766, 335, 403, 568, 302, 302, 335, 504, + 456, 252, 335, 302, 312, 504, 756, 756, 756, 447, 727, 727, 727, 727, + 727, 727, 896, 672, 615, 615, 615, 615, 335, 335, 335, 335, 727, 727, + 727, 727, 727, 727, 727, 568, 727, 727, 727, 727, 727, 727, 560, 504, + 447, 447, 447, 447, 447, 447, 672, 447, 447, 447, 447, 447, 280, 280, + 280, 280, 504, 504, 504, 504, 504, 504, 504, 568, 504, 504, 504, 504, + 504, 504, 504, 504, +}; + +static const uint16_t times_bold_widths[256] = { + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 335, 559, 504, 504, 1008, 839, + 280, 335, 335, 504, 574, 252, 335, 252, 280, 504, 504, 504, 504, + 504, 504, 504, 504, 504, 504, 335, 335, 574, 574, 574, 504, 937, + 727, 672, 727, 727, 672, 615, 784, 784, 392, 504, 784, 672, 951, + 727, 784, 615, 784, 727, 560, 672, 727, 727, 1008, 727, 727, 672, + 335, 280, 335, 585, 504, 335, 504, 560, 447, 560, 447, 335, 504, + 560, 280, 335, 560, 280, 839, 560, 504, 560, 560, 447, 392, 335, + 560, 504, 727, 504, 504, 447, 397, 221, 397, 524, 352, 504, 352, + 335, 504, 504, 1008, 504, 504, 335, 1008, 560, 335, 1008, 352, 672, + 352, 352, 335, 335, 504, 504, 352, 504, 1008, 335, 1008, 392, 335, + 727, 352, 447, 727, 252, 335, 504, 504, 504, 504, 221, 504, 335, + 752, 302, 504, 574, 335, 752, 335, 403, 574, 302, 302, 335, 560, + 544, 252, 335, 302, 332, 504, 756, 756, 756, 504, 727, 727, 727, + 727, 727, 727, 1008, 727, 672, 672, 672, 672, 392, 392, 392, 392, + 727, 727, 784, 784, 784, 784, 784, 574, 784, 727, 727, 727, 727, + 727, 615, 560, 504, 504, 504, 504, 504, 504, 727, 447, 447, 447, + 447, 447, 280, 280, 280, 280, 504, 560, 504, 504, 504, 504, 504, + 574, 504, 560, 560, 560, 560, 504, 560, 504, +}; + +static const uint16_t times_bold_italic_widths[256] = { + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 392, 559, 504, 504, 839, 784, 280, 335, 335, + 504, 574, 252, 335, 252, 280, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 335, 335, 574, 574, 574, 504, 838, 672, 672, 672, 727, 672, + 672, 727, 784, 392, 504, 672, 615, 896, 727, 727, 615, 727, 672, 560, + 615, 727, 672, 896, 672, 615, 615, 335, 280, 335, 574, 504, 335, 504, + 504, 447, 504, 447, 335, 504, 560, 280, 280, 504, 280, 784, 560, 504, + 504, 504, 392, 392, 280, 560, 447, 672, 504, 447, 392, 350, 221, 350, + 574, 352, 504, 352, 335, 504, 504, 1008, 504, 504, 335, 1008, 560, 335, + 951, 352, 615, 352, 352, 335, 335, 504, 504, 352, 504, 1008, 335, 1008, + 392, 335, 727, 352, 392, 615, 252, 392, 504, 504, 504, 504, 221, 504, + 335, 752, 268, 504, 610, 335, 752, 335, 403, 574, 302, 302, 335, 580, + 504, 252, 335, 302, 302, 504, 756, 756, 756, 504, 672, 672, 672, 672, + 672, 672, 951, 672, 672, 672, 672, 672, 392, 392, 392, 392, 727, 727, + 727, 727, 727, 727, 727, 574, 727, 727, 727, 727, 727, 615, 615, 504, + 504, 504, 504, 504, 504, 504, 727, 447, 447, 447, 447, 447, 280, 280, + 280, 280, 504, 560, 504, 504, 504, 504, 504, 574, 504, 560, 560, 560, + 560, 447, 504, 447, +}; + +static const uint16_t times_italic_widths[256] = { + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 335, 423, 504, 504, 839, 784, 215, 335, 335, + 504, 680, 252, 335, 252, 280, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 335, 335, 680, 680, 680, 504, 927, 615, 615, 672, 727, 615, + 615, 727, 727, 335, 447, 672, 560, 839, 672, 727, 615, 727, 615, 504, + 560, 727, 615, 839, 615, 560, 560, 392, 280, 392, 425, 504, 335, 504, + 504, 447, 504, 447, 280, 504, 504, 280, 280, 447, 280, 727, 504, 504, + 504, 504, 392, 392, 280, 504, 447, 672, 447, 447, 392, 403, 277, 403, + 545, 352, 504, 352, 335, 504, 560, 896, 504, 504, 335, 1008, 504, 335, + 951, 352, 560, 352, 352, 335, 335, 560, 560, 352, 504, 896, 335, 987, + 392, 335, 672, 352, 392, 560, 252, 392, 504, 504, 504, 504, 277, 504, + 335, 766, 278, 504, 680, 335, 766, 335, 403, 680, 302, 302, 335, 504, + 527, 252, 335, 302, 312, 504, 756, 756, 756, 504, 615, 615, 615, 615, + 615, 615, 896, 672, 615, 615, 615, 615, 335, 335, 335, 335, 727, 672, + 727, 727, 727, 727, 727, 680, 727, 727, 727, 727, 727, 560, 615, 504, + 504, 504, 504, 504, 504, 504, 672, 447, 447, 447, 447, 447, 280, 280, + 280, 280, 504, 504, 504, 504, 504, 504, 504, 680, 504, 504, 504, 504, + 504, 447, 504, 447, +}; + +static const uint16_t zapfdingbats_widths[256] = { + 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, 280, 981, 968, 981, 987, 724, 795, 796, 797, 695, + 967, 946, 553, 861, 918, 940, 918, 952, 981, 761, 852, 768, 767, 575, + 682, 769, 766, 765, 760, 497, 556, 541, 581, 697, 792, 794, 794, 796, + 799, 800, 822, 829, 795, 847, 829, 839, 822, 837, 930, 749, 728, 754, + 796, 798, 700, 782, 774, 798, 765, 712, 713, 687, 706, 832, 821, 795, + 795, 712, 692, 701, 694, 792, 793, 718, 797, 791, 797, 879, 767, 768, + 768, 765, 765, 899, 899, 794, 790, 441, 139, 279, 418, 395, 395, 673, + 673, 0, 393, 393, 319, 319, 278, 278, 513, 513, 413, 413, 235, 235, + 336, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 737, 548, 548, 917, 672, 766, 766, + 782, 599, 699, 631, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, + 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, + 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, + 794, 794, 901, 844, 1024, 461, 753, 931, 753, 925, 934, 935, 935, 840, + 879, 834, 931, 931, 924, 937, 938, 466, 890, 842, 842, 873, 873, 701, + 701, 880, 0, 880, 766, 953, 777, 871, 777, 895, 974, 895, 837, 879, + 934, 977, 925, 0, +}; + +static const uint16_t courier_widths[256] = { + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, + 604, +}; + +static int pdf_text_point_width(struct pdf_doc *pdf, const char *text, + ptrdiff_t text_len, float size, + const uint16_t *widths, float *point_width) +{ + uint32_t len = 0; + if (text_len < 0) + text_len = strlen(text); + *point_width = 0.0f; + + for (int i = 0; i < (int)text_len;) { + uint8_t pdf_char = 0; + int code_len; + code_len = + utf8_to_pdfencoding(pdf, &text[i], text_len - i, &pdf_char); + if (code_len < 0) + return pdf_set_err(pdf, code_len, + "Invalid unicode string at position %d in %s", + i, text); + i += code_len; + + if (pdf_char != '\n' && pdf_char != '\r') + len += widths[pdf_char]; + } + + /* Our widths arrays are for 14pt fonts */ + *point_width = len * size / (14.0f * 72.0f); + + return 0; +} + +static const uint16_t *find_font_widths(const char *font_name) +{ + if (strcasecmp(font_name, "Helvetica") == 0) + return helvetica_widths; + if (strcasecmp(font_name, "Helvetica-Bold") == 0) + return helvetica_bold_widths; + if (strcasecmp(font_name, "Helvetica-BoldOblique") == 0) + return helvetica_bold_oblique_widths; + if (strcasecmp(font_name, "Helvetica-Oblique") == 0) + return helvetica_oblique_widths; + if (strcasecmp(font_name, "Courier") == 0 || + strcasecmp(font_name, "Courier-Bold") == 0 || + strcasecmp(font_name, "Courier-BoldOblique") == 0 || + strcasecmp(font_name, "Courier-Oblique") == 0) + return courier_widths; + if (strcasecmp(font_name, "Times-Roman") == 0) + return times_widths; + if (strcasecmp(font_name, "Times-Bold") == 0) + return times_bold_widths; + if (strcasecmp(font_name, "Times-Italic") == 0) + return times_italic_widths; + if (strcasecmp(font_name, "Times-BoldItalic") == 0) + return times_bold_italic_widths; + if (strcasecmp(font_name, "Symbol") == 0) + return symbol_widths; + if (strcasecmp(font_name, "ZapfDingbats") == 0) + return zapfdingbats_widths; + + return NULL; +} + +int pdf_get_font_text_width(struct pdf_doc *pdf, const char *font_name, + const char *text, float size, float *text_width) +{ + if (!font_name) + font_name = pdf->current_font->font.name; + const uint16_t *widths = find_font_widths(font_name); + + if (!widths) + return pdf_set_err(pdf, -EINVAL, + "Unable to determine width for font '%s'", + pdf->current_font->font.name); + return pdf_text_point_width(pdf, text, -1, size, widths, text_width); +} + +static const char *find_word_break(const char *string) +{ + /* Skip over the actual word */ + while (string && *string && (*string < 0 || !isspace(*string))) + string++; + + return string; +} + +int pdf_add_text_wrap(struct pdf_doc *pdf, struct pdf_object *page, + const char *text, float size, float xoff, float yoff, + uint32_t colour, float wrap_width, int align, + float *height) +{ + /* Move through the text string, stopping at word boundaries, + * trying to find the longest text string we can fit in the given width + */ + const char *start = text; + const char *last_best = text; + const char *end = text; + char line[512]; + const uint16_t *widths; + float orig_yoff = yoff; + + widths = find_font_widths(pdf->current_font->font.name); + if (!widths) + return pdf_set_err(pdf, -EINVAL, + "Unable to determine width for font '%s'", + pdf->current_font->font.name); + + while (start && *start) { + const char *new_end = find_word_break(end + 1); + float line_width; + int output = 0; + float xoff_align = xoff; + int e; + + end = new_end; + + e = pdf_text_point_width(pdf, start, end - start, size, widths, + &line_width); + if (e < 0) + return e; + + if (line_width >= wrap_width) { + if (last_best == start) { + /* There is a single word that is too long for the line */ + ptrdiff_t i; + /* Find the best character to chop it at */ + for (i = end - start - 1; i > 0; i--) { + float this_width; + // Don't look at places that are in the middle of a utf-8 + // sequence + if ((start[i - 1] & 0xc0) == 0xc0 || + ((start[i - 1] & 0xc0) == 0x80 && + (start[i] & 0xc0) == 0x80)) + continue; + e = pdf_text_point_width(pdf, start, i, size, widths, + &this_width); + if (e < 0) + return e; + if (this_width < wrap_width) + break; + } + if (i == 0) + return pdf_set_err(pdf, -EINVAL, + "Unable to find suitable line break"); + + end = start + i; + } else + end = last_best; + output = 1; + } + if (*end == '\0') + output = 1; + + if (*end == '\n' || *end == '\r') + output = 1; + + if (output) { + int len = end - start; + float char_spacing = 0; + if (len >= (int)sizeof(line)) + len = (int)sizeof(line) - 1; + strncpy(line, start, len); + line[len] = '\0'; + + e = pdf_text_point_width(pdf, start, len, size, widths, + &line_width); + if (e < 0) + return e; + + switch (align) { + case PDF_ALIGN_RIGHT: + xoff_align += wrap_width - line_width; + break; + case PDF_ALIGN_CENTER: + xoff_align += (wrap_width - line_width) / 2; + break; + case PDF_ALIGN_JUSTIFY: + if ((len - 1) > 0 && *end != '\r' && *end != '\n' && + *end != '\0') + char_spacing = (wrap_width - line_width) / (len - 2); + break; + case PDF_ALIGN_JUSTIFY_ALL: + if ((len - 1) > 0) + char_spacing = (wrap_width - line_width) / (len - 2); + break; + } + + if (align != PDF_ALIGN_NO_WRITE) { + pdf_add_text_spacing(pdf, page, line, size, xoff_align, yoff, + colour, char_spacing); + } + + if (*end == ' ') + end++; + + start = last_best = end; + yoff -= size; + } else + last_best = end; + } + + if (height) + *height = orig_yoff - yoff; + return 0; +} + +int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, + float y1, float x2, float y2, float width, uint32_t colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f w\r\n", width); + dstr_printf(&str, "%f %f m\r\n", x1, y1); + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f RG\r\n", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f %f l S\r\n", x2, y2); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_cubic_bezier(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, float xq1, + float yq1, float xq2, float yq2, float width, + uint32_t colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f w\r\n", width); + dstr_printf(&str, "%f %f m\r\n", x1, y1); + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f RG\r\n", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f %f %f %f %f %f c S\r\n", xq1, yq1, xq2, yq2, x2, + y2); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_quadratic_bezier(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, + float xq1, float yq1, float width, + uint32_t colour) +{ + float xc1 = x1 + (xq1 - x1) * (2.0f / 3.0f); + float yc1 = y1 + (yq1 - y1) * (2.0f / 3.0f); + float xc2 = x2 + (xq1 - x2) * (2.0f / 3.0f); + float yc2 = y2 + (yq1 - y2) * (2.0f / 3.0f); + return pdf_add_cubic_bezier(pdf, page, x1, y1, x2, y2, xc1, yc1, xc2, yc2, + width, colour); +} + +int pdf_add_custom_path(struct pdf_doc *pdf, struct pdf_object *page, + struct pdf_path_operation *operations, + int operation_count, float stroke_width, + uint32_t stroke_colour, uint32_t fill_colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + if (!PDF_IS_TRANSPARENT(fill_colour)) { + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f rg\r\n", PDF_RGB_R(fill_colour), + PDF_RGB_G(fill_colour), PDF_RGB_B(fill_colour)); + } + dstr_printf(&str, "%f w\r\n", stroke_width); + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f RG\r\n", PDF_RGB_R(stroke_colour), + PDF_RGB_G(stroke_colour), PDF_RGB_B(stroke_colour)); + + for (int i = 0; i < operation_count; i++) { + struct pdf_path_operation operation = operations[i]; + switch (operation.op) { + case 'm': + dstr_printf(&str, "%f %f m\r\n", operation.x1, operation.y1); + break; + case 'l': + dstr_printf(&str, "%f %f l\r\n", operation.x1, operation.y1); + break; + case 'c': + dstr_printf(&str, "%f %f %f %f %f %f c\r\n", operation.x1, + operation.y1, operation.x2, operation.y2, + operation.x3, operation.y3); + break; + case 'v': + dstr_printf(&str, "%f %f %f %f v\r\n", operation.x1, operation.y1, + operation.x2, operation.y2); + break; + case 'y': + dstr_printf(&str, "%f %f %f %f y\r\n", operation.x1, operation.y1, + operation.x2, operation.y2); + break; + case 'h': + dstr_printf(&str, "h\r\n"); + break; + default: + return pdf_set_err(pdf, -errno, "Invalid operation"); + break; + } + } + + if (PDF_IS_TRANSPARENT(fill_colour)) + dstr_printf(&str, "%s", "S "); + else + dstr_printf(&str, "%s", "B "); + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_ellipse(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float xradius, float yradius, float width, + uint32_t colour, uint32_t fill_colour) +{ + int ret; + struct dstr str = INIT_DSTR; + float lx, ly; + + lx = (4.0f / 3.0f) * (M_SQRT2 - 1) * xradius; + ly = (4.0f / 3.0f) * (M_SQRT2 - 1) * yradius; + + if (!PDF_IS_TRANSPARENT(fill_colour)) { + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f rg\r\n", PDF_RGB_R(fill_colour), + PDF_RGB_G(fill_colour), PDF_RGB_B(fill_colour)); + } + + /* stroke color */ + dstr_printf(&str, "/DeviceRGB CS\r\n"); + dstr_printf(&str, "%f %f %f RG\r\n", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + + dstr_printf(&str, "%f w ", width); + + dstr_printf(&str, "%.2f %.2f m ", (x + xradius), (y)); + + dstr_printf(&str, "%.2f %.2f %.2f %.2f %.2f %.2f c ", (x + xradius), + (y - ly), (x + lx), (y - yradius), x, (y - yradius)); + + dstr_printf(&str, "%.2f %.2f %.2f %.2f %.2f %.2f c ", (x - lx), + (y - yradius), (x - xradius), (y - ly), (x - xradius), y); + + dstr_printf(&str, "%.2f %.2f %.2f %.2f %.2f %.2f c ", (x - xradius), + (y + ly), (x - lx), (y + yradius), x, (y + yradius)); + + dstr_printf(&str, "%.2f %.2f %.2f %.2f %.2f %.2f c ", (x + lx), + (y + yradius), (x + xradius), (y + ly), (x + xradius), y); + + if (PDF_IS_TRANSPARENT(fill_colour)) + dstr_printf(&str, "%s", "S "); + else + dstr_printf(&str, "%s", "B "); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_circle(struct pdf_doc *pdf, struct pdf_object *page, float xr, + float yr, float radius, float width, uint32_t colour, + uint32_t fill_colour) +{ + return pdf_add_ellipse(pdf, page, xr, yr, radius, radius, width, colour, + fill_colour); +} + +int pdf_add_rectangle(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float width, float height, float border_width, + uint32_t colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f %f %f RG ", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f w ", border_width); + dstr_printf(&str, "%f %f %f %f re S ", x, y, width, height); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_filled_rectangle(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + float border_width, uint32_t colour_fill, + uint32_t colour_border) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f %f %f rg ", PDF_RGB_R(colour_fill), + PDF_RGB_G(colour_fill), PDF_RGB_B(colour_fill)); + if (border_width > 0) { + dstr_printf(&str, "%f %f %f RG ", PDF_RGB_R(colour_border), + PDF_RGB_G(colour_border), PDF_RGB_B(colour_border)); + dstr_printf(&str, "%f w ", border_width); + dstr_printf(&str, "%f %f %f %f re B ", x, y, width, height); + } else { + dstr_printf(&str, "%f %f %f %f re f ", x, y, width, height); + } + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_polygon(struct pdf_doc *pdf, struct pdf_object *page, float x[], + float y[], int count, float border_width, uint32_t colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f %f %f RG ", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f w ", border_width); + dstr_printf(&str, "%f %f m ", x[0], y[0]); + for (int i = 1; i < count; i++) { + dstr_printf(&str, "%f %f l ", x[i], y[i]); + } + dstr_printf(&str, "h S "); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +int pdf_add_filled_polygon(struct pdf_doc *pdf, struct pdf_object *page, + float x[], float y[], int count, + float border_width, uint32_t colour) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_printf(&str, "%f %f %f RG ", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f %f %f rg ", PDF_RGB_R(colour), PDF_RGB_G(colour), + PDF_RGB_B(colour)); + dstr_printf(&str, "%f w ", border_width); + dstr_printf(&str, "%f %f m ", x[0], y[0]); + for (int i = 1; i < count; i++) { + dstr_printf(&str, "%f %f l ", x[i], y[i]); + } + dstr_printf(&str, "h f "); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + + return ret; +} + +static const struct { + uint32_t code; + char ch; +} code_128a_encoding[] = { + {0x212222, ' '}, {0x222122, '!'}, {0x222221, '"'}, {0x121223, '#'}, + {0x121322, '$'}, {0x131222, '%'}, {0x122213, '&'}, {0x122312, '\''}, + {0x132212, '('}, {0x221213, ')'}, {0x221312, '*'}, {0x231212, '+'}, + {0x112232, ','}, {0x122132, '-'}, {0x122231, '.'}, {0x113222, '/'}, + {0x123122, '0'}, {0x123221, '1'}, {0x223211, '2'}, {0x221132, '3'}, + {0x221231, '4'}, {0x213212, '5'}, {0x223112, '6'}, {0x312131, '7'}, + {0x311222, '8'}, {0x321122, '9'}, {0x321221, ':'}, {0x312212, ';'}, + {0x322112, '<'}, {0x322211, '='}, {0x212123, '>'}, {0x212321, '?'}, + {0x232121, '@'}, {0x111323, 'A'}, {0x131123, 'B'}, {0x131321, 'C'}, + {0x112313, 'D'}, {0x132113, 'E'}, {0x132311, 'F'}, {0x211313, 'G'}, + {0x231113, 'H'}, {0x231311, 'I'}, {0x112133, 'J'}, {0x112331, 'K'}, + {0x132131, 'L'}, {0x113123, 'M'}, {0x113321, 'N'}, {0x133121, 'O'}, + {0x313121, 'P'}, {0x211331, 'Q'}, {0x231131, 'R'}, {0x213113, 'S'}, + {0x213311, 'T'}, {0x213131, 'U'}, {0x311123, 'V'}, {0x311321, 'W'}, + {0x331121, 'X'}, {0x312113, 'Y'}, {0x312311, 'Z'}, {0x332111, '['}, + {0x314111, '\\'}, {0x221411, ']'}, {0x431111, '^'}, {0x111224, '_'}, + {0x111422, '`'}, {0x121124, 'a'}, {0x121421, 'b'}, {0x141122, 'c'}, + {0x141221, 'd'}, {0x112214, 'e'}, {0x112412, 'f'}, {0x122114, 'g'}, + {0x122411, 'h'}, {0x142112, 'i'}, {0x142211, 'j'}, {0x241211, 'k'}, + {0x221114, 'l'}, {0x413111, 'm'}, {0x241112, 'n'}, {0x134111, 'o'}, + {0x111242, 'p'}, {0x121142, 'q'}, {0x121241, 'r'}, {0x114212, 's'}, + {0x124112, 't'}, {0x124211, 'u'}, {0x411212, 'v'}, {0x421112, 'w'}, + {0x421211, 'x'}, {0x212141, 'y'}, {0x214121, 'z'}, {0x412121, '{'}, + {0x111143, '|'}, {0x111341, '}'}, {0x131141, '~'}, {0x114113, '\0'}, + {0x114311, '\0'}, {0x411113, '\0'}, {0x411311, '\0'}, {0x113141, '\0'}, + {0x114131, '\0'}, {0x311141, '\0'}, {0x411131, '\0'}, {0x211412, '\0'}, + {0x211214, '\0'}, {0x211232, '\0'}, {0x2331112, '\0'}, +}; + +static int find_128_encoding(char ch) +{ + for (int i = 0; i < (int)ARRAY_SIZE(code_128a_encoding); i++) { + if (code_128a_encoding[i].ch == ch) + return i; + } + return -1; +} + +static float pdf_barcode_128a_ch(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + uint32_t colour, int index, int code_len) +{ + uint32_t code = code_128a_encoding[index].code; + float line_width = width / 11.0f; + + for (int i = 0; i < code_len; i++) { + uint8_t shift = (code_len - 1 - i) * 4; + uint8_t mask = (code >> shift) & 0xf; + + if (!(i % 2)) + pdf_add_filled_rectangle(pdf, page, x, y, line_width * mask, + height, 0, colour, PDF_TRANSPARENT); + x += line_width * mask; + } + return x; +} + +static int pdf_add_barcode_128a(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + const char *s; + size_t len = strlen(string) + 3; + float char_width = width / len; + int checksum, i; + + if (char_width / 11.0f <= 0) + return pdf_set_err(pdf, -EINVAL, + "Insufficient width to draw barcode"); + + for (s = string; *s; s++) + if (find_128_encoding(*s) < 0) + return pdf_set_err(pdf, -EINVAL, "Invalid barcode character 0x%x", + *s); + + x = pdf_barcode_128a_ch(pdf, page, x, y, char_width, height, colour, 104, + 6); + checksum = 104; + + for (i = 1, s = string; *s; s++, i++) { + int index = find_128_encoding(*s); + // This should be impossible, due to the checks above, but confirm + // here anyway to stop coverity complaining + if (index < 0) + return pdf_set_err(pdf, -EINVAL, + "Invalid 128a barcode character 0x%x", *s); + x = pdf_barcode_128a_ch(pdf, page, x, y, char_width, height, colour, + index, 6); + checksum += index * i; + } + x = pdf_barcode_128a_ch(pdf, page, x, y, char_width, height, colour, + checksum % 103, 6); + pdf_barcode_128a_ch(pdf, page, x, y, char_width, height, colour, 106, 7); + return 0; +} + +/* Code 39 character encoding. Each 4-bit value indicates: + * 0 => wide bar + * 1 => narrow bar + * 2 => wide space + */ +static const struct { + int code; + char ch; +} code_39_encoding[] = { + {0x012110, '1'}, {0x102110, '2'}, {0x002111, '3'}, + {0x112010, '4'}, {0x012011, '5'}, {0x102011, '6'}, + {0x112100, '7'}, {0x012101, '8'}, {0x102101, '9'}, + {0x112001, '0'}, {0x011210, 'A'}, {0x101210, 'B'}, + {0x001211, 'C'}, {0x110210, 'D'}, {0x010211, 'E'}, + {0x100211, 'F'}, {0x111200, 'G'}, {0x011201, 'H'}, + {0x101201, 'I'}, {0x110201, 'J'}, {0x011120, 'K'}, + {0x101120, 'L'}, {0x001121, 'M'}, {0x110120, 'N'}, + {0x010121, 'O'}, {0x100121, 'P'}, {0x111020, 'Q'}, + {0x011021, 'R'}, {0x101021, 'S'}, {0x110021, 'T'}, + {0x021110, 'U'}, {0x120110, 'V'}, {0x020111, 'W'}, + {0x121010, 'X'}, {0x021011, 'Y'}, {0x120011, 'Z'}, + {0x121100, '-'}, {0x021101, '.'}, {0x120101, ' '}, + {0x121001, '*'}, // 'stop' character +}; + +static int find_39_encoding(char ch) +{ + for (int i = 0; i < (int)ARRAY_SIZE(code_39_encoding); i++) { + if (code_39_encoding[i].ch == ch) { + return code_39_encoding[i].code; + } + } + return -1; +} + +static int pdf_barcode_39_ch(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float char_width, float height, + uint32_t colour, char ch, float *new_x) +{ + float nw = char_width / 12.0f; + float ww = char_width / 4.0f; + int code = 0; + + code = find_39_encoding(ch); + if (code < 0) + return pdf_set_err(pdf, -EINVAL, "Invalid Code 39 character %c 0x%x", + ch, ch); + + for (int i = 5; i >= 0; i--) { + int pattern = (code >> i * 4) & 0xf; + if (pattern == 0) { // wide + if (pdf_add_filled_rectangle(pdf, page, x, y, ww - 1, height, 0, + colour, PDF_TRANSPARENT) < 0) + return pdf->errval; + x += ww; + } + if (pattern == 1) { // narrow + if (pdf_add_filled_rectangle(pdf, page, x, y, nw - 1, height, 0, + colour, PDF_TRANSPARENT) < 0) + return pdf->errval; + x += nw; + } + if (pattern == 2) { // space + x += nw; + } + } + if (new_x) + *new_x = x; + return 0; +} + +static int pdf_add_barcode_39(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + size_t len = strlen(string); + float char_width = width / (len + 2); + int e; + + e = pdf_barcode_39_ch(pdf, page, x, y, char_width, height, colour, '*', + &x); + if (e < 0) + return e; + + while (string && *string) { + e = pdf_barcode_39_ch(pdf, page, x, y, char_width, height, colour, + *string, &x); + if (e < 0) + return e; + string++; + } + + e = pdf_barcode_39_ch(pdf, page, x, y, char_width, height, colour, '*', + NULL); + if (e < 0) + return e; + + return 0; +} + +/* EAN/UPC character encoding. Each 4-bit value indicates width in x units. + * Elements are SBSB (Space, Bar, Space, Bar) for LHS digits + * Elements are inverted for RHS digits + */ +static const int code_eanupc_encoding[] = { + 0x3211, // 0 + 0x2221, // 1 + 0x2122, // 2 + 0x1411, // 3 + 0x1132, // 4 + 0x1231, // 5 + 0x1114, // 6 + 0x1312, // 7 + 0x1213, // 8 + 0x3112, // 9 +}; + +/** + * List of different barcode guard patterns that are supported + */ +enum { + GUARD_NORMAL, //!< Produce normal guard pattern + GUARD_CENTRE, //!< Produce centre guard pattern + GUARD_SPECIAL, //!< Produce special guard pattern + GUARD_ADDON, + GUARD_ADDON_DELIN, +}; + +static const int code_eanupc_aux_encoding[] = { + 0x150, // Normal guard + 0x554, // Centre guard + 0x555, // Special guard + 0x160, // Add-on guard + 0x500, // Add-on delineator +}; + +static const int set_ean13_encoding[] = { + 0x00, // 0 + 0x34, // 1 + 0x2c, // 2 + 0x1c, // 3 + 0x32, // 4 + 0x26, // 5 + 0x0e, // 6 + 0x2a, // 7 + 0x1a, // 8 + 0x16, // 9 +}; + +static const int set_upce_encoding[] = { + 0x07, // 0 + 0x0b, // 1 + 0x13, // 2 + 0x23, // 3 + 0x0d, // 4 + 0x19, // 5 + 0x31, // 6 + 0x15, // 7 + 0x25, // 8 + 0x29, // 9 +}; + +#define EANUPC_X PDF_MM_TO_POINT(0.330f) + +static const struct { + unsigned modules; + float height_bar; + float height_outer; + unsigned quiet_left; + unsigned quiet_right; +} eanupc_dimensions[] = { + {113, PDF_MM_TO_POINT(22.85), PDF_MM_TO_POINT(25.93), 11, 7}, // EAN-13 + {113, PDF_MM_TO_POINT(22.85), PDF_MM_TO_POINT(25.93), 9, 9}, // UPC-A + {81, PDF_MM_TO_POINT(18.23), PDF_MM_TO_POINT(21.31), 7, 7}, // EAN-8 + {67, PDF_MM_TO_POINT(22.85), PDF_MM_TO_POINT(25.93), 9, 7}, // UPC-E +}; + +static void pdf_barcode_eanupc_calc_dims(int type, float width, float height, + float *x_off, float *y_off, + float *new_width, float *new_height, + float *x, float *bar_height, + float *bar_ext, float *font_size) +{ + float aspectBarcode, aspectRect, scale; + + aspectRect = width / height; + aspectBarcode = eanupc_dimensions[type - PDF_BARCODE_EAN13].modules * + EANUPC_X / + eanupc_dimensions[type - PDF_BARCODE_EAN13].height_outer; + if (aspectRect > aspectBarcode) { + *new_height = height; + *new_width = height * aspectBarcode; + } else if (aspectRect < aspectBarcode) { + *new_width = width; + *new_height = width / aspectBarcode; + } else { + *new_width = width; + *new_height = height; + } + scale = *new_height / + eanupc_dimensions[type - PDF_BARCODE_EAN13].height_outer; + + *x = *new_width / eanupc_dimensions[type - PDF_BARCODE_EAN13].modules; + *bar_ext = *x * 5; + *bar_height = + eanupc_dimensions[type - PDF_BARCODE_EAN13].height_bar * scale; + *font_size = 8.0 * scale; + *x_off = (width - *new_width) / 2.0; + *y_off = (height - *new_height) / 2.0; +} + +static int pdf_barcode_eanupc_ch(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float x_width, + float height, uint32_t colour, char ch, + int set, float *new_x) +{ + if ('0' > ch || ch > '9') + return pdf_set_err(pdf, -EINVAL, "Invalid EAN/UPC character %c 0x%x", + ch, ch); + + int code; + code = code_eanupc_encoding[ch - '0']; + + for (int i = 3; i >= 0; i--) { + int shift = (set == 1 ? 3 - i : i) * 4; + int bar = (set == 2 && i & 0x1) || (set != 2 && (i & 0x1) == 0); + float width = (code >> shift) & 0xf; + + switch (ch) { + case '1': + case '2': + if ((set == 0 && bar) || (set != 0 && !bar)) { + width -= 1.0 / 13.0; + } else { + width += 1.0 / 13.0; + } + break; + + case '7': + case '8': + if ((set == 0 && bar) || (set != 0 && !bar)) { + width += 1.0 / 13.0; + } else { + width -= 1.0 / 13.0; + } + break; + } + + width *= x_width; + if (bar) { + if (pdf_add_filled_rectangle(pdf, page, x, y, width, height, 0, + colour, PDF_TRANSPARENT) < 0) + return pdf->errval; + } + x += width; + } + if (new_x) + *new_x = x; + return 0; +} + +static int pdf_barcode_eanupc_aux(struct pdf_doc *pdf, + struct pdf_object *page, float x, float y, + float x_width, float height, + uint32_t colour, int guard_type, + float *new_x) +{ + int code = code_eanupc_aux_encoding[guard_type]; + + for (int i = 5; i >= 0; i--) { + int value = code >> i * 2 & 0x3; + if (value) { + if ((i & 0x1) == 0) { + if (pdf_add_filled_rectangle(pdf, page, x, y, x_width * value, + height, 0, colour, + PDF_TRANSPARENT) < 0) + return pdf->errval; + } + x += x_width * value; + } + } + if (new_x) + *new_x = x; + return 0; +} + +static int pdf_add_barcode_ean13(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + if (!string) + return 0; + + size_t len = strlen(string); + int lead = 0; + if (len == 13) { + char ch = string[0]; + if (!isdigit(*string)) + return pdf_set_err(pdf, -EINVAL, + "Invalid EAN13 character %c 0x%x", ch, ch); + lead = ch - '0'; + ++string; + } else if (len != 12) + return pdf_set_err(pdf, -EINVAL, "Invalid EAN13 string length %lu", + len); + + /* Scale and calculate dimensions */ + float x_off, y_off, new_width, new_height, x_width, bar_height, bar_ext, + font; + + pdf_barcode_eanupc_calc_dims(PDF_BARCODE_EAN13, width, height, &x_off, + &y_off, &new_width, &new_height, &x_width, + &bar_height, &bar_ext, &font); + + x += x_off; + y += y_off; + float bar_y = y + new_height - bar_height; + + int e; + const char *save_font = pdf->current_font->font.name; + e = pdf_set_font(pdf, "Courier"); /* Built-in monospace font */ + if (e < 0) + return e; + + char text[2]; + text[1] = 0; + text[0] = lead + '0'; + e = pdf_add_text(pdf, page, text, font, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + x += eanupc_dimensions[0].quiet_left * x_width; + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 6; i++) { + text[0] = *string; + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + int set = (set_ean13_encoding[lead] & 1 << i) ? 1 : 0; + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y, x_width, bar_height, + colour, *string, set, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_CENTRE, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 6; i++) { + text[0] = *string; + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y, x_width, bar_height, + colour, *string, 2, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + text[0] = '>'; + x += eanupc_dimensions[0].quiet_right * x_width - + 604.0f * font / (14.0f * 72.0f); + e = pdf_add_text(pdf, page, text, font, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + pdf_set_font(pdf, save_font); + return 0; +} + +static int pdf_add_barcode_upca(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + if (!string) + return 0; + + size_t len = strlen(string); + if (len != 12) + return pdf_set_err(pdf, -EINVAL, "Invalid UPCA string length %lu", + len); + + /* Scale and calculate dimensions */ + float x_off, y_off, new_width, new_height; + float x_width, bar_height, bar_ext, font; + + pdf_barcode_eanupc_calc_dims(PDF_BARCODE_UPCA, width, height, &x_off, + &y_off, &new_width, &new_height, &x_width, + &bar_height, &bar_ext, &font); + + x += x_off; + y += y_off; + float bar_y = y + new_height - bar_height; + + int e; + const char *save_font = pdf->current_font->font.name; + e = pdf_set_font(pdf, "Courier"); + if (e < 0) + return e; + + char text[2]; + text[1] = 0; + text[0] = *string; + e = pdf_add_text(pdf, page, text, font * 4.0 / 7.0, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + x += eanupc_dimensions[1].quiet_left * x_width; + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 6; i++) { + text[0] = *string; + if (i) { + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + } + + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y - (i ? 0 : bar_ext), + x_width, bar_height + (i ? 0 : bar_ext), + colour, *string, 0, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_CENTRE, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 6; i++) { + text[0] = *string; + if (i != 5) { + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + } + + e = pdf_barcode_eanupc_ch( + pdf, page, x, bar_y - (i != 5 ? 0 : bar_ext), x_width, + bar_height + (i != 5 ? 0 : bar_ext), colour, *string, 2, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + text[0] = *--string; + + x += eanupc_dimensions[1].quiet_right * x_width - + 604.0f * font * 4.0f / 7.0f / (14.0f * 72.0f); + e = pdf_add_text(pdf, page, text, font * 4.0 / 7.0, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + pdf_set_font(pdf, save_font); + return 0; +} + +static int pdf_add_barcode_ean8(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + if (!string) + return 0; + + size_t len = strlen(string); + if (len != 8) + return pdf_set_err(pdf, -EINVAL, "Invalid EAN8 string length %lu", + len); + + /* Scale and calculate dimensions */ + float x_off, y_off, new_width, new_height, x_width, bar_height, bar_ext, + font; + + pdf_barcode_eanupc_calc_dims(PDF_BARCODE_EAN8, width, height, &x_off, + &y_off, &new_width, &new_height, &x_width, + &bar_height, &bar_ext, &font); + + x += x_off; + y += y_off; + float bar_y = y + new_height - bar_height; + + int e; + const char *save_font = pdf->current_font->font.name; + e = pdf_set_font(pdf, "Courier"); /* Built-in monospace font */ + if (e < 0) + return e; + + char text[2]; + text[1] = 0; + text[0] = '<'; + e = pdf_add_text(pdf, page, text, font, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + x += eanupc_dimensions[2].quiet_left * x_width; + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 4; i++) { + text[0] = *string; + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y, x_width, bar_height, + colour, *string, 0, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_CENTRE, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + for (int i = 0; i != 4; i++) { + text[0] = *string; + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y, x_width, bar_height, + colour, *string, 2, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + string++; + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y - bar_ext, x_width, + bar_height + bar_ext, colour, GUARD_NORMAL, + &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + text[0] = '>'; + x += eanupc_dimensions[0].quiet_right * x_width - + 604.0f * font / (14.0f * 72.0f); + e = pdf_add_text(pdf, page, text, font, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + pdf_set_font(pdf, save_font); + return 0; +} + +static int pdf_add_barcode_upce(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + if (!string) + return 0; + + size_t len = strlen(string); + if (len != 12) + return pdf_set_err(pdf, -EINVAL, "Invalid UPCE string length %lu", + len); + + if (*string != '0') + return pdf_set_err(pdf, -EINVAL, "Invalid UPCE char %c at start", + *string); + + for (size_t i = 0; i < len; i++) { + if (!isdigit(string[i])) + return pdf_set_err(pdf, -EINVAL, "Invalid UPCE char 0x%x at %zd", + string[i], i); + } + + /* Scale and calculate dimensions */ + float x_off, y_off, new_width, new_height; + float x_width, bar_height, bar_ext, font; + + pdf_barcode_eanupc_calc_dims(PDF_BARCODE_UPCE, width, height, &x_off, + &y_off, &new_width, &new_height, &x_width, + &bar_height, &bar_ext, &font); + + x += x_off; + y += y_off; + float bar_y = y + new_height - bar_height; + + int e; + const char *save_font = pdf->current_font->font.name; + e = pdf_set_font(pdf, "Courier"); + if (e < 0) + return e; + + char text[2]; + text[1] = 0; + text[0] = string[0]; + e = pdf_add_text(pdf, page, text, font * 4.0 / 7.0, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + x += eanupc_dimensions[2].quiet_left * x_width; + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y, x_width, bar_height, + colour, GUARD_NORMAL, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + char X[6]; + if (string[5] && memcmp(string + 6, "0000", 4) == 0 && + '5' <= string[10] && string[10] <= '9') { + memcpy(X, string + 1, 5); + X[5] = string[10]; + } else if (string[4] && memcmp(string + 5, "00000", 5) == 0) { + memcpy(X, string + 1, 4); + X[4] = string[11]; + X[5] = 4; + } else if ('0' <= string[3] && string[3] <= '2' && + memcmp(string + 4, "0000", 4) == 0) { + X[0] = string[1]; + X[1] = string[2]; + X[2] = string[8]; + X[3] = string[9]; + X[4] = string[10]; + X[5] = string[3]; + } else if ('3' <= string[3] && string[3] <= '9' && + memcmp(string + 4, "00000", 5) == 0) { + memcpy(X, string + 1, 3); + X[3] = string[9]; + X[4] = string[10]; + X[5] = 3; + } else { + pdf_set_font(pdf, save_font); + return pdf_set_err(pdf, -EINVAL, "Invalid UPCE string format"); + } + + for (int i = 0; i != 6; i++) { + text[0] = X[i]; + e = pdf_add_text_wrap(pdf, page, text, font, x, y, colour, + 7 * x_width, PDF_ALIGN_CENTER, NULL); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + int set = (set_upce_encoding[string[11] - '0'] & 1 << i) ? 1 : 0; + e = pdf_barcode_eanupc_ch(pdf, page, x, bar_y, x_width, bar_height, + colour, X[i], set, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + } + + e = pdf_barcode_eanupc_aux(pdf, page, x, bar_y, x_width, bar_height, + colour, GUARD_SPECIAL, &x); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + text[0] = string[11]; + x += eanupc_dimensions[0].quiet_right * x_width - + 604.0f * font * 4.0f / 7.0f / (14.0f * 72.0f); + e = pdf_add_text(pdf, page, text, font * 4.0 / 7.0, x, y, colour); + if (e < 0) { + pdf_set_font(pdf, save_font); + return e; + } + + pdf_set_font(pdf, save_font); + return 0; +} + +int pdf_add_barcode(struct pdf_doc *pdf, struct pdf_object *page, int code, + float x, float y, float width, float height, + const char *string, uint32_t colour) +{ + if (!string || !*string) + return 0; + switch (code) { + case PDF_BARCODE_128A: + return pdf_add_barcode_128a(pdf, page, x, y, width, height, string, + colour); + case PDF_BARCODE_39: + return pdf_add_barcode_39(pdf, page, x, y, width, height, string, + colour); + case PDF_BARCODE_EAN13: + return pdf_add_barcode_ean13(pdf, page, x, y, width, height, string, + colour); + case PDF_BARCODE_UPCA: + return pdf_add_barcode_upca(pdf, page, x, y, width, height, string, + colour); + case PDF_BARCODE_EAN8: + return pdf_add_barcode_ean8(pdf, page, x, y, width, height, string, + colour); + case PDF_BARCODE_UPCE: + return pdf_add_barcode_upce(pdf, page, x, y, width, height, string, + colour); + default: + return pdf_set_err(pdf, -EINVAL, "Invalid barcode code %d", code); + } +} + +static pdf_object *pdf_add_raw_grayscale8(struct pdf_doc *pdf, + const uint8_t *data, uint32_t width, + uint32_t height) +{ + struct pdf_object *obj; + size_t len; + const char *endstream = ">\r\nendstream\r\n"; + struct dstr str = INIT_DSTR; + size_t data_len = (size_t)width * (size_t)height; + + dstr_printf(&str, + "<<\r\n" + " /Type /XObject\r\n" + " /Name /Image%d\r\n" + " /Subtype /Image\r\n" + " /ColorSpace /DeviceGray\r\n" + " /Height %d\r\n" + " /Width %d\r\n" + " /BitsPerComponent 8\r\n" + " /Length %zu\r\n" + ">>stream\r\n", + flexarray_size(&pdf->objects), height, width, data_len + 1); + + len = dstr_len(&str) + data_len + strlen(endstream) + 1; + if (dstr_ensure(&str, len) < 0) { + dstr_free(&str); + pdf_set_err(pdf, -ENOMEM, + "Unable to allocate %zu bytes memory for image", len); + return NULL; + } + dstr_append_data(&str, data, data_len); + dstr_append(&str, endstream); + + obj = pdf_add_object(pdf, OBJ_image); + if (!obj) { + dstr_free(&str); + return NULL; + } + obj->stream = str; + + return obj; +} + +static struct pdf_object *pdf_add_raw_rgb24(struct pdf_doc *pdf, + const uint8_t *data, + uint32_t width, uint32_t height) +{ + struct pdf_object *obj; + size_t len; + const char *endstream = ">\r\nendstream\r\n"; + struct dstr str = INIT_DSTR; + size_t data_len = (size_t)width * (size_t)height * 3; + + dstr_printf(&str, + "<<\r\n" + " /Type /XObject\r\n" + " /Name /Image%d\r\n" + " /Subtype /Image\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Height %d\r\n" + " /Width %d\r\n" + " /BitsPerComponent 8\r\n" + " /Length %zu\r\n" + ">>stream\r\n", + flexarray_size(&pdf->objects), height, width, data_len + 1); + + len = dstr_len(&str) + data_len + strlen(endstream) + 1; + if (dstr_ensure(&str, len) < 0) { + dstr_free(&str); + pdf_set_err(pdf, -ENOMEM, + "Unable to allocate %zu bytes memory for image", len); + return NULL; + } + dstr_append_data(&str, data, data_len); + dstr_append(&str, endstream); + + obj = pdf_add_object(pdf, OBJ_image); + if (!obj) { + dstr_free(&str); + return NULL; + } + obj->stream = str; + + return obj; +} + +static uint8_t *get_file(struct pdf_doc *pdf, const char *file_name, + size_t *length) +{ + FILE *fp; + uint8_t *file_data; + struct stat buf; + off_t len; + + if ((fp = fopen(file_name, "rb")) == NULL) { + pdf_set_err(pdf, -errno, "Unable to open %s: %s", file_name, + strerror(errno)); + return NULL; + } + + if (fstat(fileno(fp), &buf) < 0) { + pdf_set_err(pdf, -errno, "Unable to access %s: %s", file_name, + strerror(errno)); + fclose(fp); + return NULL; + } + + len = buf.st_size; + + file_data = (uint8_t *)malloc(len); + if (!file_data) { + pdf_set_err(pdf, -ENOMEM, "Unable to allocate: %d", (int)len); + fclose(fp); + return NULL; + } + + if (fread(file_data, len, 1, fp) != 1) { + pdf_set_err(pdf, -errno, "Unable to read full data: %s", file_name); + free(file_data); + fclose(fp); + return NULL; + } + + fclose(fp); + + *length = len; + + return file_data; +} + +static struct pdf_object * +pdf_add_raw_jpeg_data(struct pdf_doc *pdf, const struct pdf_img_info *info, + const uint8_t *jpeg_data, size_t len) +{ + struct pdf_object *obj = pdf_add_object(pdf, OBJ_image); + if (!obj) + return NULL; + + dstr_printf(&obj->stream, + "<<\r\n" + " /Type /XObject\r\n" + " /Name /Image%d\r\n" + " /Subtype /Image\r\n" + " /ColorSpace %s\r\n" + " /Width %d\r\n" + " /Height %d\r\n" + " /BitsPerComponent 8\r\n" + " /Filter /DCTDecode\r\n" + " /Length %zu\r\n" + ">>stream\r\n", + flexarray_size(&pdf->objects), + (info->jpeg.ncolours == 1) ? "/DeviceGray" : "/DeviceRGB", + info->width, info->height, len); + dstr_append_data(&obj->stream, jpeg_data, len); + + dstr_printf(&obj->stream, "\r\nendstream\r\n"); + + return obj; +} + +/** + * Get the display dimensions of an image, respecting the images aspect ratio + * if only one desired display dimension is defined. + * The pdf parameter is only used for setting the error value. + */ +static int get_img_display_dimensions(struct pdf_doc *pdf, uint32_t img_width, + uint32_t img_height, + float *display_width, + float *display_height) +{ + if (!display_height || !display_width) { + return pdf_set_err( + pdf, -EINVAL, + "display_width and display_height may not be null pointers"); + } + + const float display_width_in = *display_width; + const float display_height_in = *display_height; + + if (display_width_in < 0 && display_height_in < 0) { + return pdf_set_err(pdf, -EINVAL, + "Unable to determine image display dimensions, " + "display_width and display_height are both < 0"); + } + if (img_width == 0 || img_height == 0) { + return pdf_set_err(pdf, -EINVAL, + "Invalid image dimensions received, the loaded " + "image appears to be empty."); + } + + if (display_width_in < 0) { + // Set width, keeping aspect ratio + *display_width = display_height_in * ((float)img_width / img_height); + } else if (display_height_in < 0) { + // Set height, keeping aspect ratio + *display_height = display_width_in * ((float)img_height / img_width); + } + return 0; +} + +static int pdf_add_image(struct pdf_doc *pdf, struct pdf_object *page, + struct pdf_object *image, float x, float y, + float width, float height) +{ + int ret; + struct dstr str = INIT_DSTR; + + dstr_append(&str, "q "); + dstr_printf(&str, "%f 0 0 %f %f %f cm ", width, height, x, y); + dstr_printf(&str, "/Image%d Do ", image->index); + dstr_append(&str, "Q"); + + ret = pdf_add_stream(pdf, page, dstr_data(&str)); + dstr_free(&str); + return ret; +} + +// Works like fgets, except it's for a fixed in-memory buffer of data +static size_t dgets(const uint8_t *data, size_t *pos, size_t len, char *line, + size_t line_len) +{ + size_t line_pos = 0; + + if (*pos >= len) + return 0; + + while ((*pos) < len) { + if (line_pos < line_len) { + // Reject non-ascii data + if (data[*pos] & 0x80) { + return 0; + } + line[line_pos] = data[*pos]; + line_pos++; + } + if (data[*pos] == '\n') { + (*pos)++; + break; + } + (*pos)++; + } + + if (line_pos < line_len) { + line[line_pos] = '\0'; + } + + return *pos; +} + +static int parse_ppm_header(struct pdf_img_info *info, const uint8_t *data, + size_t length, char *err_msg, + size_t err_msg_length) +{ + char line[1024]; + memset(line, '\0', sizeof(line)); + size_t pos = 0; + + // Load the PPM file + if (!dgets(data, &pos, length, line, sizeof(line) - 1)) { + snprintf(err_msg, err_msg_length, "Invalid PPM file"); + return -EINVAL; + } + + // Determine number of color channels (Also, we only support binary ppms) + int ncolors; + if (strncmp(line, "P6", 2) == 0) { + info->ppm.color_space = PPM_BINARY_COLOR_RGB; + ncolors = 3; + } else if (strncmp(line, "P5", 2) == 0) { + info->ppm.color_space = PPM_BINARY_COLOR_GRAY; + ncolors = 1; + } else { + snprintf(err_msg, err_msg_length, + "Only binary PPM files (grayscale, RGB) supported"); + return -EINVAL; + } + + // Skip comments before header + do { + if (!dgets(data, &pos, length, line, sizeof(line) - 1)) { + snprintf(err_msg, err_msg_length, "Unable to find PPM header"); + return -EINVAL; + } + } while (line[0] == '#'); + + // Read image dimensions + if (sscanf(line, "%u %u\n", &(info->width), &(info->height)) != 2) { + snprintf(err_msg, err_msg_length, "Unable to find PPM size"); + return -EINVAL; + } + if (info->width > MAX_IMAGE_WIDTH || info->height > MAX_IMAGE_HEIGHT) { + snprintf(err_msg, err_msg_length, "Invalid width/height: %ux%u", + info->width, info->height); + return -EINVAL; + } + info->ppm.size = (size_t)(info->width * info->height * ncolors); + info->ppm.data_begin_pos = pos; + + return 0; +} + +static int pdf_add_ppm_data(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float display_width, + float display_height, + const struct pdf_img_info *info, + const uint8_t *ppm_data, size_t len) +{ + char line[1024]; + // We start reading at the position delivered by parse_ppm_header, + // since we already parsed the header of the file there. + size_t pos = info->ppm.data_begin_pos; + + /* Skip over the byte-size line */ + if (!dgets(ppm_data, &pos, len, line, sizeof(line) - 1)) + return pdf_set_err(pdf, -EINVAL, "No byte-size line in PPM file"); + + /* Try and limit the memory usage to sane images */ + if (info->width > MAX_IMAGE_WIDTH || info->height > MAX_IMAGE_HEIGHT) { + return pdf_set_err(pdf, -EINVAL, + "Invalid width/height in PPM file: %ux%u", + info->width, info->height); + } + + if (info->ppm.size > len - pos) { + return pdf_set_err(pdf, -EINVAL, "Insufficient image data available"); + } + + switch (info->ppm.color_space) { + case PPM_BINARY_COLOR_GRAY: + return pdf_add_grayscale8(pdf, page, x, y, display_width, + display_height, &ppm_data[pos], info->width, + info->height); + break; + + case PPM_BINARY_COLOR_RGB: + return pdf_add_rgb24(pdf, page, x, y, display_width, display_height, + &ppm_data[pos], info->width, info->height); + break; + + default: + return pdf_set_err(pdf, -EINVAL, + "Invalid color space in ppm file: %i", + info->ppm.color_space); + break; + } +} + +static int parse_jpeg_header(struct pdf_img_info *info, const uint8_t *data, + size_t length, char *err_msg, + size_t err_msg_length) +{ + // See http://www.videotechnology.com/jpeg/j1.html for details + if (length >= 4 && data[0] == 0xFF && data[1] == 0xD8) { + for (size_t i = 2; i < length; i++) { + if (data[i] != 0xff) { + break; + } + while (++i < length && data[i] == 0xff) + ; + if (i + 2 >= length) { + break; + } + int len = data[i + 1] * 256 + data[i + 2]; + /* Search for SOFn marker and decode jpeg details */ + if ((data[i] & 0xf4) == 0xc0) { + if (len >= 9 && i + len + 1 < length) { + info->height = data[i + 4] * 256 + data[i + 5]; + info->width = data[i + 6] * 256 + data[i + 7]; + info->jpeg.ncolours = data[i + 8]; + return 0; + } + break; + } + i += len; + } + } + snprintf(err_msg, err_msg_length, "Error parsing JPEG header"); + return -EINVAL; +} + +static int pdf_add_jpeg_data(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float display_width, + float display_height, struct pdf_img_info *info, + const uint8_t *jpeg_data, size_t len) +{ + struct pdf_object *obj; + + obj = pdf_add_raw_jpeg_data(pdf, info, jpeg_data, len); + if (!obj) + return pdf->errval; + + if (get_img_display_dimensions(pdf, info->width, info->height, + &display_width, &display_height)) { + return pdf->errval; + } + return pdf_add_image(pdf, page, obj, x, y, display_width, display_height); +} + +int pdf_add_rgb24(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, uint32_t width, uint32_t height) +{ + struct pdf_object *obj; + + obj = pdf_add_raw_rgb24(pdf, data, width, height); + if (!obj) + return pdf->errval; + + if (get_img_display_dimensions(pdf, width, height, &display_width, + &display_height)) { + return pdf->errval; + } + return pdf_add_image(pdf, page, obj, x, y, display_width, display_height); +} + +int pdf_add_grayscale8(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, uint32_t width, uint32_t height) +{ + struct pdf_object *obj; + + obj = pdf_add_raw_grayscale8(pdf, data, width, height); + if (!obj) + return pdf->errval; + + if (get_img_display_dimensions(pdf, width, height, &display_width, + &display_height)) { + return pdf->errval; + } + return pdf_add_image(pdf, page, obj, x, y, display_width, display_height); +} + +static int parse_png_header(struct pdf_img_info *info, const uint8_t *data, + size_t length, char *err_msg, + size_t err_msg_length) +{ + if (length <= sizeof(png_signature)) { + snprintf(err_msg, err_msg_length, "PNG file too short"); + return -EINVAL; + } + + if (memcmp(data, png_signature, sizeof(png_signature))) { + snprintf(err_msg, err_msg_length, "File is not correct PNG file"); + return -EINVAL; + } + + // process first PNG chunk + uint32_t pos = sizeof(png_signature); + const struct png_chunk *chunk = (const struct png_chunk *)&data[pos]; + pos += sizeof(struct png_chunk); + if (pos > length) { + snprintf(err_msg, err_msg_length, "PNG file too short"); + return -EINVAL; + } + if (strncmp(chunk->type, png_chunk_header, 4) == 0) { + // header found, process width and height, check errors + struct png_header *header = &info->png; + + if (pos + sizeof(struct png_header) > length) { + snprintf(err_msg, err_msg_length, "PNG file too short"); + return -EINVAL; + } + + memcpy(header, &data[pos], sizeof(struct png_header)); + if (header->deflate != 0) { + snprintf(err_msg, err_msg_length, "Deflate wrong in PNG header"); + return -EINVAL; + } + if (header->bitDepth == 0) { + snprintf(err_msg, err_msg_length, "PNG file has zero bit depth"); + return -EINVAL; + } + // ensure the width and height values have the proper byte order + // and copy them into the info struct. + header->width = ntoh32(header->width); + header->height = ntoh32(header->height); + info->width = header->width; + info->height = header->height; + return 0; + } + snprintf(err_msg, err_msg_length, "Failed to read PNG file header"); + return -EINVAL; +} + +static int pdf_add_png_data(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float display_width, + float display_height, + const struct pdf_img_info *img_info, + const uint8_t *png_data, size_t png_data_length) +{ + // indicates if we return an error or add the img at the + // end of the function + bool success = false; + + // string stream used for writing color space (and palette) info + // into the pdf + struct dstr colour_space = INIT_DSTR; + + struct pdf_object *obj = NULL; + uint8_t *final_data = NULL; + int written = 0; + uint32_t pos; + uint8_t *png_data_temp = NULL; + size_t png_data_total_length = 0; + uint8_t ncolours; + + // Stores palette information for indexed PNGs + struct rgb_value *palette_buffer = NULL; + size_t palette_buffer_length = 0; + + const struct png_header *header = &img_info->png; + + // Father info from png header + switch (header->colorType) { + case PNG_COLOR_GREYSCALE: + ncolours = 1; + break; + case PNG_COLOR_RGB: + ncolours = 3; + break; + case PNG_COLOR_INDEXED: + ncolours = 1; + break; + // PNG_COLOR_RGBA and PNG_COLOR_GREYSCALE_A are unsupported + default: + pdf_set_err(pdf, -EINVAL, "PNG has unsupported color type: %d", + header->colorType); + goto free_buffers; + break; + } + + /* process PNG chunks */ + pos = sizeof(png_signature); + + while (1) { + const struct png_chunk *chunk; + + chunk = (const struct png_chunk *)&png_data[pos]; + pos += sizeof(struct png_chunk); + + if (pos > png_data_length - 4) { + pdf_set_err(pdf, -EINVAL, "PNG file too short"); + goto free_buffers; + } + const uint32_t chunk_length = ntoh32(chunk->length); + // chunk length + 4-bytes of CRC + if (chunk_length > png_data_length - pos - 4) { + pdf_set_err(pdf, -EINVAL, "PNG chunk exceeds file: %d vs %ld", + chunk_length, png_data_length - pos - 4); + goto free_buffers; + } + if (strncmp(chunk->type, png_chunk_header, 4) == 0) { + // Ignoring the header, since it was parsed + // before calling this function. + } else if (strncmp(chunk->type, png_chunk_palette, 4) == 0) { + // Palette chunk + if (header->colorType == PNG_COLOR_INDEXED) { + // palette chunk is needed for indexed images + if (palette_buffer) { + pdf_set_err(pdf, -EINVAL, + "PNG contains multiple palette chunks"); + goto free_buffers; + } + if (chunk_length % 3 != 0) { + pdf_set_err(pdf, -EINVAL, + "PNG format error: palette chunk length is " + "not divisbly by 3!"); + goto free_buffers; + } + palette_buffer_length = (size_t)(chunk_length / 3); + if (palette_buffer_length > 256 || + palette_buffer_length == 0) { + pdf_set_err(pdf, -EINVAL, + "PNG palette length invalid: %zd", + palette_buffer_length); + goto free_buffers; + } + palette_buffer = (struct rgb_value *)malloc( + palette_buffer_length * sizeof(struct rgb_value)); + if (!palette_buffer) { + pdf_set_err(pdf, -ENOMEM, + "Could not allocate memory for indexed color " + "palette (%zu bytes)", + palette_buffer_length * + sizeof(struct rgb_value)); + goto free_buffers; + } + for (size_t i = 0; i < palette_buffer_length; i++) { + size_t offset = (i * 3) + pos; + palette_buffer[i].red = png_data[offset]; + palette_buffer[i].green = png_data[offset + 1]; + palette_buffer[i].blue = png_data[offset + 2]; + } + } else if (header->colorType == PNG_COLOR_RGB || + header->colorType == PNG_COLOR_RGBA) { + // palette chunk is optional for RGB(A) images + // but we do not process them + } else { + pdf_set_err(pdf, -EINVAL, + "Unexpected palette chunk for color type %d", + header->colorType); + goto free_buffers; + } + } else if (strncmp(chunk->type, png_chunk_data, 4) == 0) { + if (chunk_length > 0 && chunk_length < png_data_length - pos) { + uint8_t *data = (uint8_t *)realloc( + png_data_temp, png_data_total_length + chunk_length); + // (uint8_t *)realloc(info.data, info.length + chunk_length); + if (!data) { + pdf_set_err(pdf, -ENOMEM, "No memory for PNG data"); + goto free_buffers; + } + png_data_temp = data; + memcpy(&png_data_temp[png_data_total_length], &png_data[pos], + chunk_length); + png_data_total_length += chunk_length; + } + } else if (strncmp(chunk->type, png_chunk_end, 4) == 0) { + /* end of file, exit */ + break; + } + + if (chunk_length >= png_data_length) { + pdf_set_err(pdf, -EINVAL, "PNG chunk length larger than file"); + goto free_buffers; + } + + pos += chunk_length; // add chunk length + pos += sizeof(uint32_t); // add CRC length + } + + /* if no length was found */ + if (png_data_total_length == 0) { + pdf_set_err(pdf, -EINVAL, "PNG file has zero length"); + goto free_buffers; + } + + switch (header->colorType) { + case PNG_COLOR_GREYSCALE: + dstr_append(&colour_space, "/DeviceGray"); + break; + case PNG_COLOR_RGB: + dstr_append(&colour_space, "/DeviceRGB"); + break; + case PNG_COLOR_INDEXED: + if (palette_buffer_length == 0) { + pdf_set_err(pdf, -EINVAL, "Indexed PNG contains no palette"); + goto free_buffers; + } + // Write the color palette to the color_palette buffer + dstr_printf(&colour_space, + "[ /Indexed\r\n" + " /DeviceRGB\r\n" + " %zu\r\n" + " <", + palette_buffer_length - 1); + // write individual paletter values + // the index value for every RGB value is determined by its position + // (0, 1, 2, ...) + for (size_t i = 0; i < palette_buffer_length; i++) { + dstr_printf(&colour_space, "%02X%02X%02X ", palette_buffer[i].red, + palette_buffer[i].green, palette_buffer[i].blue); + } + dstr_append(&colour_space, ">\r\n]"); + break; + + default: + pdf_set_err(pdf, -EINVAL, + "Cannot map PNG color type %d to PDF color space", + header->colorType); + goto free_buffers; + break; + } + + final_data = (uint8_t *)malloc(png_data_total_length + 1024 + + dstr_len(&colour_space)); + if (!final_data) { + pdf_set_err(pdf, -ENOMEM, "Unable to allocate PNG data %zu", + png_data_total_length + 1024 + dstr_len(&colour_space)); + goto free_buffers; + } + + // Write image information to PDF + written = + sprintf((char *)final_data, + "<<\r\n" + " /Type /XObject\r\n" + " /Name /Image%d\r\n" + " /Subtype /Image\r\n" + " /ColorSpace %s\r\n" + " /Width %u\r\n" + " /Height %u\r\n" + " /Interpolate true\r\n" + " /BitsPerComponent %u\r\n" + " /Filter /FlateDecode\r\n" + " /DecodeParms << /Predictor 15 /Colors %d " + "/BitsPerComponent %u /Columns %u >>\r\n" + " /Length %zu\r\n" + ">>stream\r\n", + flexarray_size(&pdf->objects), dstr_data(&colour_space), + header->width, header->height, header->bitDepth, ncolours, + header->bitDepth, header->width, png_data_total_length); + + memcpy(&final_data[written], png_data_temp, png_data_total_length); + written += png_data_total_length; + written += sprintf((char *)&final_data[written], "\r\nendstream\r\n"); + + obj = pdf_add_object(pdf, OBJ_image); + if (!obj) { + goto free_buffers; + } + + dstr_append_data(&obj->stream, final_data, written); + + if (get_img_display_dimensions(pdf, header->width, header->height, + &display_width, &display_height)) { + goto free_buffers; + } + success = true; + +free_buffers: + if (final_data) + free(final_data); + if (palette_buffer) + free(palette_buffer); + if (png_data_temp) + free(png_data_temp); + dstr_free(&colour_space); + + if (success) + return pdf_add_image(pdf, page, obj, x, y, display_width, + display_height); + else + return pdf->errval; +} + +static int parse_bmp_header(struct pdf_img_info *info, const uint8_t *data, + size_t data_length, char *err_msg, + size_t err_msg_length) +{ + if (data_length < sizeof(bmp_signature) + sizeof(struct bmp_header)) { + snprintf(err_msg, err_msg_length, "File is too short"); + return -EINVAL; + } + + if (memcmp(data, bmp_signature, sizeof(bmp_signature))) { + snprintf(err_msg, err_msg_length, "File is not correct BMP file"); + return -EINVAL; + } + memcpy(&info->bmp, &data[sizeof(bmp_signature)], + sizeof(struct bmp_header)); + if (info->bmp.biWidth < 0) { + snprintf(err_msg, err_msg_length, "BMP has negative width"); + return -EINVAL; + } + if (info->bmp.biHeight == -2147483648) { // 1 << 31 + snprintf(err_msg, err_msg_length, "BMP height overflow"); + return -EINVAL; + } + info->width = info->bmp.biWidth; + // biHeight might be negative (positive indicates vertically mirrored + // lines) + info->height = abs(info->bmp.biHeight); + return 0; +} + +static int pdf_add_bmp_data(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float display_width, + float display_height, + const struct pdf_img_info *info, + const uint8_t *data, const size_t len) +{ + const struct bmp_header *header = &info->bmp; + uint8_t *bmp_data = NULL; + uint8_t row_padding; + uint32_t bpp; + size_t data_len; + int retval; + const uint32_t width = info->width; + const uint32_t height = info->height; + + if (header->bfSize != len) + return pdf_set_err(pdf, -EINVAL, + "BMP file seems to have wrong length"); + if (header->biSize != 40) + return pdf_set_err(pdf, -EINVAL, "Wrong BMP header: biSize"); + if (header->biCompression != 0) + return pdf_set_err(pdf, -EINVAL, "Wrong BMP compression value: %d", + header->biCompression); + if (header->biWidth > MAX_IMAGE_WIDTH || header->biWidth <= 0 || + width > MAX_IMAGE_WIDTH || width == 0) + return pdf_set_err(pdf, -EINVAL, "BMP has invalid width: %d", + header->biWidth); + if (header->biHeight > MAX_IMAGE_HEIGHT || + header->biHeight < -MAX_IMAGE_HEIGHT || header->biHeight == 0 || + height > MAX_IMAGE_HEIGHT || height == 0) + return pdf_set_err(pdf, -EINVAL, "BMP has invalid height: %d", + header->biHeight); + if (header->biBitCount != 24 && header->biBitCount != 32) + return pdf_set_err(pdf, -EINVAL, "Unsupported BMP bitdepth: %d", + header->biBitCount); + bpp = header->biBitCount / 8; + /* BMP rows are 4-bytes padded! */ + row_padding = (width * bpp) & 3; + data_len = (size_t)width * (size_t)height * 3; + + if (header->bfOffBits >= len) + return pdf_set_err(pdf, -EINVAL, "Invalid BMP image offset"); + + if (len - header->bfOffBits < + (size_t)height * (width + row_padding) * bpp) + return pdf_set_err(pdf, -EINVAL, "Wrong BMP image size"); + + if (bpp == 3) { + /* 24 bits: change R and B colors */ + bmp_data = (uint8_t *)malloc(data_len); + if (!bmp_data) + return pdf_set_err(pdf, -ENOMEM, + "Insufficient memory for bitmap"); + for (uint32_t pos = 0; pos < width * height; pos++) { + uint32_t src_pos = + header->bfOffBits + 3 * (pos + (pos / width) * row_padding); + + bmp_data[pos * 3] = data[src_pos + 2]; + bmp_data[pos * 3 + 1] = data[src_pos + 1]; + bmp_data[pos * 3 + 2] = data[src_pos]; + } + } else if (bpp == 4) { + /* 32 bits: change R and B colors, remove key color */ + int offs = 0; + bmp_data = (uint8_t *)malloc(data_len); + if (!bmp_data) + return pdf_set_err(pdf, -ENOMEM, + "Insufficient memory for bitmap"); + + for (uint32_t pos = 0; pos < width * height * 4; pos += 4) { + bmp_data[offs] = data[header->bfOffBits + pos + 2]; + bmp_data[offs + 1] = data[header->bfOffBits + pos + 1]; + bmp_data[offs + 2] = data[header->bfOffBits + pos]; + offs += 3; + } + } else { + return pdf_set_err(pdf, -EINVAL, "Unsupported BMP bitdepth: %d", + header->biBitCount); + } + if (header->biHeight >= 0) { + // BMP has vertically mirrored representation of lines, so swap them + uint8_t *line = (uint8_t *)malloc(width * 3); + if (!line) { + free(bmp_data); + return pdf_set_err(pdf, -ENOMEM, + "Unable to allocate memory for bitmap mirror"); + } + for (uint32_t pos = 0; pos < (height / 2); pos++) { + memcpy(line, &bmp_data[pos * width * 3], width * 3); + memcpy(&bmp_data[pos * width * 3], + &bmp_data[(height - pos - 1) * width * 3], width * 3); + memcpy(&bmp_data[(height - pos - 1) * width * 3], line, + width * 3); + } + free(line); + } + + retval = pdf_add_rgb24(pdf, page, x, y, display_width, display_height, + bmp_data, width, height); + free(bmp_data); + + return retval; +} + +static int determine_image_format(const uint8_t *data, size_t length) +{ + if (length >= sizeof(png_signature) && + memcmp(data, png_signature, sizeof(png_signature)) == 0) + return IMAGE_PNG; + if (length >= sizeof(bmp_signature) && + memcmp(data, bmp_signature, sizeof(bmp_signature)) == 0) + return IMAGE_BMP; + if (length >= sizeof(jpeg_signature) && + memcmp(data, jpeg_signature, sizeof(jpeg_signature)) == 0) + return IMAGE_JPG; + if (length >= sizeof(ppm_signature) && + memcmp(data, ppm_signature, sizeof(ppm_signature)) == 0) + return IMAGE_PPM; + if (length >= sizeof(pgm_signature) && + memcmp(data, pgm_signature, sizeof(pgm_signature)) == 0) + return IMAGE_PPM; + + return IMAGE_UNKNOWN; +} + +int pdf_parse_image_header(struct pdf_img_info *info, const uint8_t *data, + size_t length, char *err_msg, + size_t err_msg_length) + +{ + const int image_format = determine_image_format(data, length); + info->image_format = image_format; + switch (image_format) { + case IMAGE_PNG: + return parse_png_header(info, data, length, err_msg, err_msg_length); + case IMAGE_BMP: + return parse_bmp_header(info, data, length, err_msg, err_msg_length); + case IMAGE_JPG: + return parse_jpeg_header(info, data, length, err_msg, err_msg_length); + case IMAGE_PPM: + return parse_ppm_header(info, data, length, err_msg, err_msg_length); + + case IMAGE_UNKNOWN: + default: + snprintf(err_msg, err_msg_length, "Unknown file format"); + return -EINVAL; + } +} + +int pdf_add_image_data(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, size_t len) +{ + struct pdf_img_info info = { + .image_format = IMAGE_UNKNOWN, + .width = 0, + .height = 0, + .jpeg = {0}, + }; + + int ret = pdf_parse_image_header(&info, data, len, pdf->errstr, + sizeof(pdf->errstr)); + if (ret) + return ret; + + // Try and determine which image format it is based on the content + switch (info.image_format) { + case IMAGE_PNG: + return pdf_add_png_data(pdf, page, x, y, display_width, + display_height, &info, data, len); + case IMAGE_BMP: + return pdf_add_bmp_data(pdf, page, x, y, display_width, + display_height, &info, data, len); + case IMAGE_JPG: + return pdf_add_jpeg_data(pdf, page, x, y, display_width, + display_height, &info, data, len); + case IMAGE_PPM: + return pdf_add_ppm_data(pdf, page, x, y, display_width, + display_height, &info, data, len); + + // This case should be caught in parse_image_header, but is checked + // here again for safety + case IMAGE_UNKNOWN: + default: + return pdf_set_err(pdf, -EINVAL, "Unable to determine image format"); + } +} + +int pdf_add_image_file(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const char *image_filename) +{ + size_t len; + uint8_t *data; + int ret = 0; + + data = get_file(pdf, image_filename, &len); + if (data == NULL) + return pdf_get_errval(pdf); + + ret = pdf_add_image_data(pdf, page, x, y, display_width, display_height, + data, len); + free(data); + return ret; +} diff --git a/src/PDFGen/pdfgen.h b/src/PDFGen/pdfgen.h new file mode 100644 index 0000000..ca0ac6d --- /dev/null +++ b/src/PDFGen/pdfgen.h @@ -0,0 +1,773 @@ +/** + * Simple engine for creating PDF files. + * It supports text, shapes, images etc... + * Capable of handling millions of objects without too much performance + * penalty. + * Public domain license - no warrenty implied; use at your own risk. + * @file pdfgen.h + */ +#ifndef PDFGEN_H +#define PDFGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdio.h> + +/** + * @defgroup subsystem Simple PDF Generation + * Allows for quick generation of simple PDF documents. + * This is useful for producing easily printed output from C code, where + * advanced formatting is not required + * + * Note: All coordinates/sizes are in points (1/72 of an inch). + * All coordinates are based on 0,0 being the bottom left of the page. + * All colours are specified as a packed 32-bit value - see @ref PDF_RGB. + * Text strings are interpreted as UTF-8 encoded, but only a small subset of + * characters beyond 7-bit ascii are supported (see @ref pdf_add_text for + * details). + * + * @par PDF library example: + * @code +#include "pdfgen.h" + ... +struct pdf_info info = { + .creator = "My software", + .producer = "My software", + .title = "My document", + .author = "My name", + .subject = "My subject", + .date = "Today" + }; +struct pdf_doc *pdf = pdf_create(PDF_A4_WIDTH, PDF_A4_HEIGHT, &info); +pdf_set_font(pdf, "Times-Roman"); +pdf_append_page(pdf); +pdf_add_text(pdf, NULL, "This is text", 12, 50, 20, PDF_BLACK); +pdf_add_line(pdf, NULL, 50, 24, 150, 24); +pdf_save(pdf, "output.pdf"); +pdf_destroy(pdf); + * @endcode + */ + +struct pdf_doc; +struct pdf_object; + +/** + * pdf_info describes the metadata to be inserted into the + * header of the output PDF + */ +struct pdf_info { + char creator[64]; //!< Software used to create the PDF + char producer[64]; //!< Software used to create the PDF + char title[64]; //!< The title of the PDF (typically displayed in the + //!< window bar when viewing) + char author[64]; //!< Who created the PDF + char subject[64]; //!< What is the PDF about + char date[64]; //!< The date the PDF was created +}; + +/** + * Enum that declares the different image file formats we currently support. + * Each value has a corresponding header struct used within + * the format_specific_img_info union. + */ +enum { + IMAGE_PNG, + IMAGE_JPG, + IMAGE_PPM, + IMAGE_BMP, + + IMAGE_UNKNOWN +}; + +/** + * Since we're casting random areas of memory to these, make sure + * they're packed properly to match the image format requirements + */ +#pragma pack(push, 1) + +/** + * Information about color type of PNG format + * As defined by https://www.w3.org/TR/2003/REC-PNG-20031110/#6Colour-values + */ +enum /* png colortype */ { + // Greyscale + PNG_COLOR_GREYSCALE = 0, + // Truecolour + PNG_COLOR_RGB = 2, + // Indexed-colour + PNG_COLOR_INDEXED = 3, + // Greyscale with alpha + PNG_COLOR_GREYSCALE_A = 4, + // Truecolour with alpha + PNG_COLOR_RGBA = 6, + + PNG_COLOR_INVALID = 255 +}; + +/** + * png_header describes the header information extracted from .PNG files + */ +struct png_header { + uint32_t width; //!< Width in pixels + uint32_t height; //!< Height in pixels + uint8_t bitDepth; //!< Bit Depth + uint8_t colorType; //!< Color type - see PNG_COLOR_xx + uint8_t deflate; //!< Deflate setting + uint8_t filtering; //!< Filtering + uint8_t interlace; //!< Interlacing +}; + +/** + * bmp_header describes the header information extracted from .BMP files + */ +struct bmp_header { + uint32_t bfSize; //!< size of BMP in bytes + uint16_t bfReserved1; //!< ignore! + uint16_t bfReserved2; //!< ignore! + uint32_t bfOffBits; //!< Offset to BMP data + uint32_t biSize; //!< Size of this header (40) + int32_t biWidth; //!< Width in pixels + int32_t biHeight; //!< Height in pixels + uint16_t biPlanes; //!< Number of colour planes - must be 1 + uint16_t biBitCount; //!< Bits Per Pixel + uint32_t biCompression; //!< Compression Method +}; +#pragma pack(pop) + +/** + * jpeg_header describes the header information extracted from .JPG files + */ +struct jpeg_header { + int ncolours; //!< Number of colours +}; + +/** + * PPM color spaces + */ +enum { + PPM_BINARY_COLOR_RGB, //!< binary ppm with RGB colors (magic number P5) + PPM_BINARY_COLOR_GRAY, //!< binary ppm with grayscale colors (magic number + //!< P6) +}; + +/** + * ppm_header describes the header information extracted from .PPM files + */ +struct ppm_header { + size_t size; //!< Indicate the size of the image data + size_t data_begin_pos; //!< position in the data where the image starts + int color_space; //!< PPM color space +}; + +/** + * pdf_img_info describes the metadata for an arbitrary image + */ +struct pdf_img_info { + int image_format; //!< Indicates the image format (IMAGE_PNG, ...) + uint32_t width; //!< Width in pixels + uint32_t height; //!< Height in pixels + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + // Doxygen doesn't like anonymous unions + //!< Image specific details + union { + struct bmp_header bmp; //!< BMP header info + struct jpeg_header jpeg; //!< JPEG header info + struct png_header png; //!< PNG header info + struct ppm_header ppm; //!< PPM header info + }; +#endif +}; + +/** + * pdf_path_operation holds information about a path + * drawing operation. + * See PDF reference for detailed usage. + */ +struct pdf_path_operation { + char op; /*!< Operation command. Possible operators are: m = move to, l = + line to, c = cubic bezier curve with two control points, v = + cubic bezier curve with one control point fixed at first + point, y = cubic bezier curve with one control point fixed + at second point, h = close path */ + float x1; /*!< X offset of the first point. Used with: m, l, c, v, y */ + float y1; /*!< Y offset of the first point. Used with: m, l, c, v, y */ + float x2; /*!< X offset of the second point. Used with: c, v, y */ + float y2; /*!< Y offset of the second point. Used with: c, v, y */ + float x3; /*!< X offset of the third point. Used with: c */ + float y3; /*!< Y offset of the third point. Used with: c */ +}; + +/** + * Convert a value in inches into a number of points. + * @param inch inches value to convert to points + */ +#define PDF_INCH_TO_POINT(inch) ((float)((inch)*72.0f)) + +/** + * Convert a value in milli-meters into a number of points. + * @param mm millimeter value to convert to points + */ +#define PDF_MM_TO_POINT(mm) ((float)((mm)*72.0f / 25.4f)) + +/*! Point width of a standard US-Letter page */ +#define PDF_LETTER_WIDTH PDF_INCH_TO_POINT(8.5f) + +/*! Point height of a standard US-Letter page */ +#define PDF_LETTER_HEIGHT PDF_INCH_TO_POINT(11.0f) + +/*! Point width of a standard A4 page */ +#define PDF_A4_WIDTH PDF_MM_TO_POINT(210.0f) + +/*! Point height of a standard A4 page */ +#define PDF_A4_HEIGHT PDF_MM_TO_POINT(297.0f) + +/*! Point width of a standard A3 page */ +#define PDF_A3_WIDTH PDF_MM_TO_POINT(297.0f) + +/*! Point height of a standard A3 page */ +#define PDF_A3_HEIGHT PDF_MM_TO_POINT(420.0f) + +/** + * Convert three 8-bit RGB values into a single packed 32-bit + * colour. These 32-bit colours are used by various functions + * in PDFGen + */ +#define PDF_RGB(r, g, b) \ + (uint32_t)((((r)&0xff) << 16) | (((g)&0xff) << 8) | (((b)&0xff))) + +/** + * Convert four 8-bit ARGB values into a single packed 32-bit + * colour. These 32-bit colours are used by various functions + * in PDFGen. Alpha values range from 0 (opaque) to 0xff + * (transparent) + */ +#define PDF_ARGB(a, r, g, b) \ + (uint32_t)(((uint32_t)((a)&0xff) << 24) | (((r)&0xff) << 16) | \ + (((g)&0xff) << 8) | (((b)&0xff))) + +/*! Utility macro to provide bright red */ +#define PDF_RED PDF_RGB(0xff, 0, 0) + +/*! Utility macro to provide bright green */ +#define PDF_GREEN PDF_RGB(0, 0xff, 0) + +/*! Utility macro to provide bright blue */ +#define PDF_BLUE PDF_RGB(0, 0, 0xff) + +/*! Utility macro to provide black */ +#define PDF_BLACK PDF_RGB(0, 0, 0) + +/*! Utility macro to provide white */ +#define PDF_WHITE PDF_RGB(0xff, 0xff, 0xff) + +/*! + * Utility macro to provide a transparent colour + * This is used in some places for 'fill' colours, where no fill is required + */ +#define PDF_TRANSPARENT (uint32_t)(0xffu << 24) + +/** + * Different alignment options for rendering text + */ +enum { + PDF_ALIGN_LEFT, //!< Align text to the left + PDF_ALIGN_RIGHT, //!< Align text to the right + PDF_ALIGN_CENTER, //!< Align text in the center + PDF_ALIGN_JUSTIFY, //!< Align text in the center, with padding to fill the + //!< available space + PDF_ALIGN_JUSTIFY_ALL, //!< Like PDF_ALIGN_JUSTIFY, except even short + //!< lines will be fully justified + PDF_ALIGN_NO_WRITE, //!< Fake alignment for only checking wrap height with + //!< no writes +}; + +/** + * Create a new PDF object, with the given page + * width/height + * @param width Width of the page + * @param height Height of the page + * @param info Optional information to be put into the PDF header + * @return PDF document object, or NULL on failure + */ +struct pdf_doc *pdf_create(float width, float height, + const struct pdf_info *info); + +/** + * Destroy the pdf object, and all of its associated memory + * @param pdf PDF document to clean up + */ +void pdf_destroy(struct pdf_doc *pdf); + +/** + * Retrieve the error message if any operation fails + * @param pdf pdf document to retrieve error message from + * @param errval optional pointer to an integer to be set to the error code + * @return NULL if no error message, string description of error otherwise + */ +const char *pdf_get_err(const struct pdf_doc *pdf, int *errval); + +/** + * Acknowledge an outstanding pdf error + * @param pdf pdf document to clear the error message from + */ +void pdf_clear_err(struct pdf_doc *pdf); + +/** + * Sets the font to use for text objects. Default value is Times-Roman if + * this function is not called. + * Note: The font selection should be done before text is output, + * and will remain until pdf_set_font is called again. + * @param pdf PDF document to update font on + * @param font New font to use. This must be one of the standard PDF fonts: + * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, + * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, + * Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, + * Symbol or ZapfDingbats + * @return < 0 on failure, 0 on success + */ +int pdf_set_font(struct pdf_doc *pdf, const char *font); + +/** + * Calculate the width of a given string in the current font + * @param pdf PDF document + * @param font_name Name of the font to get the width of. + * This must be one of the standard PDF fonts: + * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, + * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, + * Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, + * Symbol or ZapfDingbats + * @param text Text to determine width of + * @param size Size of the text, in points + * @param text_width area to store calculated width in + * @return < 0 on failure, 0 on success + */ +int pdf_get_font_text_width(struct pdf_doc *pdf, const char *font_name, + const char *text, float size, float *text_width); + +/** + * Retrieves a PDF document height + * @param pdf PDF document to get height of + * @return height of PDF document (in points) + */ +float pdf_height(const struct pdf_doc *pdf); + +/** + * Retrieves a PDF document width + * @param pdf PDF document to get width of + * @return width of PDF document (in points) + */ +float pdf_width(const struct pdf_doc *pdf); + +/** + * Retrieves page height + * @param page Page object to get height of + * @return height of page (in points) + */ +float pdf_page_height(const struct pdf_object *page); + +/** + * Retrieves page width + * @param page Page object to get width of + * @return width of page (in points) + */ +float pdf_page_width(const struct pdf_object *page); + +/** + * Add a new page to the given pdf + * @param pdf PDF document to append page to + * @return new page object + */ +struct pdf_object *pdf_append_page(struct pdf_doc *pdf); + +/** + * Adjust the width/height of a specific page + * @param pdf PDF document that the page belongs to + * @param page object returned from @ref pdf_append_page + * @param width Width of the page in points + * @param height Height of the page in points + * @return < 0 on failure, 0 on success + */ +int pdf_page_set_size(struct pdf_doc *pdf, struct pdf_object *page, + float width, float height); + +/** + * Save the given pdf document to the supplied filename. + * @param pdf PDF document to save + * @param filename Name of the file to store the PDF into (NULL for stdout) + * @return < 0 on failure, >= 0 on success + */ +int pdf_save(struct pdf_doc *pdf, const char *filename); + +/** + * Save the given pdf document to the given FILE output + * @param pdf PDF document to save + * @param fp FILE pointer to store the data into (must be writable) + * @return < 0 on failure, >= 0 on success + */ +int pdf_save_file(struct pdf_doc *pdf, FILE *fp); + +/** + * Add a text string to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param text String to display + * @param size Point size of the font + * @param xoff X location to put it in + * @param yoff Y location to put it in + * @param colour Colour to draw the text + * @return 0 on success, < 0 on failure + */ +int pdf_add_text(struct pdf_doc *pdf, struct pdf_object *page, + const char *text, float size, float xoff, float yoff, + uint32_t colour); + +/** + * Add a text string to the document, making it wrap if it is too + * long + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param text String to display + * @param size Point size of the font + * @param xoff X location to put it in + * @param yoff Y location to put it in + * @param colour Colour to draw the text + * @param wrap_width Width at which to wrap the text + * @param align Text alignment (see PDF_ALIGN_xxx) + * @param height Store the final height of the wrapped text here (optional) + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_text_wrap(struct pdf_doc *pdf, struct pdf_object *page, + const char *text, float size, float xoff, float yoff, + uint32_t colour, float wrap_width, int align, + float *height); + +/** + * Add a line to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x1 X offset of start of line + * @param y1 Y offset of start of line + * @param x2 X offset of end of line + * @param y2 Y offset of end of line + * @param width Width of the line + * @param colour Colour to draw the line + * @return 0 on success, < 0 on failure + */ +int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1, + float y1, float x2, float y2, float width, uint32_t colour); + +/** + * Add a cubic bezier curve to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x1 X offset of the initial point of the curve + * @param y1 Y offset of the initial point of the curve + * @param x2 X offset of the final point of the curve + * @param y2 Y offset of the final point of the curve + * @param xq1 X offset of the first control point of the curve + * @param yq1 Y offset of the first control point of the curve + * @param xq2 X offset of the second control of the curve + * @param yq2 Y offset of the second control of the curve + * @param width Width of the curve + * @param colour Colour to draw the curve + * @return 0 on success, < 0 on failure + */ +int pdf_add_cubic_bezier(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, float xq1, + float yq1, float xq2, float yq2, float width, + uint32_t colour); + +/** + * Add a quadratic bezier curve to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x1 X offset of the initial point of the curve + * @param y1 Y offset of the initial point of the curve + * @param x2 X offset of the final point of the curve + * @param y2 Y offset of the final point of the curve + * @param xq1 X offset of the control point of the curve + * @param yq1 Y offset of the control point of the curve + * @param width Width of the curve + * @param colour Colour to draw the curve + * @return 0 on success, < 0 on failure + */ +int pdf_add_quadratic_bezier(struct pdf_doc *pdf, struct pdf_object *page, + float x1, float y1, float x2, float y2, + float xq1, float yq1, float width, + uint32_t colour); + +/** + * Add a custom path to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param operations Array of drawing operations + * @param operation_count The number of operations + * @param stroke_width Width of the stroke + * @param stroke_colour Colour to stroke the curve + * @param fill_colour Colour to fill the path + * @return 0 on success, < 0 on failure + */ +int pdf_add_custom_path(struct pdf_doc *pdf, struct pdf_object *page, + struct pdf_path_operation *operations, + int operation_count, float stroke_width, + uint32_t stroke_colour, uint32_t fill_colour); + +/** + * Add an ellipse to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x X offset of the center of the ellipse + * @param y Y offset of the center of the ellipse + * @param xradius Radius of the ellipse in the X axis + * @param yradius Radius of the ellipse in the Y axis + * @param width Width of the ellipse outline stroke + * @param colour Colour to draw the ellipse outline stroke + * @param fill_colour Colour to fill the ellipse + * @return 0 on success, < 0 on failure + */ +int pdf_add_ellipse(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float xradius, float yradius, float width, + uint32_t colour, uint32_t fill_colour); + +/** + * Add a circle to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x X offset of the center of the circle + * @param y Y offset of the center of the circle + * @param radius Radius of the circle + * @param width Width of the circle outline stroke + * @param colour Colour to draw the circle outline stroke + * @param fill_colour Colour to fill the circle + * @return 0 on success, < 0 on failure + */ +int pdf_add_circle(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float radius, float width, uint32_t colour, + uint32_t fill_colour); + +/** + * Add an outline rectangle to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x X offset to start rectangle at + * @param y Y offset to start rectangle at + * @param width Width of rectangle + * @param height Height of rectangle + * @param border_width Width of rectangle border + * @param colour Colour to draw the rectangle + * @return 0 on success, < 0 on failure + */ +int pdf_add_rectangle(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float width, float height, float border_width, + uint32_t colour); + +/** + * Add a filled rectangle to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x X offset to start rectangle at + * @param y Y offset to start rectangle at + * @param width Width of rectangle + * @param height Height of rectangle + * @param border_width Width of rectangle border + * @param colour_fill Colour to fill the rectangle + * @param colour_border Colour to draw the rectangle + * @return 0 on success, < 0 on failure + */ +int pdf_add_filled_rectangle(struct pdf_doc *pdf, struct pdf_object *page, + float x, float y, float width, float height, + float border_width, uint32_t colour_fill, + uint32_t colour_border); + +/** + * Add an outline polygon to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x array of X offsets for points comprising the polygon + * @param y array of Y offsets for points comprising the polygon + * @param count Number of points comprising the polygon + * @param border_width Width of polygon border + * @param colour Colour to draw the polygon + * @return 0 on success, < 0 on failure + */ +int pdf_add_polygon(struct pdf_doc *pdf, struct pdf_object *page, float x[], + float y[], int count, float border_width, + uint32_t colour); + +/** + * Add a filled polygon to the document + * @param pdf PDF document to add to + * @param page Page to add object to (NULL => most recently added page) + * @param x array of X offsets of points comprising the polygon + * @param y array of Y offsets of points comprising the polygon + * @param count Number of points comprising the polygon + * @param border_width Width of polygon border + * @param colour Colour to draw the polygon + * @return 0 on success, < 0 on failure + */ +int pdf_add_filled_polygon(struct pdf_doc *pdf, struct pdf_object *page, + float x[], float y[], int count, + float border_width, uint32_t colour); + +/** + * Add a bookmark to the document + * @param pdf PDF document to add bookmark to + * @param page Page to jump to for bookmark + (or NULL for the most recently added page) + * @param parent ID of a previously created bookmark that is the parent + of this one. -1 if this should be a top-level bookmark. + * @param name String to associate with the bookmark + * @return < 0 on failure, new bookmark id on success + */ +int pdf_add_bookmark(struct pdf_doc *pdf, struct pdf_object *page, int parent, + const char *name); + +/** + * Add a link annotation to the document + * @param pdf PDF document to add link to + * @param page Page that holds the clickable rectangle + (or NULL for the most recently added page) + * @param x X coordinate of bottom LHS corner of clickable rectangle + * @param y Y coordinate of bottom LHS corner of clickable rectangle + * @param width width of clickable rectangle + * @param height height of clickable rectangle + * @param target_page Page to jump to for link + * @param target_x X coordinate to position at the left of the view + * @param target_y Y coordinate to position at the top of the view + * @return < 0 on failure, new bookmark id on success + */ +int pdf_add_link(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float width, float height, + struct pdf_object *target_page, float target_x, + float target_y); + +/** + * List of different barcode encodings that are supported + */ +enum { + PDF_BARCODE_128A, //!< Produce code-128A style barcodes + PDF_BARCODE_39, //!< Produce code-39 style barcodes + PDF_BARCODE_EAN13, //!< Produce EAN-13 style barcodes + PDF_BARCODE_UPCA, //!< Produce UPC-A style barcodes + PDF_BARCODE_EAN8, //!< Produce EAN-8 style barcodes + PDF_BARCODE_UPCE, //!< Produce UPC-E style barcodes +}; + +/** + * Add a barcode to the document + * @param pdf PDF document to add barcode to + * @param page Page to add barcode to (NULL => most recently added page) + * @param code Type of barcode to add (PDF_BARCODE_xxx) + * @param x X offset to put barcode at + * @param y Y offset to put barcode at + * @param width Width of barcode + * @param height Height of barcode + * @param string Barcode contents + * @param colour Colour to draw barcode + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_barcode(struct pdf_doc *pdf, struct pdf_object *page, int code, + float x, float y, float width, float height, + const char *string, uint32_t colour); + +/** + * Add image data as an image to the document. + * Image data must be one of: JPEG, PNG, PPM, PGM or BMP formats + * Passing 0 for either the display width or height will + * include the image but not render it visible. + * Passing a negative number either the display height or width will + * have the image be resized while keeping the original aspect ratio. + * @param pdf PDF document to add image to + * @param page Page to add image to (NULL => most recently added page) + * @param x X offset to put image at + * @param y Y offset to put image at + * @param display_width Displayed width of image + * @param display_height Displayed height of image + * @param data Image data bytes + * @param len Length of data + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_image_data(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, size_t len); + +/** + * Add a raw 24 bit per pixel RGB buffer as an image to the document + * Passing 0 for either the display width or height will + * include the image but not render it visible. + * Passing a negative number either the display height or width will + * have the image be resized while keeping the original aspect ratio. + * @param pdf PDF document to add image to + * @param page Page to add image to (NULL => most recently added page) + * @param x X offset to put image at + * @param y Y offset to put image at + * @param display_width Displayed width of image + * @param display_height Displayed height of image + * @param data RGB data to add + * @param width width of image in pixels + * @param height height of image in pixels + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_rgb24(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, uint32_t width, uint32_t height); + +/** + * Add a raw 8 bit per pixel grayscale buffer as an image to the document + * @param pdf PDF document to add image to + * @param page Page to add image to (NULL => most recently added page) + * @param x X offset to put image at + * @param y Y offset to put image at + * @param display_width Displayed width of image + * @param display_height Displayed height of image + * @param data grayscale pixel data to add + * @param width width of image in pixels + * @param height height of image in pixels + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_grayscale8(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const uint8_t *data, uint32_t width, uint32_t height); + +/** + * Add an image file as an image to the document. + * Passing 0 for either the display width or height will + * include the image but not render it visible. + * Passing a negative number either the display height or width will + * have the image be resized while keeping the original aspect ratio. + * Supports image formats: JPEG, PNG, PPM, PGM & BMP + * @param pdf PDF document to add bookmark to + * @param page Page to add image to (NULL => most recently added page) + * @param x X offset to put image at + * @param y Y offset to put image at + * @param display_width Displayed width of image + * @param display_height Displayed height of image + * @param image_filename Filename of image file to display + * @return < 0 on failure, >= 0 on success + */ +int pdf_add_image_file(struct pdf_doc *pdf, struct pdf_object *page, float x, + float y, float display_width, float display_height, + const char *image_filename); + +/** + * Parse image data to determine the image type & metadata + * @param info structure to hold the parsed metadata + * @param data image data to parse + * @param length number of bytes in data + * @param err_msg area to put any failure details + * @param err_msg_length maximum number of bytes to store in err_msg + * @return < 0 on failure, >= 0 on success + */ +int pdf_parse_image_header(struct pdf_img_info *info, const uint8_t *data, + size_t length, char *err_msg, + size_t err_msg_length); + +#ifdef __cplusplus +} +#endif + +#endif // PDFGEN_H diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..13deffa --- /dev/null +++ b/src/conf.c @@ -0,0 +1,620 @@ +/* + * conf.c: functions that handle the nwipe.conf configuration file + * and the creation of the nwipe_customers.csv file. nwipe.conf uses + * libconfig format, while nwipe_customers.csv uses comma separted + * values. CSV is used so that the user can build there own customer + * listing using spreadsheets rather than enter all the customer + * information via the nwipe GUI interface. + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * + */ + +#include <libconfig.h> +#include <unistd.h> +#include <sys/types.h> +#include "nwipe.h" +#include "context.h" +#include "logging.h" +#include "method.h" +#include "options.h" +#include "conf.h" + +config_t nwipe_cfg; +config_setting_t *nwipe_conf_setting, *group_organisation, *root, *group, *previous_group, *setting; +const char* nwipe_conf_str; +char nwipe_config_directory[] = "/etc/nwipe"; +char nwipe_config_file[] = "/etc/nwipe/nwipe.conf"; +char nwipe_customers_file[] = "/etc/nwipe/nwipe_customers.csv"; +char nwipe_customers_file_backup[] = "/etc/nwipe/nwipe_customers.csv.backup"; +char nwipe_customers_file_backup_tmp[] = "/etc/nwipe/nwipe_customers.csv.backup.tmp"; + +/* + * Checks for the existence of nwipe.conf and nwipe_customers.csv + * If either one does not exist, they are created and formatted + * with a basic configuration. + */ + +int nwipe_conf_init() +{ + FILE* fp_config; + FILE* fp_customers; + + config_init( &nwipe_cfg ); + char nwipe_customers_initial_content[] = + "\"Customer Name\";\"Contact Name\";\"Customer Address\";\"Contact Phone\"\n" + "\"Not Applicable\";\"Not Applicable\";\"Not Applicable\";\"Not Applicable\"\n"; + + /* Read /etc/nwipe/nwipe.conf. If there is an error, determine whether + * it's because it doesn't exist. If it doesn't exist create it and + * populate it with a basic structure. + */ + + /* Does the /etc/nwipe/nwipe.conf file exist? If not, then create it */ + if( access( nwipe_config_file, F_OK ) == 0 ) + { + nwipe_log( NWIPE_LOG_INFO, "Nwipes config file %s exists", nwipe_config_file ); + + /* Read the nwipe.conf configuration file and report any errors */ + + nwipe_log( NWIPE_LOG_INFO, "Reading nwipe's config file %s", nwipe_config_file ); + if( !config_read_file( &nwipe_cfg, nwipe_config_file ) ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Syntax error: %s:%d - %s\n", + config_error_file( &nwipe_cfg ), + config_error_line( &nwipe_cfg ), + config_error_text( &nwipe_cfg ) ); + } + } + else + { + nwipe_log( NWIPE_LOG_WARNING, "%s does not exist", nwipe_config_file ); + + /* We assume the /etc/nwipe directory doesn't exist, so try to create it */ + mkdir( nwipe_config_directory, 0755 ); + + /* create the nwipe.conf file */ + if( !( fp_config = fopen( nwipe_config_file, "w" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to create %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Created %s", nwipe_config_file ); + fclose( fp_config ); + } + } + + root = config_root_setting( &nwipe_cfg ); + + /** + * If they don't already exist, populate nwipe.conf with groups, settings and values. + * This will also fill in missing group or settings if they have been corrupted or + * accidently deleted by the user. It will also update an existing nwipe.conf + * file as new groups and settings are added to nwipe. If new settings are added + * to nwipes conf file they MUST appear below in this list of groups and settings. + */ + + nwipe_conf_populate( "Organisation_Details.Business_Name", "Not Applicable (BN)" ); + nwipe_conf_populate( "Organisation_Details.Business_Address", "Not Applicable (BA)" ); + nwipe_conf_populate( "Organisation_Details.Contact_Name", "Not Applicable (BCN)" ); + nwipe_conf_populate( "Organisation_Details.Contact_Phone", "Not Applicable (BCP)" ); + nwipe_conf_populate( "Organisation_Details.Op_Tech_Name", "Not Applicable (OTN)" ); + + /** + * Add PDF Certificate/Report settings + */ + nwipe_conf_populate( "PDF_Certificate.PDF_Enable", "ENABLED" ); + nwipe_conf_populate( "PDF_Certificate.PDF_Preview", "DISABLED" ); + + /** + * The currently selected customer that will be printed on the report + */ + nwipe_conf_populate( "Selected_Customer.Customer_Name", "Not Applicable (CN)" ); + nwipe_conf_populate( "Selected_Customer.Customer_Address", "Not Applicable (CA)" ); + nwipe_conf_populate( "Selected_Customer.Contact_Name", "Not Applicable (CCN)" ); + nwipe_conf_populate( "Selected_Customer.Contact_Phone", "Not Applicable (CP)" ); + + /** + * Write out the new configuration. + */ + if( !config_write_file( &nwipe_cfg, nwipe_config_file ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write nwipe config to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Sucessfully written nwipe config to %s", nwipe_config_file ); + } + + /* Read the nwipe.conf configuration file and report any errors */ + if( !config_read_file( &nwipe_cfg, nwipe_config_file ) ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Syntax error: %s:%d - %s\n", + config_error_file( &nwipe_cfg ), + config_error_line( &nwipe_cfg ), + config_error_text( &nwipe_cfg ) ); + } + + /* ----------------------------------------------------------------------------- + * Now check nwipe_customers.csv exists, if not create it with a basic structure + */ + if( access( nwipe_customers_file, F_OK ) == 0 ) + { + nwipe_log( NWIPE_LOG_INFO, "Nwipes customer file %s exists", nwipe_customers_file ); + } + else + { + nwipe_log( NWIPE_LOG_WARNING, "%s does not exist", nwipe_customers_file ); + + /* We assume the /etc/nwipe directory doesn't exist, so try to create it */ + mkdir( nwipe_config_directory, 0755 ); + + /* create the nwipe_customers.csv file */ + if( !( fp_customers = fopen( nwipe_customers_file, "w" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to create %s", nwipe_customers_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Created %s", nwipe_customers_file ); + + /* Now populate the csv header and first entry, Lines 1 and 2 */ + if( fwrite( nwipe_customers_initial_content, sizeof( nwipe_customers_initial_content ), 1, fp_customers ) + == 1 ) + { + nwipe_log( NWIPE_LOG_INFO, "Populated %s with basic config", nwipe_customers_file ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write basic config to %s", nwipe_customers_file ); + } + fclose( fp_customers ); + } + } + return ( 0 ); +} + +void save_selected_customer( char** customer ) +{ + /* This function saves the user selected customer + * to nwipe's config file /etc/nwipe/nwipe.conf + * for later use by the PDF creation functions. + */ + + int idx; + int field_count; + int field_idx; + + char field_1[FIELD_LENGTH]; + char field_2[FIELD_LENGTH]; + char field_3[FIELD_LENGTH]; + char field_4[FIELD_LENGTH]; + + /* zero the field strings */ + for( idx = 0; idx < FIELD_LENGTH; idx++ ) + field_1[idx] = 0; + for( idx = 0; idx < FIELD_LENGTH; idx++ ) + field_2[idx] = 0; + for( idx = 0; idx < FIELD_LENGTH; idx++ ) + field_3[idx] = 0; + for( idx = 0; idx < FIELD_LENGTH; idx++ ) + field_4[idx] = 0; + + /* Extract the field contents from the csv string + */ + idx = 0; + field_idx = 0; + field_count = 1; + + while( *( *customer + idx ) != 0 && field_count < NUMBER_OF_FIELDS + 1 ) + { + /* Start of a field? */ + if( *( *customer + idx ) == '\"' ) + { + idx++; + + while( *( *customer + idx ) != '\"' && *( *customer + idx ) != 0 ) + { + if( field_count == 1 && field_idx < ( FIELD_LENGTH - 1 ) ) + { + field_1[field_idx++] = *( *customer + idx ); + } + else + { + if( field_count == 2 && field_idx < ( FIELD_LENGTH - 1 ) ) + { + field_2[field_idx++] = *( *customer + idx ); + } + else + { + if( field_count == 3 && field_idx < ( FIELD_LENGTH - 1 ) ) + { + field_3[field_idx++] = *( *customer + idx ); + } + else + { + if( field_count == 4 && field_idx < ( FIELD_LENGTH - 1 ) ) + { + field_4[field_idx++] = *( *customer + idx ); + } + } + } + } + idx++; + } + if( *( *customer + idx ) == '\"' ) + { + /* Makesure the field string is terminated */ + switch( field_count ) + { + case 1: + field_1[field_idx] = 0; + break; + case 2: + field_2[field_idx] = 0; + break; + case 3: + field_3[field_idx] = 0; + break; + case 4: + field_4[field_idx] = 0; + break; + } + + field_count++; + field_idx = 0; + } + } + idx++; + } + + /* All 4 fields present? */ + if( field_count != NUMBER_OF_FIELDS + 1 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Insuffient fields in customer entry, expected %i, actual(field_count) %i, idx=%i", + NUMBER_OF_FIELDS, + field_count, + idx ); + return; + } + + /* ------------------------------------------------------------- + * Write the fields to nwipe's config file /etc/nwipe/nwipe.conf + */ + if( ( setting = config_lookup( &nwipe_cfg, "Selected_Customer.Customer_Name" ) ) ) + { + config_setting_set_string( setting, field_1 ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Can't find \"Selected Customers.Customer_Name\" in %s", nwipe_config_file ); + } + + if( ( setting = config_lookup( &nwipe_cfg, "Selected_Customer.Customer_Address" ) ) ) + { + config_setting_set_string( setting, field_2 ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Can't find \"Selected Customers.Customer_Address\" in %s", nwipe_config_file ); + } + + if( ( setting = config_lookup( &nwipe_cfg, "Selected_Customer.Contact_Name" ) ) ) + { + config_setting_set_string( setting, field_3 ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Can't find \"Selected Customers.Contact_Name\" in %s", nwipe_config_file ); + } + + if( ( setting = config_lookup( &nwipe_cfg, "Selected_Customer.Contact_Phone" ) ) ) + { + config_setting_set_string( setting, field_4 ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Can't find \"Selected Customers.Contact_Phone\" in %s", nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( !config_write_file( &nwipe_cfg, nwipe_config_file ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write user selected customer to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Populated %s with user selected customer", nwipe_config_file ); + } +} + +int nwipe_conf_update_setting( char* group_name_setting_name, char* setting_value ) +{ + /* You would call this function of you wanted to update an existing setting in nwipe.conf, i.e + * + * nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "ENABLED" ) + * + * It is NOT used for creating a new group or setting name. + */ + + /* ------------------------------------------------------------- + * Write the field to nwipe's config file /etc/nwipe/nwipe.conf + */ + if( ( setting = config_lookup( &nwipe_cfg, group_name_setting_name ) ) ) + { + config_setting_set_string( setting, setting_value ); + } + else + { + nwipe_log( + NWIPE_LOG_ERROR, "Can't find group.setting_name %s in %s", group_name_setting_name, nwipe_config_file ); + return 1; + } + + /* Write the new configuration to nwipe.conf + */ + if( !config_write_file( &nwipe_cfg, nwipe_config_file ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write %s to %s", group_name_setting_name, nwipe_config_file ); + return 2; + } + else + { + nwipe_log( NWIPE_LOG_INFO, + "Updated %s with value %s in %s", + group_name_setting_name, + setting_value, + nwipe_config_file ); + } + + return 0; + +} // end nwipe_conf_update_setting() + +int nwipe_conf_read_setting( char* group_name_setting_name, const char** setting_value ) +{ + /* You would call this function if you wanted to read a settings value in nwipe.conf, i.e + * + * const char ** pReturnString; + * nwipe_conf_read_setting( "PDF_Certificate", "PDF_Enable", pReturnString ); + * + */ + + /* Separate group_name_setting_name i.e "PDF_Certificate.PDF_Enable" string + * into two separate strings by replacing the period with a NULL. + */ + + int return_status; + int length = strlen( group_name_setting_name ); + + char* group_name = malloc( length ); + char* setting_name = malloc( length ); + + int idx = 0; + + while( group_name_setting_name[idx] != 0 && group_name_setting_name[idx] != '.' ) + { + if( group_name_setting_name[idx] == '.' ) + { + break; + } + idx++; + } + memcpy( group_name, group_name_setting_name, idx ); + strcpy( setting_name, &group_name_setting_name[idx + 1] ); + + if( !( setting = config_lookup( &nwipe_cfg, group_name ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Can't find group name %s.%s in %s", group_name, setting_name, nwipe_config_file ); + return_status = -1; + } + else + { + /* Retrieve data from nwipe.conf */ + if( CONFIG_TRUE == config_setting_lookup_string( setting, setting_name, setting_value ) ) + { + return_status = 0; /* Success */ + } + else + { + nwipe_log( + NWIPE_LOG_ERROR, "Can't find setting_name %s.%s in %s", group_name, setting_name, nwipe_config_file ); + return_status = -2; + } + } + + free( group_name ); + free( setting_name ); + return ( return_status ); + +} // end nwipe_conf_read_setting() + +int nwipe_conf_populate( char* path, char* value ) +{ + /* This function will check that a path containing a group or multiple groups that lead to a setting all exist, + * if they don't exist, the group/s, settings and associated value are created. + * + * The path, a string consisting of one or more groups separted by a period symbol + * '.' with the final element in the path being the setting name. For instance the path might be + * PDF_Certificate.PDF_Enable. Where PDF_Certificate is the group name and PDF_Enable is the setting name. + * If one or other don't exist then they will be created. + * + * An arbitary depth of four groups are allowed for nwipe's configuration file, although we only currently, as of + * October 2023 use a depth of one group. The number of groups can be increased in the future if required by + * changing the definition MAX_GROUP_DEPTH in conf.h + */ + + char* path_copy; + char* path_build; + + char* group_start[MAX_GROUP_DEPTH + 2]; // A pointer to the start of each group string + char* setting_start; + + int idx; // General index + int group_count; // Counts the number of groups in the path + + /* Initialise the pointers */ + memset( group_start, 0, MAX_GROUP_DEPTH + 2 ); + memset( &setting_start, 0, 1 ); + + /* Allocate enough memory for a copy of the path and initialise to zero */ + path_copy = calloc( strlen( path ) + 1, sizeof( char ) ); + path_build = calloc( strlen( path ) + 1, sizeof( char ) ); + + /* Duplicate the path */ + strcpy( path_copy, path ); + + /* Create individual strings by replacing the period '.' with NULL, counting the number of groups. */ + idx = 0; + group_count = 0; + + /* pointer to first group */ + group_start[group_count] = path_copy; + + while( *( path_copy + idx ) != 0 ) + { + if( group_count > MAX_GROUP_DEPTH ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Too many groups in path, specified = %i, allowed = %i ", + group_count, + MAX_GROUP_DEPTH ); + return 1; + } + + if( *( path_copy + idx ) == '.' ) + { + *( path_copy + idx ) = 0; + group_count++; + group_start[group_count] = path_copy + idx + 1; + } + idx++; + } + + /* setting_start points to a string that represents the setting to be created */ + setting_start = group_start[group_count]; + + /* Remove the last entry from group_start as that would be the setting and not a group */ + group_start[group_count] = 0; + + if( group_count == 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "No groups specified in path, i.e. no period . separator found." ); + return 2; + } + + /** + * Now determine whether the group/s in the path exist, if not create them. + */ + + idx = 0; + while( group_start[idx] != 0 ) + { + strcat( path_build, group_start[idx] ); + + if( !( group = config_lookup( &nwipe_cfg, path_build ) ) ) + { + if( idx == 0 ) + { + group = config_setting_add( root, path_build, CONFIG_TYPE_GROUP ); + previous_group = group; + } + else + { + group = config_setting_add( previous_group, group_start[idx], CONFIG_TYPE_GROUP ); + previous_group = group; + } + if( group ) + { + nwipe_log( NWIPE_LOG_INFO, "Created group [%s] in %s", path_build, nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to create group [%s] in %s", path_build, nwipe_config_file ); + } + } + else + { + previous_group = group; + } + + idx++; + + if( group_start[idx] != 0 ) + { + strcat( path_build, "." ); + } + } + + /** + * And finally determine whether the setting already exists, if not create it and assign the value to it + */ + + /* Does the full path exist ? i.e AAA.BBB */ + if( ( group = config_lookup( &nwipe_cfg, path_build ) ) ) + { + /* Does the path and setting exist? AAA.BBB.SETTING_NAME */ + if( !( setting = config_lookup( &nwipe_cfg, path ) ) ) + { + /* Add the new SETTING_NAME */ + if( ( setting = config_setting_add( group, setting_start, CONFIG_TYPE_STRING ) ) ) + { + nwipe_log( NWIPE_LOG_INFO, "Created setting name %s in %s", path, nwipe_config_file ); + } + else + { + nwipe_log( + NWIPE_LOG_ERROR, "Failed to create setting name %s in %s", setting_start, nwipe_config_file ); + } + + if( config_setting_set_string( setting, value ) == CONFIG_TRUE ) + { + nwipe_log( NWIPE_LOG_INFO, "Set value for %s in %s to %s", path, nwipe_config_file, value ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to set value for %s in %s to %s", path, nwipe_config_file, value ); + } + } + else + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Setting already exists [%s] in %s", path, nwipe_config_file ); + } + } + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Couldn't find constructed path [%s] in %s", path_build, nwipe_config_file ); + } + + free( path_copy ); + free( path_build ); + + return 0; +} + +void nwipe_conf_close() +{ + config_destroy( &nwipe_cfg ); +} diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..4fce884 --- /dev/null +++ b/src/conf.h @@ -0,0 +1,55 @@ +#ifndef CONF_H_ +#define CONF_H_ + +/** + * Initialises the libconfig code, called once at the + * start of nwipe, prior to any attempts to access + * nwipe's config file /etc/nwipe/nwipe.conf + * @param none + * @return int + * 0 = success + * -1 = error + */ +int nwipe_conf_init(); + +/** + * Before exiting nwipe, this function should be called + * to free up libconfig's memory usage + * @param none + * @return void + */ +void nwipe_conf_close(); + +void save_selected_customer( char** ); + +/** + * int nwipe_conf_update_setting( char *, char * ); + * Use this function to update a setting in nwipe.conf + * @param char * this is the group name and setting name separated by a period '.' + * i.e "PDF_Certificate.PDF_Enable" + * @param char * this is the setting, i.e ENABLED + * @return int 0 = Success + * 1 = Unable to update memory copy + * 2 = Unable to write new configuration to /etc/nwipe/nwipe.conf + */ +int nwipe_conf_update_setting( char*, char* ); + +/** + * int nwipe_conf_read_setting( char *, char *, const char ** ) + * Use this function to read a setting value in nwipe.conf + * @param char * this is the group name + * @param char * this is the setting name + * @param char ** this is a pointer to the setting value + * @return int 0 = Success + * -1 = Unable to find the specified group name + * -2 = Unable to find the specified setting name + */ +int nwipe_conf_read_setting( char*, const char** ); + +int nwipe_conf_populate( char* path, char* value ); + +#define FIELD_LENGTH 256 +#define NUMBER_OF_FIELDS 4 +#define MAX_GROUP_DEPTH 4 + +#endif /* CONF_H_ */ diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..80edf6e --- /dev/null +++ b/src/context.h @@ -0,0 +1,228 @@ +/* + * context.h: The internal state representation of nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef CONTEXT_H_ +#define CONTEXT_H_ + +#include "prng.h" +#ifndef __HDDTEMP_H__ +#include "hddtemp_scsi/hddtemp.h" +#endif /* __HDDTEMP_H__ */ + +typedef enum nwipe_device_t_ { + NWIPE_DEVICE_UNKNOWN = 0, // Unknown device. + NWIPE_DEVICE_IDE, + NWIPE_DEVICE_SCSI, + NWIPE_DEVICE_COMPAQ, // Unimplemented. + NWIPE_DEVICE_USB, + NWIPE_DEVICE_IEEE1394, // Unimplemented. + NWIPE_DEVICE_ATA, + NWIPE_DEVICE_NVME, + NWIPE_DEVICE_VIRT, + NWIPE_DEVICE_SAS, + NWIPE_DEVICE_MMC +} nwipe_device_t; + +typedef enum nwipe_pass_t_ { + NWIPE_PASS_NONE = 0, // Not running. + NWIPE_PASS_WRITE, // Writing patterns to the device. + NWIPE_PASS_VERIFY, // Verifying a pass. + NWIPE_PASS_FINAL_BLANK, // Filling the device with zeros. + NWIPE_PASS_FINAL_OPS2 // Special case for nwipe_ops2. +} nwipe_pass_t; + +typedef enum nwipe_select_t_ { + NWIPE_SELECT_NONE = 0, // Unused. + NWIPE_SELECT_TRUE, // Wipe this device. + NWIPE_SELECT_TRUE_PARENT, // A parent of this device has been selected, so the wipe is implied. + NWIPE_SELECT_FALSE, // Do not wipe this device. + NWIPE_SELECT_FALSE_CHILD, // A child of this device has been selected, so we can't wipe this device. + NWIPE_SELECT_DISABLED // Do not wipe this device and do not allow it to be selected. +} nwipe_select_t; + +#define NWIPE_KNOB_SPEEDRING_SIZE 30 +#define NWIPE_KNOB_SPEEDRING_GRANULARITY 10 + +typedef struct nwipe_speedring_t_ +{ + u64 bytes[NWIPE_KNOB_SPEEDRING_SIZE]; + u64 bytestotal; + u64 byteslast; + time_t times[NWIPE_KNOB_SPEEDRING_SIZE]; + time_t timestotal; + time_t timeslast; + u32 position; +} nwipe_speedring_t; + +#define NWIPE_DEVICE_LABEL_LENGTH 200 +#define NWIPE_DEVICE_SIZE_TXT_LENGTH 8 + +// Arbitrary length, so far most paths don't exceed about 25 characters +#define MAX_HWMON_PATH_LENGTH 100 + +// 20 chracters for serial number plus null Byte +#define NWIPE_SERIALNUMBER_LENGTH 20 + +typedef struct nwipe_context_t_ +{ + /* + * Device fields + */ + int device_block_size; // The soft block size reported by the device, as logical + int device_sector_size; // The logical sector size reported by libparted + int device_phys_sector_size; // The physical sector size reported by libparted + int device_bus; // The device bus number. + int device_fd; // The file descriptor of the device file being wiped. + int device_host; // The host number. + struct hd_driveid device_id; // The WIN_IDENTIFY data for IDE drives. + int device_lun; // The device logical unit number. + int device_major; // The major device number. + int device_minor; // The minor device number. + int device_part; // The device partition or slice number. + char* device_name; // The device file name. + char device_name_without_path[100]; + char gui_device_name[100]; + unsigned long long device_size; // The device size in bytes. + u64 device_size_in_sectors; // The device size in number of logical sectors, this may be 512 or 4096 sectors + u64 device_size_in_512byte_sectors; // The device size in number of 512byte sectors, irrespective of logical sector + // size reported by libata + unsigned long long bytes_erased; // Irrespective of pass, this how much of the drive has been erased, CANNOT be + // greater than device_size. + char* device_size_text; // The device size in a more (human)readable format. + char device_size_txt[NWIPE_DEVICE_SIZE_TXT_LENGTH]; // The device size in a more (human)readable format. + char* device_model; // The model of the device. + char device_label[NWIPE_DEVICE_LABEL_LENGTH]; // The label (name, model, size and serial) of the device. + struct stat device_stat; // The device file state from fstat(). + nwipe_device_t device_type; // Indicates an IDE, SCSI, or Compaq SMART device in enumerated form (int) + char device_type_str[14]; // Indicates an IDE, SCSI, USB etc as per nwipe_device_t but in ascii + int device_is_ssd; // 0 = no SSD, 1 = is a SSD + char device_serial_no[NWIPE_SERIALNUMBER_LENGTH + + 1]; // Serial number(processed, 20 characters plus null termination) of the device. + int device_target; // The device target. + + u64 eta; // The estimated number of seconds until method completion. + int entropy_fd; // The entropy source. Usually /dev/urandom. + int pass_count; // The number of passes performed by the working wipe method. + u64 pass_done; // The number of bytes that have already been i/o'd in this pass. + u64 pass_errors; // The number of errors across all passes. + u64 pass_size; // The total number of i/o bytes across all passes. + nwipe_pass_t pass_type; // The type of the current working pass. + int pass_working; // The current working pass. + nwipe_prng_t* prng; // The PRNG implementation. + nwipe_entropy_t prng_seed; // The random data that is used to seed the PRNG. + void* prng_state; // The private internal state of the PRNG. + int result; // The process return value. + int round_count; // The number of rounds requested by the user for the working wipe method. + u64 round_done; // The number of bytes that have already been i/o'd. + u64 round_errors; // The number of errors across all rounds. + u64 round_size; // The total number of i/o bytes across all rounds. + double round_percent; // The percentage complete across all rounds. + int round_working; // The current working round. + nwipe_select_t select; // Indicates whether this device should be wiped. + int signal; // Set when the child is killed by a signal. + nwipe_speedring_t speedring; // Ring buffer for computing the rolling throughput average. + short sync_status; // A flag to indicate when the method is syncing. + pthread_t thread; // The ID of the thread. + u64 throughput; // Average throughput in bytes per second. + char throughput_txt[13]; // Human readable throughput. + u64 verify_errors; // The number of verification errors across all passes. + int templ_has_hwmon_data; // 0 = no hwmon data available, 1 = hwmon data available + int templ_has_scsitemp_data; // 0 = no scsitemp data available, 1 = scsitemp data available + char temp1_path[MAX_HWMON_PATH_LENGTH]; // path to temperature variables /sys/class/hwmon/hwmonX/ etc. + int temp1_crit; // Critical high drive temperature, 1000000=unitialised, millidegree celsius. + int temp1_highest; // Historical highest temperature reached, 1000000=unitialised, millidegree celsius. + int temp1_input; // drive temperature, -1=unitialised. 1000000=unitialised, millidegree celsius. + int temp1_lcrit; // Critical low drive temperature, 1000000=unitialised, millidegree celsius. + int temp1_lowest; // Historically lowest temperature, 1000000=unitialised, millidegree celsius. + int temp1_max; // Maximum allowed temperature, 1000000=unitialised, millidegree celsius. + int temp1_min; // Minimum allowed temperature, 1000000=unitialised, millidegree celsius. + int temp1_monitored_wipe_max; + int temp1_monitored_wipe_min; + int temp1_monitored_wipe_avg; + int temp1_flash_rate; // number relates to one tenth of a second, so 2 means a flash on and off = 0.4s + int temp1_flash_rate_counter; // used by the gui for timing the flash rate + int temp1_flash_rate_status; // 0=blank 1=visible + time_t temp1_time; // The time when temperature was last checked, seconds since epoch + struct disk* templ_disk; // Pointer to disk structure for hddtemp SCSI routines + int wipe_status; // Wipe finished = 0, wipe in progress = 1, wipe yet to start = -1. + char wipe_status_txt[10]; // ERASED, FAILED, ABORTED, INSANITY + int spinner_idx; // Index into the spinner character array + char spinner_character[1]; // The current spinner character + double duration; // Duration of the wipe in seconds + char duration_str[20]; // The duration string in hh:mm:ss + time_t start_time; // Start time of wipe + time_t end_time; // End time of wipe + u64 fsyncdata_errors; // The number of fsyncdata errors across all passes. + char PDF_filename[FILENAME_MAX]; // The filename of the PDF certificate/report. + int HPA_status; // 0 = No HPA found/disabled, 1 = HPA detected, 2 = Unknown, unable to checked, + // 3 = Not applicable to this device + u64 HPA_reported_set; // the 'HPA set' value reported hdparm -N, i.e the first value of n/n + u64 HPA_reported_real; // the 'HPA real' value reported hdparm -N, i.e the second value of n/n + int DCO_status; // 0 = No DCO found, 1 = DCO detected, 2 = Unknown, unable to checked + u64 DCO_reported_real_max_sectors; // real max sectors as reported by hdparm --dco-identify + u64 DCO_reported_real_max_size; // real max sectors in bytes + u64 Calculated_real_max_size_in_bytes; // This value is determined from all the possible variations for drives that + // don't support DCO/HPA and those that do. Also drives that can't provide + // HPA/DCO due to the chips they use (USB adapters) + char DCO_reported_real_max_size_text[NWIPE_DEVICE_SIZE_TXT_LENGTH]; // real max size in human readable form i.e 1TB + char Calculated_real_max_size_in_bytes_text[NWIPE_DEVICE_SIZE_TXT_LENGTH]; // calculated real max human readable + u64 HPA_sectors; // The size of the host protected area in sectors + char HPA_size_text[NWIPE_DEVICE_SIZE_TXT_LENGTH]; // Human readable size bytes, KB, MB, GB .. + int HPA_display_toggle_state; // 0 or 1 Used to toggle between "[1TB] [ 33C]" and [HDA STATUS] + time_t HPA_toggle_time; // records a time, then if for instance 3 seconds has elapsed the display changes + int test_use1; + int test_use2; + + /* + * Identity contains the raw serial number of the drive + * (where applicable), however, for use within nwipe use the + * processed serial_no[21] string above. To access serial no. use + * c[i]->serial_no) and not c[i]->identity.serial_no); + */ + struct hd_driveid identity; +} nwipe_context_t; + +/* + * We use 2 data structs to pass data between threads. + * The first contains any required values. + * Values cannot form part of the second array below, hence the need for this. + */ +typedef struct +{ + int nwipe_enumerated; // The number of devices available. + int nwipe_selected; // The number of devices being wiped. + time_t maxeta; // The estimated runtime of the slowest device. + u64 throughput; // Total throughput. + u64 errors; // The combined number of errors of all processes. + pthread_t* gui_thread; // The ID of GUI thread. +} nwipe_misc_thread_data_t; + +/* + * The second points to the first structure, as well as the structure of all the devices + */ +typedef struct +{ + nwipe_context_t** c; // Pointer to the nwipe context structure. + nwipe_misc_thread_data_t* nwipe_misc_thread_data; // Pointer to the misc structure above. +} nwipe_thread_data_ptr_t; + +#endif /* CONTEXT_H_ */ diff --git a/src/create_pdf.c b/src/create_pdf.c new file mode 100644 index 0000000..754543b --- /dev/null +++ b/src/create_pdf.c @@ -0,0 +1,997 @@ +/* + * create_pdf.c: Routines that create the PDF erasure certificate + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <stdint.h> +#include "stdarg.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "nwipe.h" +#include "context.h" +#include "create_pdf.h" +#include "PDFGen/pdfgen.h" +#include "version.h" +#include "method.h" +#include "embedded_images/shred_db.jpg.h" +#include "embedded_images/tick_erased.jpg.h" +#include "embedded_images/redcross.h" +#include "embedded_images/nwipe_exclamation.jpg.h" +#include "logging.h" +#include "options.h" +#include "prng.h" +#include "hpa_dco.h" +#include "miscellaneous.h" +#include <libconfig.h> +#include "conf.h" + +#define text_size_data 10 + +struct pdf_doc* pdf; +struct pdf_object* page; + +char model_header[50] = ""; /* Model text in the header */ +char serial_header[30] = ""; /* Serial number text in the header */ +char barcode[100] = ""; /* Contents of the barcode, i.e model:serial */ +char pdf_footer[MAX_PDF_FOOTER_TEXT_LENGTH]; +float height; +float page_width; +int status_icon; + +int create_pdf( nwipe_context_t* ptr ) +{ + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + + /* Used by libconfig functions to retrieve data from nwipe.conf defined in conf.c */ + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + // char pdf_footer[MAX_PDF_FOOTER_TEXT_LENGTH]; + nwipe_context_t* c; + c = ptr; + // char model_header[50] = ""; /* Model text in the header */ + // char serial_header[30] = ""; /* Serial number text in the header */ + char device_size[100] = ""; /* Device size in the form xMB (xxxx bytes) */ + // char barcode[100] = ""; /* Contents of the barcode, i.e model:serial */ + char verify[20] = ""; /* Verify option text */ + char blank[10] = ""; /* blanking pass, none, zeros, ones */ + char rounds[50] = ""; /* rounds ASCII numeric */ + char prng_type[50] = ""; /* type of prng, twister, isaac, isaac64 */ + char start_time_text[50] = ""; + char end_time_text[50] = ""; + char bytes_erased[50] = ""; + char HPA_status_text[50] = ""; + char HPA_size_text[50] = ""; + char errors[50] = ""; + char throughput_txt[50] = ""; + char bytes_percent_str[7] = ""; + + // int status_icon; + + // float height; + // float page_width; + + struct pdf_info info = { .creator = "https://github.com/PartialVolume/shredos.x86_64", + .producer = "https://github.com/martijnvanbrummelen/nwipe", + .title = "PDF Disk Erasure Certificate", + .author = "Nwipe", + .subject = "Disk Erase Certificate", + .date = "Today" }; + + /* A pointer to the system time struct. */ + struct tm* p; + + /* variables used by libconfig */ + config_setting_t* setting; + const char *business_name, *business_address, *contact_name, *contact_phone, *op_tech_name, *customer_name, + *customer_address, *customer_contact_name, *customer_contact_phone; + + /* ------------------ */ + /* Initialise Various */ + + /* Used to display correct icon on page 2 */ + status_icon = 0; // zero don't display icon, see header STATUS_ICON_.. + + // nwipe_log( NWIPE_LOG_NOTICE, "Create the PDF disk erasure certificate" ); + // struct pdf_doc* pdf = pdf_create( PDF_A4_WIDTH, PDF_A4_HEIGHT, &info ); + pdf = pdf_create( PDF_A4_WIDTH, PDF_A4_HEIGHT, &info ); + + /* Create footer text string and append the version */ + snprintf( pdf_footer, sizeof( pdf_footer ), "Disc Erasure by NWIPE version %s", version_string ); + + pdf_set_font( pdf, "Helvetica" ); + struct pdf_object* page_1 = pdf_append_page( pdf ); + + /* Obtain page page_width */ + page_width = pdf_page_width( page_1 ); + + /********************************************************************* + * Create header and footer on page 1, with the exception of the green + * tick/red icon which is set from the 'status' section below + */ + pdf_add_text_wrap( pdf, NULL, pdf_footer, 12, 0, 30, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_add_line( pdf, NULL, 50, 50, 550, 50, 3, PDF_BLACK ); + pdf_add_line( pdf, NULL, 50, 650, 550, 650, 3, PDF_BLACK ); + pdf_add_image_data( pdf, NULL, 45, 665, 100, 100, bin2c_shred_db_jpg, 27063 ); + pdf_set_font( pdf, "Helvetica-Bold" ); + snprintf( model_header, sizeof( model_header ), " %s: %s ", "Model", c->device_model ); + pdf_add_text_wrap( pdf, NULL, model_header, 14, 0, 755, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + snprintf( serial_header, sizeof( serial_header ), " %s: %s ", "S/N", c->device_serial_no ); + pdf_add_text_wrap( pdf, NULL, serial_header, 14, 0, 735, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_set_font( pdf, "Helvetica" ); + + pdf_add_text_wrap( pdf, NULL, "Disk Erasure Report", 24, 0, 695, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + snprintf( barcode, sizeof( barcode ), "%s:%s", c->device_model, c->device_serial_no ); + pdf_add_text_wrap( + pdf, NULL, "Page 1 - Erasure Status", 14, 0, 670, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_add_barcode( pdf, NULL, PDF_BARCODE_128A, 100, 790, 400, 25, barcode, PDF_BLACK ); + + /* ------------------------ */ + /* Organisation Information */ + + pdf_add_line( pdf, NULL, 50, 550, 550, 550, 1, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Organisation Performing The Disk Erasure", 12, 50, 630, PDF_BLUE ); + pdf_add_text( pdf, NULL, "Business Name:", 12, 60, 610, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Business Address:", 12, 60, 590, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Contact Name:", 12, 60, 570, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Contact Phone:", 12, 300, 570, PDF_GRAY ); + + /* Obtain organisational details from nwipe.conf - See conf.c */ + setting = config_lookup( &nwipe_cfg, "Organisation_Details" ); + if( setting != NULL ) + { + pdf_set_font( pdf, "Helvetica-Bold" ); + if( config_setting_lookup_string( setting, "Business_Name", &business_name ) ) + { + pdf_add_text( pdf, NULL, business_name, text_size_data, 153, 610, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Business_Address", &business_address ) ) + { + pdf_add_text( pdf, NULL, business_address, text_size_data, 165, 590, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Contact_Name", &contact_name ) ) + { + pdf_add_text( pdf, NULL, contact_name, text_size_data, 145, 570, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Contact_Phone", &contact_phone ) ) + { + pdf_add_text( pdf, NULL, contact_phone, text_size_data, 390, 570, PDF_BLACK ); + } + pdf_set_font( pdf, "Helvetica" ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Cannot locate group [Organisation_Details] in %s", nwipe_config_file ); + } + + /* -------------------- */ + /* Customer Information */ + pdf_add_line( pdf, NULL, 50, 450, 550, 450, 1, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Customer Details", 12, 50, 530, PDF_BLUE ); + pdf_add_text( pdf, NULL, "Name:", 12, 60, 510, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Address:", 12, 60, 490, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Contact Name:", 12, 60, 470, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Contact Phone:", 12, 300, 470, PDF_GRAY ); + + /* Obtain current customer details from nwipe.conf - See conf.c */ + setting = config_lookup( &nwipe_cfg, "Selected_Customer" ); + if( setting != NULL ) + { + pdf_set_font( pdf, "Helvetica-Bold" ); + if( config_setting_lookup_string( setting, "Customer_Name", &customer_name ) ) + { + pdf_add_text( pdf, NULL, customer_name, text_size_data, 100, 510, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Customer_Address", &customer_address ) ) + { + pdf_add_text( pdf, NULL, customer_address, text_size_data, 110, 490, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Contact_Name", &customer_contact_name ) ) + { + pdf_add_text( pdf, NULL, customer_contact_name, text_size_data, 145, 470, PDF_BLACK ); + } + if( config_setting_lookup_string( setting, "Contact_Phone", &customer_contact_phone ) ) + { + pdf_add_text( pdf, NULL, customer_contact_phone, text_size_data, 390, 470, PDF_BLACK ); + } + pdf_set_font( pdf, "Helvetica" ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Cannot locate group [Selected_Customer] in %s", nwipe_config_file ); + } + + /****************** + * Disk Information + */ + pdf_add_line( pdf, NULL, 50, 350, 550, 350, 1, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Disk Information", 12, 50, 430, PDF_BLUE ); + + /************ + * Make/model + */ + pdf_add_text( pdf, NULL, "Make/Model:", 12, 60, 410, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, c->device_model, text_size_data, 135, 410, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /************ + * Serial no. + */ + pdf_add_text( pdf, NULL, "Serial:", 12, 340, 410, PDF_GRAY ); + if( c->device_serial_no[0] == 0 ) + { + snprintf( c->device_serial_no, sizeof( c->device_serial_no ), "Unknown" ); + } + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, c->device_serial_no, text_size_data, 380, 410, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /****************************** + * Bus type, ATA, USB, NVME etc + */ + pdf_add_text( pdf, NULL, "Bus:", 12, 340, 390, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, c->device_type_str, text_size_data, 370, 390, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /************************* + * Capacity (Size) of disk + */ + + /* Size (Apparent) */ + pdf_add_text( pdf, NULL, "Size(Apparent): ", 12, 60, 390, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + snprintf( device_size, sizeof( device_size ), "%s, %lli bytes", c->device_size_text, c->device_size ); + if( ( c->device_size == c->Calculated_real_max_size_in_bytes ) || c->device_type == NWIPE_DEVICE_NVME + || c->device_type == NWIPE_DEVICE_VIRT || c->HPA_status == HPA_NOT_APPLICABLE || c->HPA_status != HPA_UNKNOWN ) + { + pdf_add_text( pdf, NULL, device_size, text_size_data, 145, 390, PDF_DARK_GREEN ); + } + else + { + pdf_add_text( pdf, NULL, device_size, text_size_data, 145, 390, PDF_RED ); + } + pdf_set_font( pdf, "Helvetica" ); + + /* Size (Real) */ + pdf_add_text( pdf, NULL, "Size(Real):", 12, 60, 370, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + if( c->device_type == NWIPE_DEVICE_NVME || c->device_type == NWIPE_DEVICE_VIRT + || c->HPA_status == HPA_NOT_APPLICABLE ) + { + snprintf( device_size, sizeof( device_size ), "%s, %lli bytes", c->device_size_text, c->device_size ); + pdf_add_text( pdf, NULL, device_size, text_size_data, 125, 370, PDF_DARK_GREEN ); + } + else + { + /* If the calculared real max size as determined from HPA/DCO and libata data is larger than + * or equal to the apparent device size then display that value in green. + */ + if( c->Calculated_real_max_size_in_bytes >= c->device_size ) + { + /* displays the real max size of the disc from the DCO displayed in Green */ + snprintf( device_size, + sizeof( device_size ), + "%s, %lli bytes", + c->Calculated_real_max_size_in_bytes_text, + c->Calculated_real_max_size_in_bytes ); + pdf_add_text( pdf, NULL, device_size, text_size_data, 125, 370, PDF_DARK_GREEN ); + } + else + { + /* If there is no real max size either because the drive or adapter doesn't support it */ + if( c->HPA_status == HPA_UNKNOWN ) + { + snprintf( device_size, sizeof( device_size ), "Unknown" ); + pdf_add_text( pdf, NULL, device_size, text_size_data, 125, 370, PDF_RED ); + } + else + { + /* we are already here because c->DCO_reported_real_max_size < 1 so if HPA enabled then use the + * value we determine from whether HPA set, HPA real exist and if not assume libata's value*/ + if( c->HPA_status == HPA_ENABLED ) + { + snprintf( device_size, + sizeof( device_size ), + "%s, %lli bytes", + c->device_size_text, + c->Calculated_real_max_size_in_bytes ); + pdf_add_text( pdf, NULL, device_size, text_size_data, 125, 370, PDF_DARK_GREEN ); + } + else + { + /* Sanity check, should never get here! */ + snprintf( device_size, sizeof( device_size ), "Sanity: HPA_status = %i", c->HPA_status ); + pdf_add_text( pdf, NULL, device_size, text_size_data, 125, 370, PDF_RED ); + } + } + } + } + + pdf_set_font( pdf, "Helvetica" ); + + /* --------------- */ + /* Erasure Details */ + pdf_add_text( pdf, NULL, "Disk Erasure Details", 12, 50, 330, PDF_BLUE ); + + /* start time */ + pdf_add_text( pdf, NULL, "Start time:", 12, 60, 310, PDF_GRAY ); + p = localtime( &c->start_time ); + snprintf( start_time_text, + sizeof( start_time_text ), + "%i/%02i/%02i %02i:%02i:%02i", + 1900 + p->tm_year, + 1 + p->tm_mon, + p->tm_mday, + p->tm_hour, + p->tm_min, + p->tm_sec ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, start_time_text, text_size_data, 120, 310, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /* end time */ + pdf_add_text( pdf, NULL, "End time:", 12, 300, 310, PDF_GRAY ); + p = localtime( &c->end_time ); + snprintf( end_time_text, + sizeof( end_time_text ), + "%i/%02i/%02i %02i:%02i:%02i", + 1900 + p->tm_year, + 1 + p->tm_mon, + p->tm_mday, + p->tm_hour, + p->tm_min, + p->tm_sec ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, end_time_text, text_size_data, 360, 310, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /* Duration */ + pdf_add_text( pdf, NULL, "Duration:", 12, 60, 290, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, c->duration_str, text_size_data, 115, 290, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /******************* + * Status of erasure + */ + pdf_add_text( pdf, NULL, "Status:", 12, 300, 290, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + + if( !strcmp( c->wipe_status_txt, "ERASED" ) + && ( c->HPA_status == HPA_DISABLED || c->HPA_status == HPA_NOT_APPLICABLE || c->device_type == NWIPE_DEVICE_NVME + || c->device_type == NWIPE_DEVICE_VIRT ) ) + { + pdf_add_text( pdf, NULL, c->wipe_status_txt, 12, 365, 290, PDF_DARK_GREEN ); + pdf_add_ellipse( pdf, NULL, 390, 295, 45, 10, 2, PDF_DARK_GREEN, PDF_TRANSPARENT ); + + /* Display the green tick icon in the header */ + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_te_jpg, 54896 ); + status_icon = STATUS_ICON_GREEN_TICK; // used later on page 2 + } + else + { + if( !strcmp( c->wipe_status_txt, "ERASED" ) + && ( c->HPA_status == HPA_ENABLED || c->HPA_status == HPA_UNKNOWN ) ) + { + pdf_add_ellipse( pdf, NULL, 390, 295, 45, 10, 2, PDF_RED, PDF_BLACK ); + pdf_add_text( pdf, NULL, c->wipe_status_txt, 12, 365, 290, PDF_YELLOW ); + pdf_add_text( pdf, NULL, "See Warning !", 12, 450, 290, PDF_RED ); + + /* Display the yellow exclamation icon in the header */ + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_nwipe_exclamation_jpg, 65791 ); + status_icon = STATUS_ICON_YELLOW_EXCLAMATION; // used later on page 2 + } + else + { + if( !strcmp( c->wipe_status_txt, "FAILED" ) ) + { + // text shifted left slightly in ellipse due to extra character + pdf_add_text( pdf, NULL, c->wipe_status_txt, 12, 370, 290, PDF_RED ); + + // Display the red cross in the header + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_redcross_jpg, 60331 ); + status_icon = STATUS_ICON_RED_CROSS; // used later on page 2 + } + else + { + pdf_add_text( pdf, NULL, c->wipe_status_txt, 12, 360, 290, PDF_RED ); + + // Print the red cross + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_redcross_jpg, 60331 ); + status_icon = STATUS_ICON_RED_CROSS; // used later on page 2 + } + pdf_add_ellipse( pdf, NULL, 390, 295, 45, 10, 2, PDF_RED, PDF_TRANSPARENT ); + } + } + pdf_set_font( pdf, "Helvetica" ); + + /******** + * Method + */ + pdf_add_text( pdf, NULL, "Method:", 12, 60, 270, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, nwipe_method_label( nwipe_options.method ), text_size_data, 110, 270, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /*********** + * prng type + */ + pdf_add_text( pdf, NULL, "PRNG algorithm:", 12, 300, 270, PDF_GRAY ); + if( nwipe_options.method == &nwipe_verify_one || nwipe_options.method == &nwipe_verify_zero + || nwipe_options.method == &nwipe_zero || nwipe_options.method == &nwipe_one ) + { + snprintf( prng_type, sizeof( prng_type ), "Not applicable to method" ); + } + else + { + if( nwipe_options.prng == &nwipe_twister ) + { + snprintf( prng_type, sizeof( prng_type ), "Twister" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac ) + { + snprintf( prng_type, sizeof( prng_type ), "Isaac" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac64 ) + { + snprintf( prng_type, sizeof( prng_type ), "Isaac64" ); + } + else + { + snprintf( prng_type, sizeof( prng_type ), "Unknown" ); + } + } + } + } + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, prng_type, text_size_data, 395, 270, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /****************************************************** + * Final blanking pass if selected, none, zeros or ones + */ + if( nwipe_options.noblank ) + { + strcpy( blank, "None" ); + } + else + { + strcpy( blank, "Zeros" ); + } + pdf_add_text( pdf, NULL, "Final Pass(Zeros/Ones/None):", 12, 60, 250, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, blank, text_size_data, 230, 250, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /* *********************************************************************** + * Create suitable text based on the numeric value of type of verification + */ + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + strcpy( verify, "Verify None" ); + break; + + case NWIPE_VERIFY_LAST: + strcpy( verify, "Verify Last" ); + break; + + case NWIPE_VERIFY_ALL: + strcpy( verify, "Verify All" ); + break; + } + pdf_add_text( pdf, NULL, "Verify Pass(Last/All/None):", 12, 300, 250, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, verify, text_size_data, 450, 250, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /* ************ + * bytes erased + */ + pdf_add_text( pdf, NULL, "*Bytes Erased:", 12, 60, 230, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + + /* Bytes erased is not applicable when user only requested a verify */ + if( nwipe_options.method == &nwipe_verify_one || nwipe_options.method == &nwipe_verify_zero ) + { + snprintf( bytes_erased, sizeof( bytes_erased ), "Not applicable to method" ); + pdf_add_text( pdf, NULL, bytes_erased, text_size_data, 145, 230, PDF_BLACK ); + } + else + { + if( c->device_type == NWIPE_DEVICE_NVME || c->device_type == NWIPE_DEVICE_VIRT + || c->HPA_status == HPA_NOT_APPLICABLE ) + { + convert_double_to_string( bytes_percent_str, + (double) ( (double) c->bytes_erased / (double) c->device_size ) * 100 ); + + snprintf( bytes_erased, sizeof( bytes_erased ), "%lli, (%s%%)", c->bytes_erased, bytes_percent_str ); + + if( c->bytes_erased == c->device_size ) + { + pdf_add_text( pdf, NULL, bytes_erased, text_size_data, 145, 230, PDF_DARK_GREEN ); + } + else + { + pdf_add_text( pdf, NULL, bytes_erased, text_size_data, 145, 230, PDF_RED ); + } + } + else + { + + convert_double_to_string( + bytes_percent_str, + (double) ( (double) c->bytes_erased / (double) c->Calculated_real_max_size_in_bytes ) * 100 ); + + snprintf( bytes_erased, sizeof( bytes_erased ), "%lli, (%s%%)", c->bytes_erased, bytes_percent_str ); + + if( c->bytes_erased == c->Calculated_real_max_size_in_bytes ) + { + pdf_add_text( pdf, NULL, bytes_erased, text_size_data, 145, 230, PDF_DARK_GREEN ); + } + else + { + pdf_add_text( pdf, NULL, bytes_erased, text_size_data, 145, 230, PDF_RED ); + } + } + } + pdf_set_font( pdf, "Helvetica" ); + + /************************************************ + * rounds - How many times the method is repeated + */ + pdf_add_text( pdf, NULL, "Rounds(completed/requested):", 12, 300, 230, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + if( !strcmp( c->wipe_status_txt, "ERASED" ) ) + { + snprintf( rounds, sizeof( rounds ), "%i/%i", c->round_working, nwipe_options.rounds ); + pdf_add_text( pdf, NULL, rounds, text_size_data, 470, 230, PDF_DARK_GREEN ); + } + else + { + snprintf( rounds, sizeof( rounds ), "%i/%i", c->round_working - 1, nwipe_options.rounds ); + pdf_add_text( pdf, NULL, rounds, text_size_data, 470, 230, PDF_RED ); + } + pdf_set_font( pdf, "Helvetica" ); + + /******************* + * HPA, DCO - LABELS + */ + pdf_add_text( pdf, NULL, "HPA/DCO:", 12, 60, 210, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 155, 210, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + pdf_add_text( pdf, NULL, "HPA/DCO Size:", 12, 300, 210, PDF_GRAY ); + + /******************* + * Populate HPA size + */ + + pdf_set_font( pdf, "Helvetica-Bold" ); + if( c->HPA_status == HPA_ENABLED ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "%lli sectors", c->HPA_sectors ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_RED ); + } + else + { + if( c->HPA_status == HPA_DISABLED ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "No hidden sectors" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); + } + else + { + if( c->HPA_status == HPA_NOT_APPLICABLE ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "Not Applicable" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); + } + else + { + if( c->HPA_status == HPA_UNKNOWN ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "Unknown" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_RED ); + } + } + } + } + + pdf_set_font( pdf, "Helvetica" ); + + /********************* + * Populate HPA status (and size if not applicable, NVMe and VIRT) + */ + if( c->device_type == NWIPE_DEVICE_NVME || c->device_type == NWIPE_DEVICE_VIRT + || c->HPA_status == HPA_NOT_APPLICABLE ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "Not applicable" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); + pdf_set_font( pdf, "Helvetica" ); + } + else + { + if( c->HPA_status == HPA_ENABLED ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "Hidden sectors found!" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); + pdf_set_font( pdf, "Helvetica" ); + } + else + { + if( c->HPA_status == HPA_DISABLED ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); + pdf_set_font( pdf, "Helvetica" ); + } + else + { + if( c->HPA_status == HPA_UNKNOWN ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "Unknown" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); + pdf_set_font( pdf, "Helvetica" ); + } + else + { + if( c->HPA_status == HPA_NOT_SUPPORTED_BY_DRIVE ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors **DDNSHDA" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); + pdf_set_font( pdf, "Helvetica" ); + } + } + } + } + } + + /************ + * Throughput + */ + pdf_add_text( pdf, NULL, "Throughput:", 12, 300, 190, PDF_GRAY ); + snprintf( throughput_txt, sizeof( throughput_txt ), "%s/sec", c->throughput_txt ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, throughput_txt, text_size_data, 370, 190, PDF_BLACK ); + pdf_set_font( pdf, "Helvetica" ); + + /******** + * Errors + */ + pdf_add_text( pdf, NULL, "Errors(pass/sync/verify):", 12, 60, 190, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + snprintf( errors, sizeof( errors ), "%llu/%llu/%llu", c->pass_errors, c->fsyncdata_errors, c->verify_errors ); + if( c->pass_errors != 0 || c->fsyncdata_errors != 0 || c->verify_errors != 0 ) + { + pdf_add_text( pdf, NULL, errors, text_size_data, 195, 190, PDF_RED ); + } + else + { + pdf_add_text( pdf, NULL, errors, text_size_data, 195, 190, PDF_DARK_GREEN ); + } + pdf_set_font( pdf, "Helvetica" ); + + /************* + * Information + */ + pdf_add_text( pdf, NULL, "Information:", 12, 60, 170, PDF_GRAY ); + pdf_set_font( pdf, "Helvetica-Bold" ); + + if( !strcmp( c->wipe_status_txt, "ERASED" ) && c->HPA_status == HPA_ENABLED ) + { + pdf_add_ellipse( pdf, NULL, 160, 173, 30, 9, 2, PDF_RED, PDF_BLACK ); + pdf_add_text( pdf, NULL, "Warning", text_size_data, 140, 170, PDF_YELLOW ); + + pdf_add_text( pdf, + NULL, + "Visible sectors erased as requested, however hidden sectors NOT erased", + text_size_data, + 200, + 170, + PDF_RED ); + } + else + { + if( c->HPA_status == HPA_UNKNOWN ) + { + pdf_add_ellipse( pdf, NULL, 160, 173, 30, 9, 2, PDF_RED, PDF_BLACK ); + pdf_add_text( pdf, NULL, "Warning", text_size_data, 140, 170, PDF_YELLOW ); + + pdf_add_text( pdf, + NULL, + "HPA/DCO data unavailable, can not determine hidden sector status.", + text_size_data, + 200, + 170, + PDF_RED ); + } + } + + /* info descripting what bytes erased actually means */ + pdf_add_text( pdf, + NULL, + "* bytes erased: The amount of drive that's been erased at least once", + text_size_data, + 60, + 137, + PDF_BLACK ); + + /* meaning of abreviation DDNSHPA */ + if( c->HPA_status == HPA_NOT_SUPPORTED_BY_DRIVE ) + { + pdf_add_text( + pdf, NULL, "** DDNSHPA = Drive does not support HPA/DCO", text_size_data, 60, 125, PDF_DARK_GREEN ); + } + pdf_set_font( pdf, "Helvetica" ); + + /************************ + * Technician/Operator ID + */ + pdf_add_line( pdf, NULL, 50, 120, 550, 120, 1, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Technician/Operator ID", 12, 50, 100, PDF_BLUE ); + pdf_add_text( pdf, NULL, "Name/ID:", 12, 60, 80, PDF_GRAY ); + pdf_add_text( pdf, NULL, "Signature:", 12, 300, 100, PDF_BLUE ); + pdf_add_line( pdf, NULL, 360, 65, 550, 66, 1, PDF_GRAY ); + + pdf_set_font( pdf, "Helvetica-Bold" ); + /* Obtain organisational details from nwipe.conf - See conf.c */ + setting = config_lookup( &nwipe_cfg, "Organisation_Details" ); + if( config_setting_lookup_string( setting, "Op_Tech_Name", &op_tech_name ) ) + { + pdf_add_text( pdf, NULL, op_tech_name, text_size_data, 120, 80, PDF_BLACK ); + } + pdf_set_font( pdf, "Helvetica" ); + + /*************************************** + * Populate page 2 and 3 with smart data + */ + nwipe_get_smart_data( c ); + + /***************************** + * Create the reports filename + * + * Sanitize the strings that we are going to use to create the report filename + * by converting any non alphanumeric characters to an underscore or hyphon + */ + replace_non_alphanumeric( end_time_text, '-' ); + replace_non_alphanumeric( c->device_model, '_' ); + replace_non_alphanumeric( c->device_serial_no, '_' ); + snprintf( c->PDF_filename, + sizeof( c->PDF_filename ), + "%s/nwipe_report_%s_Model_%s_Serial_%s.pdf", + nwipe_options.PDFreportpath, + end_time_text, + c->device_model, + c->device_serial_no ); + + pdf_save( pdf, c->PDF_filename ); + pdf_destroy( pdf ); + return 0; +} + +int nwipe_get_smart_data( nwipe_context_t* c ) +{ + FILE* fp; + + char* pdata; + char page_title[50]; + + char smartctl_command[] = "smartctl -a %s"; + char smartctl_command2[] = "/sbin/smartctl -a %s"; + char smartctl_command3[] = "/usr/bin/smartctl -a %s"; + char final_cmd_smartctl[sizeof( smartctl_command3 ) + 256]; + char result[512]; + char smartctl_labels_to_anonymize[][18] = { + "serial number:", "lu wwn device id:", "logical unit id:", "" /* Don't remove this empty string !, important */ + }; + + int idx, idx2, idx3; + int x, y; + int set_return_value; + int page_number; + + final_cmd_smartctl[0] = 0; + + /* Determine whether we can access smartctl, required if the PATH environment is not setup ! (Debian sid 'su' as + * opposed to 'su -' */ + if( system( "which smartctl > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/smartctl > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/smartctl > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install smartmontools !" ); + } + else + { + sprintf( final_cmd_smartctl, smartctl_command3, c->device_name ); + } + } + else + { + sprintf( final_cmd_smartctl, smartctl_command2, c->device_name ); + } + } + else + { + sprintf( final_cmd_smartctl, smartctl_command, c->device_name ); + } + + if( final_cmd_smartctl[0] != 0 ) + { + fp = popen( final_cmd_smartctl, "r" ); + + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "nwipe_get_smart_data(): Failed to create stream to %s", smartctl_command ); + + set_return_value = 3; + } + else + { + x = 50; // left side of page + y = 630; // top row of page + page_number = 2; + + /* Create Page 2 of the report. This shows the drives smart data + */ + page = pdf_append_page( pdf ); + + /* Create the header and footer for page 2, the start of the smart data */ + snprintf( page_title, sizeof( page_title ), "Page %i - Smart Data", page_number ); + create_header_and_footer( c, page_title ); + + /* Read the output a line at a time - output it. */ + while( fgets( result, sizeof( result ) - 1, fp ) != NULL ) + { + /* Convert the label, i.e everything before the ':' to lower case, it's required to + * convert to lower case as smartctl seems to use inconsistent case when labeling + * for serial number, i.e mostly it produces labels "Serial Number:" but occasionally + * it produces a label "Serial number:" */ + + idx = 0; + + while( result[idx] != 0 && result[idx] != ':' ) + { + /* If upper case alpha character, change to lower case */ + if( result[idx] >= 'A' && result[idx] <= 'Z' ) + { + result[idx] += 32; + } + idx++; + } + + if( nwipe_options.quiet == 1 ) + { + for( idx2 = 0; idx2 < 3; idx2++ ) + { + if( strstr( result, &smartctl_labels_to_anonymize[idx2][0] ) ) + { + if( ( pdata = strstr( result, ":" ) ) ) + { + idx3 = 1; + while( pdata[idx3] != 0 ) + { + if( pdata[idx3] != ' ' ) + { + pdata[idx3] = 'X'; + } + idx3++; + } + } + } + } + } + + pdf_set_font( pdf, "Courier" ); + pdf_add_text( pdf, NULL, result, 8, x, y, PDF_BLACK ); + y -= 9; + + /* Have we reached the bottom of the page yet */ + if( y < 60 ) + { + /* Append an extra page */ + page = pdf_append_page( pdf ); + page_number++; + y = 630; + + /* create the header and footer for the next page */ + snprintf( page_title, sizeof( page_title ), "Page %i - Smart Data", page_number ); + create_header_and_footer( c, page_title ); + } + } + set_return_value = 0; + } + } + else + { + set_return_value = 1; + } + return set_return_value; +} + +void create_header_and_footer( nwipe_context_t* c, char* page_title ) +{ + /************************************************************************** + * Create header and footer on most recently added page, with the exception + * of the green tick/red icon which is set from the 'status' section below. + */ + pdf_add_text_wrap( pdf, NULL, pdf_footer, 12, 0, 30, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_add_line( pdf, NULL, 50, 50, 550, 50, 3, PDF_BLACK ); + pdf_add_line( pdf, NULL, 50, 650, 550, 650, 3, PDF_BLACK ); + pdf_add_image_data( pdf, NULL, 45, 665, 100, 100, bin2c_shred_db_jpg, 27063 ); + pdf_set_font( pdf, "Helvetica-Bold" ); + snprintf( model_header, sizeof( model_header ), " %s: %s ", "Model", c->device_model ); + pdf_add_text_wrap( pdf, NULL, model_header, 14, 0, 755, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + snprintf( serial_header, sizeof( serial_header ), " %s: %s ", "S/N", c->device_serial_no ); + pdf_add_text_wrap( pdf, NULL, serial_header, 14, 0, 735, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_set_font( pdf, "Helvetica" ); + + pdf_add_text_wrap( pdf, NULL, "Disk Erasure Report", 24, 0, 695, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + snprintf( barcode, sizeof( barcode ), "%s:%s", c->device_model, c->device_serial_no ); + pdf_add_text_wrap( pdf, NULL, page_title, 14, 0, 670, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); + pdf_add_barcode( pdf, NULL, PDF_BARCODE_128A, 100, 790, 400, 25, barcode, PDF_BLACK ); + + /********************************************************** + * Display the appropriate status icon, top right on page on + * most recently added page. + */ + switch( status_icon ) + { + case STATUS_ICON_GREEN_TICK: + + /* Display the green tick icon in the header */ + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_te_jpg, 54896 ); + break; + + case STATUS_ICON_YELLOW_EXCLAMATION: + + /* Display the yellow exclamation icon in the header */ + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_nwipe_exclamation_jpg, 65791 ); + break; + + case STATUS_ICON_RED_CROSS: + + // Display the red cross in the header + pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_redcross_jpg, 60331 ); + break; + + default: + + break; + } +} diff --git a/src/create_pdf.h b/src/create_pdf.h new file mode 100644 index 0000000..0208657 --- /dev/null +++ b/src/create_pdf.h @@ -0,0 +1,52 @@ +/*. + * create_pdf.h: The header file for the pdf creation routines + * + * Copyright https://github.com/PartialVolume/shredos.x86_64 + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef CREATE_PDF_H_ +#define CREATE_PDF_H_ + +#define MAX_PDF_FOOTER_TEXT_LENGTH 100 + +#define STATUS_ICON_GREEN_TICK 1 +#define STATUS_ICON_YELLOW_EXCLAMATION 2 +#define STATUS_ICON_RED_CROSS 3 + +/* Additional colors that supplement the standard colors in pdfgen.h + */ +/*! Utility macro to provide gray */ +#define PDF_DARK_GREEN PDF_RGB( 0, 0x64, 0 ) + +/*! Utility macro to provide gray */ +#define PDF_GRAY PDF_RGB( 0x5A, 0x5A, 0x5A ) + +/*! Utility macro to provide gray */ +#define PDF_YELLOW PDF_RGB( 0xFF, 0xFF, 0x5A ) + +/** + * Create the disk erase report in PDF format + * @param pointer to a drive context + * @return returns 0 on success < 1 on error + */ +int create_pdf( nwipe_context_t* ptr ); + +int nwipe_get_smart_data( nwipe_context_t* ); + +void create_header_and_footer( nwipe_context_t*, char* ); + +#endif /* CREATE_PDF_H_ */ diff --git a/src/customers.c b/src/customers.c new file mode 100644 index 0000000..9097d24 --- /dev/null +++ b/src/customers.c @@ -0,0 +1,713 @@ +/* + * **************************************************************************** + * customers.c: Functions related to customer processing for the PDF erasure * + * certificate. * + * **************************************************************************** + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdio.h> +#include "nwipe.h" +#include "context.h" +#include "gui.h" +#include "logging.h" +#include "conf.h" +#include "customers.h" +#include <sys/stat.h> + +void customer_processes( int mode ) +{ + /* This function reads the customers.csv file, counts the number of lines, + * converts line feeds to NULL and constructs a array of pointers that point + * to the variable length strings. + * + * Depending on the value of mode the pointer array is passed to either + * the select_customers() or delete_customer() functions. + */ + + int idx; + int idx2; + FILE* fptr; + + struct stat st; + intmax_t size = 0; + int lines; + int list_idx; + int current_list_size; + + size_t result_size; + + extern char nwipe_customers_file[]; + + /* Determine size of customers.csv file */ + stat( nwipe_customers_file, &st ); + size = st.st_size; + current_list_size = 0; + + nwipe_customers_buffer_t raw_buffer = (nwipe_customers_buffer_t) calloc( 1, size + 1 ); + + /* Allocate storage for the contents of customers.csv */ + nwipe_customers_buffer_t buffer = (nwipe_customers_buffer_t) calloc( 1, size + 1 ); + + /* Allocate storage for the processed version of customers.csv, + * i.e we convert the csv format to strings without the quotes + * and semi colon delimiters + */ + nwipe_customers_pointers_t list = (nwipe_customers_pointers_t) calloc( 1, sizeof( char* ) ); + current_list_size += sizeof( char* ); + + /* Open customers.csv */ + if( ( fptr = fopen( nwipe_customers_file, "rb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); + free( buffer ); + free( *list ); + return; + } + + /* Read the customers.csv file and populate the list array with the data */ + result_size = fread( raw_buffer, size, 1, fptr ); + + fclose( fptr ); + + /* Validate csv contents. With the exception of line feeds, + * remove non printable characters and move to a secondary buffer. + */ + idx = 0; + idx2 = 0; + while( idx < size ) + { + if( ( raw_buffer[idx] > 0x1F && raw_buffer[idx] < 0x7F ) || raw_buffer[idx] == 0x0A ) + { + /* copy printable characters and line feeds */ + buffer[idx2++] = raw_buffer[idx]; + } + idx++; + } + + /* Construct a array of pointers that point to each line of the csv file + */ + idx = 0; + lines = 0; + list_idx = 0; + + while( idx < size ) + { + if( buffer[idx] == 0x0A ) + { + buffer[idx] = 0; + + /* increment the line counter, but don't count + * the first line as that is the csv header line. + */ + if( idx != 0 ) + { + lines++; + + /* Change the line feed to a NULL, string terminator */ + buffer[idx] = 0; + + /* Save the pointer to the first data line of the csv. */ + list[list_idx++] = &buffer[idx + 1]; + + current_list_size += sizeof( char* ); + + /* Expand allocated memory by the size of one pointer */ + if( ( list = realloc( list, current_list_size ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to realloc customer list array, out of memory?" ); + break; + } + current_list_size += sizeof( char* ); + } + } + else + { + /* Replace colons with commas */ + if( buffer[idx] == ';' ) + { + buffer[idx] = ','; + } + } + idx++; + } + + /* Sync lines variable to actual number of lines */ + if( lines > 0 ) + lines--; + + if( idx == size ) + { + /* makesure the very last entry is NULL terminated */ + buffer[idx] = 0; + } + + /* Select the requested mode, customer or delete customer. + */ + switch( mode ) + { + case SELECT_CUSTOMER: + select_customers( lines, list ); + break; + + case DELETE_CUSTOMER: + delete_customer( lines, list ); + break; + } + + free( raw_buffer ); + free( buffer ); +} + +void select_customers( int count, char** customer_list_array ) +{ + int selected_entry = 0; + char window_title[] = " Select Customer For PDF Report "; + + /* Display the customer selection window */ + nwipe_gui_list( count, window_title, customer_list_array, &selected_entry ); + + /* Save the selected customer details to nwipe's config file /etc/nwipe/nwipe.conf + * If selected entry equals 0, then the customer did not select an entry so skip save. + */ + if( selected_entry != 0 ) + { + save_selected_customer( &customer_list_array[selected_entry - 1] ); + } +} + +void delete_customer( int count, char** customer_list_array ) +{ + char window_title[] = " Delete Customer "; + int selected_entry = 0; + + nwipe_gui_list( count, window_title, customer_list_array, &selected_entry ); + + if( selected_entry != 0 ) + { + delete_customer_csv_entry( &selected_entry ); + } +} + +void write_customer_csv_entry( char* customer_name, + char* customer_address, + char* customer_contact_name, + char* customer_contact_phone ) +{ + /** + * Write the attached strings in csv format to the first + * line after the header (line 2 of file) + */ + + FILE* fptr = 0; + FILE* fptr2 = 0; + + size_t result_size; + + /* General index variables */ + int idx1, idx2, idx3; + + /* Length of the new customer line */ + int csv_line_length; + + /* Size of the new buffer that holds old contents plus new entry */ + int new_customers_buffer_size; + + struct stat st; + + extern char nwipe_customers_file[]; + extern char nwipe_customers_file_backup[]; + extern char nwipe_customers_file_backup_tmp[]; + + intmax_t existing_file_size = 0; + + /* pointer to the new customer entry in csv format. */ + char* csv_buffer = 0; + + /* pointer to the buffer containing the existing customer file */ + char* customers_buffer = 0; + + /* pointer to the buffer containing the existing customer file plus the new entry */ + char* new_customers_buffer = 0; + + size_t new_customers_buffer_length; + + /* Determine length of all four strings and malloc sufficient storage + 12 = 8 quotes + three colons + null */ + csv_line_length = strlen( customer_name ) + strlen( customer_address ) + strlen( customer_contact_name ) + + strlen( customer_contact_phone ) + 12; + if( !( csv_buffer = calloc( 1, csv_line_length == 0 ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:nwipe_gui_add_customer:csv_buffer, calloc returned NULL " ); + } + else + { + /* Determine current size of the csv file containing the customers */ + stat( nwipe_customers_file, &st ); + existing_file_size = st.st_size; + + /* calloc sufficient storage to hold the existing customers file */ + if( !( customers_buffer = calloc( 1, existing_file_size + 1 ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:nwipe_gui_add_customer:customers_buffer, calloc returned NULL " ); + } + else + { + /* create a third buffer which is the combined size of the previous two, i.e existing file size, plus the + * new customer entry + 1 (NULL) */ + new_customers_buffer_size = existing_file_size + csv_line_length + 1; + + if( !( new_customers_buffer = calloc( 1, new_customers_buffer_size ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:nwipe_gui_add_customer:customers_buffer, calloc returned NULL " ); + } + else + { + /* Read the whole of customers.csv file into customers_buffer */ + if( ( fptr = fopen( nwipe_customers_file, "rb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); + } + else + { + /* Read the customers.csv file and populate the list array with the data */ + if( ( result_size = fread( customers_buffer, existing_file_size, 1, fptr ) ) != 1 ) + { + nwipe_log( + NWIPE_LOG_ERROR, + "func:nwipe_gui_add_customer:Error reading customers file, # bytes read not as expected " + "%i bytes", + result_size ); + } + else + { + /* -------------------------------------------------------------------- + * Read the first line which is the csv header from the existing customer + * buffer & write to the new buffer. + */ + + idx1 = 0; // Index for the current csv buffer + idx2 = 0; // Index for the new csv buffer + idx3 = 0; // Index for new customer fields + + while( idx1 < existing_file_size && idx2 < new_customers_buffer_size ) + { + if( customers_buffer[idx1] != LINEFEED ) + { + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + else + { + new_customers_buffer[idx2++] = LINEFEED; + break; + } + } + + /* -------------------------------------------------------------------------- + * Copy the new customer name entry so it is immediately after the csv header + */ + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size && customer_name[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_name[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer address entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size && customer_address[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_address[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer contact name entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size + && customer_contact_name[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_contact_name[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer contact phone entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size + && customer_contact_phone[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_contact_phone[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert a line feed to finish the new entry */ + new_customers_buffer[idx2++] = LINEFEED; + + /* skip any LINEFEEDS in the existing customer entry as we just inserted one */ + while( customers_buffer[idx1] != 0 && customers_buffer[idx1] == LINEFEED ) + { + idx1++; + } + + /* ------------------------------------------------------------------------------- + * Now copy the existing customer entries, if any, immediately after the new entry + */ + + while( idx1 < existing_file_size && idx2 < new_customers_buffer_size ) + { + /* Removes any nulls when copying and pasting, which would break this process? */ + if( customers_buffer[idx1] == 0 ) + { + while( idx1 < existing_file_size && customers_buffer[idx1] == 0 ) + { + idx1++; + } + } + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + + /* Rename the customers.csv file to customers.csv.backup */ + if( rename( nwipe_customers_file, nwipe_customers_file_backup_tmp ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + else + { + /* Create/open the customers.csv file */ + if( ( fptr2 = fopen( nwipe_customers_file, "wb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); + } + else + { + /* write the new customers.csv file */ + new_customers_buffer_length = strlen( new_customers_buffer ); + + if( ( result_size = fwrite( + new_customers_buffer, sizeof( char ), new_customers_buffer_length, fptr2 ) ) + != new_customers_buffer_length ) + { + nwipe_log( + NWIPE_LOG_ERROR, + "func:write_customer_csv_entry:fwrite: Error result_size = %i not as expected", + result_size ); + } + else + { + /* Remove the customer.csv.backup file if it exists */ + if( remove( nwipe_customers_file_backup ) != 0 ) + { + nwipe_log( + NWIPE_LOG_ERROR, "Unable to remove %s", nwipe_customers_file_backup_tmp ); + } + else + { + /* Rename the customers.csv.backup.tmp file to customers.csv.backup */ + if( rename( nwipe_customers_file_backup_tmp, nwipe_customers_file_backup ) + != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + nwipe_log( NWIPE_LOG_INFO, + "Succesfully write new customer entry to %s", + nwipe_customers_file ); + } + } + fclose( fptr2 ); + } + } + fclose( fptr ); + } + } + free( new_customers_buffer ); + } + free( customers_buffer ); + } + free( csv_buffer ); + } +} + +void delete_customer_csv_entry( int* selected_entry ) +{ + /** + * Deletes a line from the csv file. The line to be deleted is determined + * by the value of selected_entry + */ + FILE* fptr = 0; + FILE* fptr2 = 0; + + size_t result_size; + + struct stat st; + + extern char nwipe_customers_file[]; + extern char nwipe_customers_file_backup[]; + extern char nwipe_customers_file_backup_tmp[]; + + intmax_t existing_file_size = 0; + + int linecount; + + /* General index variables */ + int idx1, idx2, idx3; + + /* pointer to the buffer containing the existing customer file */ + char* customers_buffer = 0; + + /* pointer to the buffer containing the existing customer minus the deleted entry */ + char* new_customers_buffer = 0; + + int status_flag = 0; + + size_t new_customers_buffer_length; + + /* Determine current size of the csv file containing the customers */ + stat( nwipe_customers_file, &st ); + existing_file_size = st.st_size; + + /* calloc sufficient storage to hold the existing customers file */ + if( !( customers_buffer = calloc( 1, existing_file_size + 1 ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:nwipe_gui_delete_customer_csv_entry:customers_buffer, calloc returned NULL " ); + } + else + { + /* create a second buffer which is identical in size to the first, it will store the customer + * csv file minus the one selected entry + */ + + if( !( new_customers_buffer = calloc( 1, existing_file_size + 1 ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:nwipe_gui_delete_customer_csv_entry:customers_buffer, calloc returned NULL " ); + } + else + { + /* Read the whole of customers.csv file into customers_buffer */ + if( ( fptr = fopen( nwipe_customers_file, "rb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:nwipe_gui_delete_customer_csv_entry:Unable to open %s", + nwipe_customers_file ); + } + else + { + /* Read the customers.csv file and populate the list array with the data */ + if( ( result_size = fread( customers_buffer, existing_file_size, 1, fptr ) ) != 1 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:nwipe_gui_delete_customer_csv_entry:Error reading customers file, # elements read " + "not as expected " + "%i elements", + result_size ); + } + else + { + /* -------------------------------------------------------------------- + * Read the first line which is the csv header from the existing customer + * buffer & write to the new buffer. + */ + + idx1 = 0; // Index for the current csv buffer + idx2 = 0; // Index for the new csv buffer + + linecount = 1; // count the lines in the csv file starting at line 1 + + while( idx1 < existing_file_size && idx2 < existing_file_size ) + { + if( customers_buffer[idx1] != LINEFEED ) + { + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + else + { + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + break; + } + } + + /* ------------------------------------------------------------------------------- + * Now copy the existing customer entries, counting the lines as we go and when we + * get to the the line selected for deletion we skip over it and then carry on + * copying. + */ + + while( idx1 < existing_file_size && idx2 < existing_file_size ) + { + /* Don't copy nulls */ + if( customers_buffer[idx1] == 0 ) + { + idx1++; + continue; + } + + /* Is this the line to delete? */ + if( linecount == *selected_entry ) + { + /* skip all the characters in this line */ + while( idx1 < existing_file_size && customers_buffer[idx1] != LINEFEED ) + { + idx1++; + } + + /* skip the trailing linefeed if it exists, may not exist if last line */ + if( customers_buffer[idx1] == LINEFEED ) + { + idx1++; + } + linecount++; + nwipe_log( NWIPE_LOG_INFO, "Deleted customer entry from cache" ); + status_flag = 1; + } + else + { + /* Is the character a LINEFEED? */ + if( customers_buffer[idx1] == LINEFEED ) + { + linecount++; + } + + /* Copy a character */ + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + } + + /* Rename the customers.csv file to customers.csv.backup */ + if( rename( nwipe_customers_file, nwipe_customers_file_backup_tmp ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:delete_customer_csv_entry:Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + else + { + /* Create/open the customers.csv file */ + if( ( fptr2 = fopen( nwipe_customers_file, "wb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:delete_customer_csv_entry:Unable to open %s", + nwipe_customers_file ); + } + else + { + /* write the new customers.csv file */ + new_customers_buffer_length = strlen( new_customers_buffer ); + + if( ( result_size = fwrite( + new_customers_buffer, sizeof( char ), new_customers_buffer_length, fptr2 ) ) + != new_customers_buffer_length ) + { + nwipe_log( + NWIPE_LOG_ERROR, + "func:delete_customer_csv_entry:fwrite: Error result_size = %i not as expected", + result_size ); + } + else + { + /* Remove the customer.csv.backup file if it exists */ + if( remove( nwipe_customers_file_backup ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:delete_customer_csv_entry:Unable to remove %s", + nwipe_customers_file_backup_tmp ); + } + else + { + /* Rename the customers.csv.backup.tmp file to customers.csv.backup */ + if( rename( nwipe_customers_file_backup_tmp, nwipe_customers_file_backup ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "func:delete_customer_csv_entry:Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + if( status_flag == 1 ) + { + nwipe_log( + NWIPE_LOG_INFO, "Deleted customer entry in %s", nwipe_customers_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, + "Failed to delete customer entry in %s", + nwipe_customers_file ); + } + } + } + fclose( fptr2 ); + } + } + } + fclose( fptr ); + } + free( new_customers_buffer ); + } + free( customers_buffer ); + } +} diff --git a/src/customers.h b/src/customers.h new file mode 100644 index 0000000..353551b --- /dev/null +++ b/src/customers.h @@ -0,0 +1,42 @@ +/* + * **************************************************************************** + * customers.h: Functions related to customer processing for the PDF erasure * + * certificate. * + * **************************************************************************** + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef CUSTOMERS_H_INCLUDED +#define CUSTOMERS_H_INCLUDED + +void customer_processes( int ); +void select_customers( int, char** ); +void delete_customer(); +void add_customer(); +void write_customer_csv_entry( char*, char*, char*, char* ); +void delete_customer_csv_entry( int* ); + +typedef char* nwipe_customers_buffer_t; +typedef char** nwipe_customers_pointers_t; + +#define SELECT_CUSTOMER 1 +#define DELETE_CUSTOMER 2 + +#define LINEFEED 0x0A + +#endif // CUSTOMERS_H_INCLUDED diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..8475f30 --- /dev/null +++ b/src/device.c @@ -0,0 +1,917 @@ +/* + * device.c: Device routines for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> + +#include "nwipe.h" +#include "context.h" +#include "device.h" +#include "method.h" +#include "options.h" +#include "logging.h" +#include <sys/ioctl.h> +#include <linux/hdreg.h> // Drive specific defs +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include "hpa_dco.h" +#include "miscellaneous.h" + +#include <parted/parted.h> +#include <parted/debug.h> + +int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount ); +char* trim( char* str ); + +extern int terminate_signal; + +int nwipe_device_scan( nwipe_context_t*** c ) +{ + /** + * Scans the filesystem for storage device names. + * + * @parameter device_names A reference to a null array pointer. + * @modifies device_names Populates device_names with an array of nwipe_context_t + * @returns The number of strings in the device_names array. + * + */ + + PedDevice* dev = NULL; + ped_device_probe_all(); + + int dcount = 0; + + while( ( dev = ped_device_get_next( dev ) ) ) + { + /* to have some progress indication. can help if there are many/slow disks */ + fprintf( stderr, "." ); + + if( check_device( c, dev, dcount ) ) + dcount++; + + /* Don't bother scanning drives if the terminate signal is active ! as in the case of + * the readlink program missing which is required if the --nousb option has been specified */ + if( terminate_signal == 1 ) + { + break; + } + } + + /* Return the number of devices that were found. */ + return dcount; + +} /* nwipe_device_scan */ + +int nwipe_device_get( nwipe_context_t*** c, char** devnamelist, int ndevnames ) +{ + PedDevice* dev = NULL; + + int i; + int dcount = 0; + + for( i = 0; i < ndevnames; i++ ) + { + /* to have some progress indication. can help if there are many/slow disks */ + fprintf( stderr, "." ); + + dev = ped_device_get( devnamelist[i] ); + if( !dev ) + { + nwipe_log( NWIPE_LOG_WARNING, "Device %s not found", devnamelist[i] ); + continue; + } + + if( check_device( c, dev, dcount ) ) + dcount++; + + /* Don't bother scanning drives if the terminate signal is active ! as in the case of + * the readlink program missing which is required if the --nousb option has been specified */ + if( terminate_signal == 1 ) + { + break; + } + } + + /* Return the number of devices that were found. */ + return dcount; + +} /* nwipe_device_get */ + +int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount ) +{ + /* Populate this struct, then assign it to overall array of structs. */ + nwipe_context_t* next_device; + int fd; + int idx; + int r; + char tmp_serial[NWIPE_SERIALNUMBER_LENGTH + 1]; + nwipe_device_t bus; + int is_ssd; + int check_HPA; // a flag that indicates whether we check for a HPA on this device + + bus = 0; + + /* Check whether this drive is on the excluded drive list ? */ + idx = 0; + while( idx < MAX_NUMBER_EXCLUDED_DRIVES ) + { + if( !strcmp( dev->path, nwipe_options.exclude[idx++] ) ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Device %s excluded as per command line option -e", dev->path ); + return 0; + } + } + + /* Check whether the user has specified using the --nousb option + * that all USB devices should not be displayed or wiped whether + * in GUI, --nogui or --autonuke modes */ + + if( nwipe_options.nousb ) + { + /* retrieve bus and drive serial number, HOWEVER we are only interested in the bus at this time */ + r = nwipe_get_device_bus_type_and_serialno( dev->path, &bus, &is_ssd, tmp_serial ); + + /* See nwipe_get_device_bus_type_and_serialno() function for meaning of these codes */ + if( r == 0 || ( r >= 3 && r <= 6 ) ) + { + if( bus == NWIPE_DEVICE_USB ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Device %s ignored as per command line option --nousb", dev->path ); + return 0; + } + } + else + { + if( r == 2 ) + { + nwipe_log( + NWIPE_LOG_NOTICE, "--nousb requires the 'readlink' program, please install readlink", dev->path ); + terminate_signal = 1; + return 0; + } + } + } + + /* Try opening the device to see if it's valid. Close on completion. */ + if( !ped_device_open( dev ) ) + { + nwipe_log( NWIPE_LOG_FATAL, "Unable to open device" ); + return 0; + } + ped_device_close( dev ); + + /* New device, reallocate memory for additional struct pointer */ + *c = realloc( *c, ( dcount + 1 ) * sizeof( nwipe_context_t* ) ); + + next_device = malloc( sizeof( nwipe_context_t ) ); + + /* Check the allocation. */ + if( !next_device ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to create the array of enumeration contexts." ); + return 0; + } + + /* Zero the allocation. */ + memset( next_device, 0, sizeof( nwipe_context_t ) ); + + /* Get device information */ + next_device->device_model = dev->model; + remove_ATA_prefix( next_device->device_model ); + + /* Some USB adapters have drive model endian swapped, pattern match and fix */ + fix_endian_model_names( next_device->device_model ); + + /* full device name, i.e. /dev/sda */ + next_device->device_name = dev->path; + + /* remove /dev/ from device, right justify and prefix name so string length is eight characters */ + nwipe_strip_path( next_device->device_name_without_path, next_device->device_name ); + + /* To maintain column alignment in the gui we have to remove /dev/ from device names that + * exceed eight characters including the /dev/ path. + */ + if( strlen( next_device->device_name ) > MAX_LENGTH_OF_DEVICE_STRING ) + { + strcpy( next_device->gui_device_name, next_device->device_name_without_path ); + } + else + { + strcpy( next_device->gui_device_name, next_device->device_name ); + } + + next_device->device_size = dev->length * dev->sector_size; + next_device->device_sector_size = dev->sector_size; // logical sector size + next_device->device_block_size = dev->sector_size; // set as logical but could be a multiple of logical sector size + next_device->device_phys_sector_size = dev->phys_sector_size; // physical sector size + next_device->device_size_in_sectors = next_device->device_size / next_device->device_sector_size; + next_device->device_size_in_512byte_sectors = next_device->device_size / 512; + Determine_C_B_nomenclature( next_device->device_size, next_device->device_size_txt, NWIPE_DEVICE_SIZE_TXT_LENGTH ); + next_device->device_size_text = next_device->device_size_txt; + next_device->result = -2; + + /* Attempt to get serial number of device. + */ + next_device->device_serial_no[0] = 0; /* initialise the serial number */ + + if( ( fd = open( next_device->device_name = dev->path, O_RDONLY ) ) == ERR ) + { + nwipe_log( NWIPE_LOG_WARNING, "Unable to open device %s to obtain serial number", next_device->device_name ); + } + + /* + * We don't check the ioctl return status because there are plenty of situations where a serial number may not be + * returned by ioctl such as USB drives, logical volumes, encryted volumes, so the log file would have multiple + * benign ioctl errors reported which isn't necessarily a problem. + */ + ioctl( fd, HDIO_GET_IDENTITY, &next_device->identity ); + close( fd ); + + for( idx = 0; idx < NWIPE_SERIALNUMBER_LENGTH; idx++ ) + { + if( isascii( next_device->identity.serial_no[idx] ) && !iscntrl( next_device->identity.serial_no[idx] ) ) + { + next_device->device_serial_no[idx] = next_device->identity.serial_no[idx]; + } + else + { + break; + } + } + + // Terminate the string. + next_device->device_serial_no[idx] = 0; + + // Remove leading/trailing whitespace from serial number and left justify. + trim( (char*) next_device->device_serial_no ); + + /* if we couldn't obtain serial number by using the above method .. try this */ + r = nwipe_get_device_bus_type_and_serialno( + next_device->device_name, &next_device->device_type, &next_device->device_is_ssd, tmp_serial ); + + /* If serial number & bus retrieved (0) OR unsupported USB bus identified (5) */ + if( r == 0 || r == 5 ) + { + /* If the serial number hasn't already been populated */ + if( next_device->device_serial_no[0] == 0 ) + { + strncpy( next_device->device_serial_no, tmp_serial, NWIPE_SERIALNUMBER_LENGTH ); + } + } + + /* Does the user want to anonymize serial numbers ? */ + if( nwipe_options.quiet ) + { + if( next_device->device_serial_no[0] == 0 ) + { + strncpy( next_device->device_serial_no, "????????????????????", NWIPE_SERIALNUMBER_LENGTH + 1 ); + } + else + { + strncpy( next_device->device_serial_no, "XXXXXXXXXXXXXXXXXXXX", NWIPE_SERIALNUMBER_LENGTH + 1 ); + } + } + /* strncpy would have copied the null terminator BUT just to be sure, just in case somebody changes the length + * of those strings we should explicitly terminate the string */ + next_device->device_serial_no[NWIPE_SERIALNUMBER_LENGTH] = 0; + + /* Initialise the variables that toggle the [size][temp c] with [HPA status] + * Not currently used, but may be used in the future or for other purposes + */ + next_device->HPA_toggle_time = time( NULL ); + next_device->HPA_display_toggle_state = 0; + + /* Initialise the HPA variables for this device + */ + next_device->HPA_reported_set = 0; + next_device->HPA_reported_real = 0; + next_device->DCO_reported_real_max_sectors = 0; + next_device->HPA_status = HPA_NOT_APPLICABLE; + + /* All device strings should be 4 characters, prefix with space if under 4 characters + * We also set a switch for certain devices to check for the host protected area (HPA) + */ + check_HPA = 0; + + // WARNING TEMP LINE WARNING + // next_device->device_type = NWIPE_DEVICE_ATA; + + switch( next_device->device_type ) + { + case NWIPE_DEVICE_UNKNOWN: + strcpy( next_device->device_type_str, " UNK" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_IDE: + strcpy( next_device->device_type_str, " IDE" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_SCSI: + strcpy( next_device->device_type_str, " SCSI" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_COMPAQ: + strcpy( next_device->device_type_str, " CPQ" ); + break; + + case NWIPE_DEVICE_USB: + strcpy( next_device->device_type_str, " USB" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_IEEE1394: + strcpy( next_device->device_type_str, "1394" ); + break; + + case NWIPE_DEVICE_ATA: + strcpy( next_device->device_type_str, " ATA" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_NVME: + strcpy( next_device->device_type_str, "NVME" ); + break; + + case NWIPE_DEVICE_VIRT: + strcpy( next_device->device_type_str, "VIRT" ); + break; + + case NWIPE_DEVICE_SAS: + strcpy( next_device->device_type_str, " SAS" ); + check_HPA = 1; + break; + + case NWIPE_DEVICE_MMC: + strcpy( next_device->device_type_str, " MMC" ); + break; + } + if( next_device->device_is_ssd ) + { + strcpy( next_device->device_type_str + 4, "-SSD" ); + } + else + { + strcpy( next_device->device_type_str + 4, " " ); + } + + if( strlen( (const char*) next_device->device_serial_no ) ) + { + snprintf( next_device->device_label, + NWIPE_DEVICE_LABEL_LENGTH, + "%s %s [%s] %s/%s", + next_device->device_name, + next_device->device_type_str, + next_device->device_size_text, + next_device->device_model, + next_device->device_serial_no ); + } + else + { + snprintf( next_device->device_label, + NWIPE_DEVICE_LABEL_LENGTH, + "%s %s [%s] %s", + next_device->device_name, + next_device->device_type_str, + next_device->device_size_text, + next_device->device_model ); + } + + nwipe_log( NWIPE_LOG_NOTICE, + "Found %s, %s, %s, %s, S/N=%s", + next_device->device_name, + next_device->device_type_str, + next_device->device_model, + next_device->device_size_text, + next_device->device_serial_no ); + + nwipe_log( NWIPE_LOG_INFO, + "%s, sector(logical)/block(physical) sizes %i/%i", + next_device->device_name, + dev->sector_size, + dev->phys_sector_size ); + + /****************************** + * Check for hidden sector_size + */ + if( check_HPA == 1 ) + { + hpa_dco_status( next_device ); + } + + /* print an empty line to separate the drives in the log */ + nwipe_log( NWIPE_LOG_INFO, " " ); + + ( *c )[dcount] = next_device; + return 1; +} + +/* Remove leading/trailing whitespace from a string and left justify result */ +char* trim( char* str ) +{ + size_t len = 0; + char* frontp = str; + char* endp = NULL; + + if( str == NULL ) + { + return NULL; + } + if( str[0] == '\0' ) + { + return str; + } + len = strlen( str ); + endp = str + len; + + /* + * Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while( isspace( (unsigned char) *frontp ) ) + { + ++frontp; + } + if( endp != frontp ) + { + while( isspace( (unsigned char) *( --endp ) ) && endp != frontp ) + { + } + } + if( str + len - 1 != endp ) + *( endp + 1 ) = '\0'; + else if( frontp != str && endp == frontp ) + *str = '\0'; + /* + * Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if( frontp != str ) + { + while( *frontp ) + { + *endp++ = *frontp++; + } + *endp = '\0'; + } + return str; +} + +int nwipe_get_device_bus_type_and_serialno( char* device, nwipe_device_t* bus, int* is_ssd, char* serialnumber ) +{ + /* The caller provides a string that contains the device, i.e. /dev/sdc, also a pointer + * to an integer (bus type), another pointer to an integer (is_ssd), and finally a 21 byte + * character string which this function populates with the serial number (20 characters + null terminator). + * + * The function populates the bus integer and serial number strings for the given device. + * Results for bus would typically be ATA or USB see nwipe_device_t in context.h + * + * Return Values: + * 0 = Success + * 1 = popen failed to create stream for readlink + * 2 = readlink exit code not 0, see nwipe logs + * 3 = popen failed to create stream for smartctl + * 4 = smartctl command not found, install smartmontools + * 5 = smartctl detected unsupported USB to IDE/SATA adapter + * 6 = All other errors ! + * + */ + + FILE* fp; + + int r; // A result buffer. + int idx_src; + int idx_dest; + int device_len; + int set_return_value; + int exit_status; + int idx; + int idx2; + + char readlink_command[] = "readlink /sys/block/%s"; + char readlink_command2[] = "/usr/bin/readlink /sys/block/%s"; + char readlink_command3[] = "/sbin/readlink /sys/block/%s"; + char smartctl_command[] = "smartctl -i %s"; + char smartctl_command2[] = "/sbin/smartctl -i %s"; + char smartctl_command3[] = "/usr/bin/smartctl -i %s"; + char device_shortform[50]; + char result[512]; + char final_cmd_readlink[sizeof( readlink_command ) + sizeof( device_shortform )]; + char final_cmd_smartctl[sizeof( smartctl_command ) + 256]; + char* pResult; + char smartctl_labels_to_anonymize[][18] = { + "serial number:", "lu wwn device id:", "logical unit id:", "" /* Don't remove this empty string !, important */ + }; + + /* Initialise return value */ + set_return_value = 0; + + *bus = 0; + + /* Scan device name and if device is for instance /dev/sdx then convert to sdx + * If already sdx then just copy. */ + + idx_dest = 0; + device_shortform[idx_dest] = 0; + device_len = strlen( device ); + idx_src = device_len; + + while( idx_src >= 0 ) + { + if( device[idx_src] == '/' || idx_src == 0 ) + { + idx_src++; + + /* Now scan forwards copying the short form device i.e sdc */ + while( idx_src < device_len ) + { + device_shortform[idx_dest++] = device[idx_src++]; + } + break; + } + else + { + idx_src--; + } + } + device_shortform[idx_dest] = 0; + + final_cmd_readlink[0] = 0; + + /* Determine whether we can access readlink, required if the PATH environment is not setup ! (Debian sid 'su' as + * opposed to 'su -' */ + if( system( "which readlink > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/readlink > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/readlink > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install readlink !" ); + set_return_value = 2; + + /* Return immediately if --nousb specified. Readlink is a requirement for this option. */ + if( nwipe_options.nousb ) + { + return set_return_value; + } + } + else + { + sprintf( final_cmd_readlink, readlink_command3, device_shortform ); + } + } + else + { + sprintf( final_cmd_readlink, readlink_command2, device_shortform ); + } + } + else + { + sprintf( final_cmd_readlink, readlink_command, device_shortform ); + } + + if( final_cmd_readlink[0] != 0 ) + { + + fp = popen( final_cmd_readlink, "r" ); + + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, + "nwipe_get_device_bus_type_and_serialno: Failed to create stream to %s", + readlink_command ); + + set_return_value = 1; + } + + if( fp != NULL ) + { + /* Read the output a line at a time - output it. */ + if( fgets( result, sizeof( result ) - 1, fp ) != NULL ) + { + if( nwipe_options.verbose ) + { + strip_CR_LF( result ); + nwipe_log( NWIPE_LOG_DEBUG, "Readlink: %s", result ); + } + + /* Scan the readlink results for bus types, i.e. USB or ATA + * Example: readlink + * /sys/block/sdd../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/host6/target6:0:0/6:0:0:0/block/sdd + */ + + if( strstr( result, "/usb" ) != 0 ) + { + *bus = NWIPE_DEVICE_USB; + } + else + { + if( strstr( result, "/ata" ) != 0 ) + { + *bus = NWIPE_DEVICE_ATA; + } + else + { + if( strstr( result, "/nvme/" ) != 0 ) + { + *bus = NWIPE_DEVICE_NVME; + } + else + { + if( strstr( result, "/virtual/" ) != 0 ) + { + *bus = NWIPE_DEVICE_VIRT; + } + else + { + if( strstr( result, "/mmcblk" ) != 0 ) + { + *bus = NWIPE_DEVICE_MMC; + } + } + } + } + } + } + /* close */ + r = pclose( fp ); + + if( r > 0 ) + { + exit_status = WEXITSTATUS( r ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_WARNING, + "nwipe_get_device_bus_type_and_serialno(): readlink failed, \"%s\" exit status = %u", + final_cmd_readlink, + exit_status ); + } + + if( exit_status == 127 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install Readlink recommended !" ); + set_return_value = 2; + if( nwipe_options.nousb ) + { + return set_return_value; + } + } + } + } + } + + /* + * Retrieve smartmontools drive information if USB bridge supports it, so we can retrieve the serial number of the + * drive that's on the other side of the USB bridge.. */ + + final_cmd_smartctl[0] = 0; + + /* Determine whether we can access smartctl, required if the PATH environment is not setup ! (Debian sid 'su' as + * opposed to 'su -' */ + if( system( "which smartctl > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/smartctl > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/smartctl > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install smartmontools !" ); + } + else + { + sprintf( final_cmd_smartctl, smartctl_command3, device ); + } + } + else + { + sprintf( final_cmd_smartctl, smartctl_command2, device ); + } + } + else + { + sprintf( final_cmd_smartctl, smartctl_command, device ); + } + + if( final_cmd_smartctl[0] != 0 ) + { + fp = popen( final_cmd_smartctl, "r" ); + + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, + "nwipe_get_device_bus_type_and_serialno(): Failed to create stream to %s", + smartctl_command ); + + set_return_value = 3; + } + else + { + /* Read the output a line at a time - output it. */ + while( fgets( result, sizeof( result ) - 1, fp ) != NULL ) + { + /* Convert the label, i.e everything before the ':' to lower case, it's required to + * convert to lower case as smartctl seems to use inconsistent case when labeling + * for serial number, i.e mostly it produces labels "Serial Number:" but occasionally + * it produces a label "Serial number:" */ + + idx = 0; + while( result[idx] != 0 && result[idx] != ':' ) + { + /* If upper case alpha character, change to lower case */ + if( result[idx] >= 'A' && result[idx] <= 'Z' ) + { + result[idx] = tolower( result[idx] ); + } + + idx++; + } + + if( nwipe_options.verbose && result[0] != 0x0A ) + { + strip_CR_LF( result ); + + /* Remove serial number if -q option specified */ + if( nwipe_options.quiet ) + { + /* initialise index into string array */ + idx2 = 0; + + while( smartctl_labels_to_anonymize[idx2][0] != 0 ) + { + if( ( pResult = strstr( result, &smartctl_labels_to_anonymize[idx2][0] ) ) != 0 ) + { + /* set index to character after end of label string */ + idx = strlen( &smartctl_labels_to_anonymize[idx2][0] ); + + /* Ignore spaces, overwrite other characters */ + while( *( pResult + idx ) != 0x0A && *( pResult + idx ) != 0x0D + && *( pResult + idx ) != 0 && idx <= sizeof( result ) - 1 ) + { + if( *( pResult + idx ) == ' ' ) + { + idx++; + continue; + } + else + { + /* ignore if the serial number has been written over with '?' */ + if( *( pResult + idx ) != '?' ) + { + *( pResult + idx ) = 'X'; + } + idx++; + } + } + } + idx2++; + } + } + + nwipe_log( NWIPE_LOG_INFO, "smartctl: %s", result ); + } + + if( strstr( result, "serial number:" ) != 0 ) + { + /* strip any leading or trailing spaces and left justify, +15 is the length of "Serial Number:" */ + trim( &result[15] ); + + strncpy( serialnumber, &result[15], NWIPE_SERIALNUMBER_LENGTH ); + serialnumber[NWIPE_SERIALNUMBER_LENGTH] = 0; + } + + if( *bus == 0 ) + { + if( strstr( result, "transport protocol:" ) != 0 ) + { + /* strip any leading or trailing spaces and left justify, +4 is the length of "bus type:" */ + trim( &result[19] ); + for( idx = 19; result[idx]; idx++ ) + { + result[idx] = tolower( result[idx] ); + } + + if( strncmp( &result[19], "sas", 3 ) == 0 ) + { + *bus = NWIPE_DEVICE_SAS; + } + } + + if( strstr( result, "sata version is:" ) != 0 ) + { + + /* strip any leading or trailing spaces and left justify, +4 is the length of "bus type:" */ + trim( &result[16] ); + for( idx = 16; result[idx]; idx++ ) + { + result[idx] = tolower( result[idx] ); + } + + if( strncmp( &result[16], "sata", 4 ) == 0 ) + { + *bus = NWIPE_DEVICE_ATA; + } + } + } + if( strstr( result, "rotation rate:" ) != 0 ) + { + /* strip any leading or trailing spaces and left justify, +15 is the length of "Rotation Rate:" */ + trim( &result[15] ); + for( idx = 15; result[idx]; idx++ ) + { + result[idx] = tolower( result[idx] ); + } + + if( strncmp( &result[15], "solid state device", 19 ) == 0 ) + { + *is_ssd = 1; + } + } + } + + /* close */ + r = pclose( fp ); + + if( r > 0 ) + { + exit_status = WEXITSTATUS( r ); + if( nwipe_options.verbose && exit_status != 1 ) + { + nwipe_log( NWIPE_LOG_WARNING, + "nwipe_get_device_bus_type_and_serialno(): smartctl failed, \"%s\" exit status = %u", + final_cmd_smartctl, + exit_status ); + } + set_return_value = 6; + + if( exit_status == 127 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install Smartctl recommended !" ); + + set_return_value = 4; + } + + if( exit_status == 1 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Smartctl is unable to provide smart data for %s", device ); + + if( *bus == NWIPE_DEVICE_USB || *bus == NWIPE_DEVICE_MMC ) + { + strcpy( serialnumber, "(S/N: unknown)" ); + set_return_value = 5; + } + } + } + } + } + + return set_return_value; +} + +void remove_ATA_prefix( char* str ) +{ + /* Remove "ATA" prefix if present in the model no. string, left justifing string */ + + int idx_pre = 4; + int idx_post = 0; + + if( !strncmp( str, "ATA ", 4 ) ) + { + while( str[idx_pre] != 0 ) + { + str[idx_post++] = str[idx_pre++]; + } + + str[idx_post] = 0; + } +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..50c04c1 --- /dev/null +++ b/src/device.h @@ -0,0 +1,49 @@ +/* + * device.h: Device routines for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef DEVICE_H_ +#define DEVICE_H_ + +#define MAX_LENGTH_OF_DEVICE_STRING 8 + +void nwipe_device_identify( nwipe_context_t* c ); // Get hardware information about the device. +int nwipe_device_scan( nwipe_context_t*** c ); // Find devices that we can wipe. + +/** + * Gets information about devices + * + * @parameter device_names A reference to a null array pointer. + * @parameter devnamelist An array of string pointers to the device names + * @parameter ndevnames Number of elements in devnamelist + * @modifies device_names Populates device_names with an array of nwipe_contect_t + * @returns The number of strings in the device_names array. + * + */ +int nwipe_device_get( nwipe_context_t*** c, char** devnamelist, int ndevnames ); // Get info about devices to wipe. + +int nwipe_get_device_bus_type_and_serialno( char*, nwipe_device_t*, int*, char* ); +void strip_CR_LF( char* ); +void determine_disk_capacity_nomenclature( u64, char* ); +void remove_ATA_prefix( char* ); +char* trim( char* ); + +#endif /* DEVICE_H_ */ diff --git a/src/embedded_images/nwipe_exclamation.jpg b/src/embedded_images/nwipe_exclamation.jpg Binary files differnew file mode 100644 index 0000000..81354ba --- /dev/null +++ b/src/embedded_images/nwipe_exclamation.jpg diff --git a/src/embedded_images/nwipe_exclamation.jpg.c b/src/embedded_images/nwipe_exclamation.jpg.c new file mode 100644 index 0000000..909be88 --- /dev/null +++ b/src/embedded_images/nwipe_exclamation.jpg.c @@ -0,0 +1,4 @@ +/* Autogenerated by hxtools bin2c */ +#include "nwipe_exclamation.jpg.h" +/* Autogenerated from nwipe_exclamation.jpg */ +const unsigned char bin2c_nwipe_exclamation_jpg[63304] = {0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,02,0,'v',0,'v',0,0,0377,0341,'(',022,'E','x','i','f',0,0,'I','I','*',0,010,0,0,0,07,0,022,01,03,0,01,0,0,0,01,0,0,0,032,01,05,0,01,0,0,0,'b',0,0,0,033,01,05,0,01,0,0,0,'j',0,0,0,'(',01,03,0,01,0,0,0,03,0,0,0,'1',01,02,0,015,0,0,0,'r',0,0,0,'2',01,02,0,024,0,0,0,0200,0,0,0,'i',0207,04,0,01,0,0,0,0224,0,0,0,0246,0,0,0,'v',0,0,0,01,0,0,0,'v',0,0,0,01,0,0,0,'G','I','M','P',' ','2','.','1','0','.','3','0',0,0,'2','0','2','3',':','0','3',':','1','2',' ','1','6',':','1','5',':','4','7',0,01,0,01,0240,03,0,01,0,0,0,01,0,0,0,0,0,0,0,011,0,0376,0,04,0,01,0,0,0,01,0,0,0,0,01,04,0,01,0,0,0,0377,0,0,0,01,01,04,0,01,0,0,0,0,01,0,0,02,01,03,0,03,0,0,0,030,01,0,0,03,01,03,0,01,0,0,0,06,0,0,0,06,01,03,0,01,0,0,0,06,0,0,0,025,01,03,0,01,0,0,0,03,0,0,0,01,02,04,0,01,0,0,0,036,01,0,0,02,02,04,0,01,0,0,0,0354,'&',0,0,0,0,0,0,010,0,010,0,010,0,0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,0,0,01,0,01,0,0,0377,0333,0,'C',0,010,06,06,07,06,05,010,07,07,07,011,011,010,012,014,024,015,014,013,013,014,031,022,023,017,024,035,032,037,036,035,032,034,034,' ','$','.',047,' ','"',',','#',034,034,'(','7',')',',','0','1','4','4','4',037,047,'9','=','8','2','<','.','3','4','2',0377,0333,0,'C',01,011,011,011,014,013,014,030,015,015,030,'2','!',034,'!','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2',0377,0300,0,021,010,01,0,0,0377,03,01,'"',0,02,021,01,03,021,01,0377,0304,0,037,0,0,01,05,01,01,01,01,01,01,0,0,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,020,0,02,01,03,03,02,04,03,05,05,04,04,0,0,01,'}',01,02,03,0,04,021,05,022,'!','1','A',06,023,'Q','a',07,'"','q',024,'2',0201,0221,0241,010,'#','B',0261,0301,025,'R',0321,0360,'$','3','b','r',0202,011,012,026,027,030,031,032,'%','&',047,'(',')','*','4','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0341,0342,0343,0344,0345,0346,0347,0350,0351,0352,0361,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0304,0,037,01,0,03,01,01,01,01,01,01,01,01,01,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,021,0,02,01,02,04,04,03,04,07,05,04,04,0,01,02,'w',0,01,02,03,021,04,05,'!','1',06,022,'A','Q',07,'a','q',023,'"','2',0201,010,024,'B',0221,0241,0261,0301,011,'#','3','R',0360,025,'b','r',0321,012,026,'$','4',0341,'%',0361,027,030,031,032,'&',047,'(',')','*','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0202,0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0342,0343,0344,0345,0346,0347,0350,0351,0352,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0332,0,014,03,01,0,02,021,03,021,0,'?',0,0367,0372,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0250,'.',0357,'m',0254,' ','i',0356,0347,0216,030,0227,0222,0316,0330,024,'l','4',0234,0235,0221,'=','5',0335,'#','R',0316,0312,0252,':',0226,'8',025,0345,0276,'%',0370,0307,'k','j',0315,'o',0241,0301,0366,0227,034,031,0344,0341,07,0320,'w',0257,'/',0326,'|',']',0255,0353,0256,0337,'m',0276,0221,0243,047,'>','R',0235,0252,'?',01,0134,0225,'1','p',0216,0213,'S',0336,0301,0360,0356,'&',0272,'R',0251,0356,'/','=',0376,0357,0363,'=',0353,'V',0370,0213,0341,0235,'!',0231,'%',0324,022,'i','W',0370,' ',033,0317,0351,0305,'q',0372,0207,0306,0333,'u','%','l','4',0307,0177,'F',0225,0261,'^','3','E','r','K',031,'Q',0355,0241,0364,'4','8','w',07,'O',0343,'N','O',0315,0377,0,0221,0350,'7',0177,030,'|','I','?',0372,0205,0266,0267,037,0354,0246,0343,0372,0326,'<',0377,0,021,0274,'Y','8','`','u','y','T',023,0237,0221,'U','q',0372,'W','-','E','b',0353,'T','{',0266,'z','P',0313,0260,0220,0370,'i',0307,0356,'G','C',0377,0,011,0327,0212,'?',0350,'7','w',0377,0,'}',0323,0243,0361,0357,0212,'b',0220,'8',0326,0356,0211,035,0230,0202,'?',',','W','9','E','/','i','.',0346,0277,'U',0241,0374,0213,0356,'G','i','k',0361,'S',0305,'v',0307,0346,0276,'I',0206,'s',0211,'b',07,0371,'b',0267,0354,'~','5',0352,'1',0220,'/','t',0350,'%',035,0314,'l','T',0376,'U',0345,0224,'U','*',0365,026,0314,0346,0251,0225,'`',0252,'|','T',0327,0311,'[',0362,'=',0367,'M',0370,0303,0341,0373,0255,0253,'v',0263,0332,'1',0352,'Y','w',017,0322,0273,'M','7','[',0323,'5','x',0204,0266,027,0320,0134,')',0376,0343,0202,0177,'*',0371,':',0246,0266,0273,0270,0263,0231,'f',0266,0236,'H','d','S',0220,0310,0304,032,0350,0206,'6','k',0342,'W','<',0254,'G',014,0341,0346,0257,'F','N','/',0357,'G',0327,'T','W',0200,'h','?',026,0365,0275,'0',0244,'w',0341,'o',0240,035,'w','p',0370,0372,0327,0255,0370,'w',0307,032,047,0211,'#','_',0262,0334,0210,0347,0357,04,0277,'+',03,0375,'k',0262,0236,'"',025,'4','[',0237,'7',0215,0311,0361,'X','O','z','J',0361,0356,0216,0222,0212,'(',0255,0317,'(','(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0246,0311,'"','E',033,'I','#',05,'E',031,',','N',0,025,0343,0276,'<',0370,0244,0322,'4',0272,'f',0201,'.',020,'|',0262,']','/',0177,'e',0377,0,032,0316,0255,'X',0323,'W',0221,0333,0201,0300,'V',0306,'T',0344,0246,0275,'_','D','v',0372,0367,0216,0354,'4',0313,0237,0354,0373,'&','[',0255,'@',0377,0,02,0237,0226,'?','v','5',0311,'M',0247,0336,0370,0246,'F','{',0334,0334,0200,'y',0363,016,021,'}',0200,0351,'^',0177,0340,0362,'d',0324,0356,'$','r','Y',0312,'d',0261,'9','$',0223,'^',0333,0244,0306,0261,0351,'V',0301,'F','2',0201,0217,0324,0327,0205,0233,'f',0262,0302,'a','U','e',024,0333,'v','W',0331,035,0270,0354,':',0301,'W','T','(',0266,0254,0223,'o',0253,0377,0,'$','r',037,0360,0257,'`',0377,0,0237,'[','O',0326,0250,'j','~',010,0266,0266,0200,0371,0266,'Q',0252,036,'<',0310,0273,032,0364,0272,0212,0346,'5',0232,0326,'X',0334,'e','Y','H','5',0363,'X','n',047,0256,0352,0305,'U',0204,0134,'[',0326,0312,0314,0347,0372,0306,'!','j',0252,'J',0376,0254,0371,0342,0377,0,'D',0272,0265,0324,0276,0311,014,'R','N','_',0230,0366,')','%',0207,0320,'W','E',0244,0374,'+',0361,'.',0244,025,0345,0267,'[','8',0317,'y',0217,'?',0225,'z',0327,0201,'c',0214,0333,0335,'H','Q','K',0207,0,'6','9',0306,'=','k',0260,0257,0271,'X','(','^',0355,0350,'z','r',0342,'l','G',0263,'Q',0214,'W','7','W',0377,0,0,0362,'+','/',0202,'1',0200,015,0356,0252,0304,0367,021,'&','?',0235,'m','A',0360,'s',0303,'q',0217,0336,0265,0334,0247,035,0344,0307,0362,0257,'C',0242,0266,'X','j','K',0241,0347,'T',0316,0261,0323,0336,0243,'^',0232,034,'R','|',')',0360,0222,' ','S','a','#',021,0334,0314,0331,'?',0255,'E','7',0302,'?',012,'J',0304,0255,0274,0361,0361,0321,'f','l',017,0316,0273,0252,'*',0275,0205,'?',0345,'F','K','4',0306,0247,0177,'k','/',0275,0236,'c','u',0360,'W','H',0220,0177,0243,'_',0334,0304,0177,0332,0303,'W','9',0250,0374,026,0325,'`','V','k',033,0330,'n','1',0321,0134,'m','&',0275,0306,0212,0211,'a','i','>',0207,'M',',',0373,035,'M',0374,'w',0365,'G',0312,0372,0277,0205,0265,0275,015,0210,0277,0323,0346,0215,'G',0374,0264,013,0225,'?',0210,0254,'z',0372,0371,0343,'I','P',0244,0212,0254,0247,0250,'a',0220,'k',0220,0327,0276,032,0370,0177,'[','V','e',0267,026,0223,0221,0304,0220,014,'s',0356,';',0327,'4',0360,'M','|',014,0366,0360,0274,'O',011,'Y','b','!','o','5',0376,'G',0316,024,0370,0245,0222,031,026,'H',0235,0221,0324,0344,'2',0234,021,']',0207,0211,'>',032,'k',0232,03,'<',0261,0305,0366,0313,'A',0317,0233,020,0344,017,'q',0134,'i',04,022,010,0301,035,'A',0256,')','B','P','v',0222,'>',0226,0216,'"',0226,'"',034,0324,0244,0232,'=','7',0301,0337,026,'.',0364,0342,0226,'Z',0341,'k',0233,'n',0213,'?',0361,0247,0327,0324,'W',0263,0351,0272,0235,0226,0255,'f',0227,'V','7',011,'<','-',0321,0220,0347,037,'Z',0371,'*',0267,'|','1',0342,0275,'G',0302,0327,0302,'{','9',011,0211,0217,0357,'a',047,0345,'q',0376,'>',0365,0325,'G',027,'(',0351,'-','Q',0341,0346,'y',05,'*',0367,0251,'C',0335,0227,'n',0217,0374,0217,0250,0350,0254,017,013,'x',0267,'O',0361,'V',0236,0263,0332,0270,'I',0200,0375,0354,04,0374,0310,'k','~',0275,'8',0311,'I',']',037,017,'V',0224,0350,0315,0323,0250,0254,0320,'Q','E','s',0332,0337,0212,'m',0364,0274,0305,036,'$',0230,'u',0347,0205,0246,'f','t','4','d','z',0327,0217,0352,'~',':',0270,0221,0310,'7','L','?',0331,0216,0261,0337,0306,0267,0231,0371,'e',0237,0361,'z',0302,'x',0252,'0','v',0224,0214,0335,'X','.',0247,0274,'d','z',0321,'^',014,0276,'5',0276,0335,0363,'K','6','=',0234,0327,0240,0370,'#','T',0272,0275,0225,0326,'G','w',0214,0246,0357,0234,0347,06,0235,'*',0364,0352,0374,016,0343,0214,0343,'-',0216,0342,0212,'(',0255,0213,012,'k',0272,0305,033,';',0260,'U','Q',0222,'O','a','N',0257,036,0370,0245,0343,0306,0336,0372,06,0227,')',0134,'q','s','*',0237,0374,'t','V','u','j',0252,'q',0346,'g','n',03,05,'S',031,'Y','R',0207,0315,0366,'F','g',0304,'_',0210,0257,0253,'K','&',0223,0244,0310,'V',0311,'N',0331,'e',035,'e','>',0203,0332,0274,0316,0212,'U','F','w',010,0212,'Y',0211,0300,0,'d',0232,0361,0252,'T',0225,'I','s','H',0375,'#',013,0205,0245,0205,0244,0251,0323,'V','K',0361,0363,':','O',06,0177,0307,0365,0307,0375,'s',037,0316,0275,0307,'L',0377,0,0220,'e',0257,0375,'r','_',0345,'^','u',0241,0370,036,0357,'C',0320,0177,0265,0357,0330,0307,'=',0301,012,0260,'c',0356,0257,0277,0275,'z','&',0234,'q',0244,0333,037,'H',0227,0371,'W',0215,0304,0321,'q',0300,0323,'O',0371,0277,'F','|','F','o','Z',0235,'l','t',0245,'M',0335,'Y','/',0270,0267,'M',0223,0375,'S',0377,0,0272,'k',0316,07,0210,0276,' ',0334,0331,'M',0250,0330,0351,0232,'D',0266,0,0273,'F',0346,'r',031,0221,'I',0301,0307,0270,025,0253,0340,0377,0,026,0352,032,0343,0334,'Y','j',0326,'p','A','r','-','c',0273,0206,'K','y','7',0307,'4','2',03,0265,0201,0374,010,0374,'+',0346,026,'[','V',0237,0357,'.',0232,0213,'W',0263,'M',0255,'{',036,'o','2',':',0177,02,0177,0307,0245,0347,0375,'t',037,0312,0272,0332,0344,0274,011,0377,0,036,0227,0237,0365,0320,0177,'*',0353,'k',0365,0323,0214,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'B',03,02,010,04,036,0306,0270,037,030,'|','1',0323,0265,0340,0367,'v',01,'l',0357,0272,0222,0243,0344,0223,0352,'?',0255,'w',0364,'T','N',0234,'f',0255,'$','t','a',0261,'U',0260,0323,0347,0245,'+','3',0344,0375,'c','E',0277,0320,0257,0232,0323,'P',0201,0242,0220,'t',047,0243,017,'P','{',0326,'}','}','M',0342,'O',013,0351,0336,047,0260,'6',0327,0260,0202,0340,037,'.','P','>','d','>',0240,0327,0316,0376,'*',0360,0245,0367,0205,'u','6',0266,0271,'R',0320,0267,'1','L',07,0312,0343,0374,'k',0313,0257,0207,'t',0365,'[',037,'{',0225,'g',024,0361,0253,0222,'Z','O',0267,0177,'B',0216,0215,0255,'^',0350,':',0214,'w',0326,'3',030,0345,'C',0310,0354,0303,0320,0327,0321,0276,020,0361,'}',0227,0212,0364,0321,'4',',',022,0345,0,0363,0241,047,0225,'?',0341,'_','1','W','W',0340,'w',0276,0260,0324,0316,0241,'m','3','B',0210,'0',0336,0216,'=',015,'<','-','Y','F','|',0253,'f','g',0236,0340,0250,'V',0303,0272,0323,'v',0224,'v',0177,0241,0355,0376,'*',0361,034,'z',']',0253,0303,023,0201,'1',034,0237,0356,0212,0361,'m','O','W',0232,0372,'f',0303,0235,0204,0372,0365,0251,0265,0355,'f','M','F',0351,0362,0345,0201,'?','1',0365,'5',0215,'Y','c',0261,0216,'O',0331,0323,'z',037,0231,'V',0253,'w','d',024,'Q','V',',',0355,036,0362,'q',032,0216,';',0237,'J',0363,'a',07,'9','(',0307,'s',04,0256,0354,0213,'Z','F',0232,0367,0327,'+',0362,0222,0200,0376,'f',0275,0313,0303,032,'7',0366,'V',0236,013,0214,'K',' ',0311,0366,036,0225,0211,0340,0277,014,0245,0274,'I','w','2','`',017,0270,0244,'u',0367,0256,0347,0265,'}','&',027,016,0250,'B',0335,'N',0372,'t',0371,020,'Q','E','E','s','q',035,0245,0264,0267,023,'0','X',0343,'R',0314,'O','`','+',0244,0325,'&',0335,0221,0311,0374,'D',0361,'h',0360,0316,0202,0353,03,017,0267,0134,015,0221,017,0356,0372,0265,'|',0345,'$',0217,',',0215,'$',0214,'Y',0330,0345,0230,0365,'&',0266,0374,']',0342,031,0274,'K',0342,013,0213,0351,030,0371,'[',0266,0302,0231,0341,'P','t',0254,'*',0361,0261,025,'}',0244,0374,0217,0322,'r',0214,0275,'`',0350,'$',0376,047,0253,0377,0,'/',0220,'W',0262,0374,'0',0360,0,0204,'&',0273,0252,0304,013,0221,0233,'x',0134,'}',0337,0366,0215,'s',037,014,0274,032,'<','C',0251,0233,0353,0330,0311,0260,0266,'a',0362,0221,0304,0215,0351,0364,0257,0240,'U','B',0250,'U',0,0,'0',0,0355,'[',0341,'(','_',0337,0221,0344,0347,0371,0253,0247,0376,0313,'E',0353,0325,0376,0207,';',0343,'O',0371,01,0217,0372,0352,0265,'_','N',0,0351,'V',0300,0364,'1','/',0362,0253,036,'5',0377,0,0220,030,0377,0,0256,0253,'U',0264,0361,0235,'"',0334,0177,0323,021,0374,0253,0304,0342,0377,0,0367,'Z',0177,0342,0375,031,0362,'4','w','<',0223,'P',0323,0355,'t',0333,0333,0235,'2',0317,0342,'l',032,'v',0226,0316,0333,0354,0134,'#','4','`',0234,0262,0202,'O',03,0223,0217,'J',0364,035,03,0303,0372,']',0230,0207,'T',0323,'.',0232,'k','s',0246,0305,'g',06,010,'*','b','M',0305,'X',036,0344,0356,'5',0346,':','5',0347,0203,0264,'{','{',0213,'-','S',0302,0227,027,0367,'I','u','6','n','e',0260,'2',0231,027,'y',0333,0311,036,0230,037,0205,'{',016,0215,'5',0244,0376,035,0264,0226,0306,0330,0332,0332,'<',0,0305,01,'M',0236,'Z',0343,0201,0267,0267,0322,0274,',',0306,'U','i',0362,0307,0336,0265,0355,'v',0242,0224,0274,0364,0325,0277,']','K',0215,0211,0274,011,0377,0,036,0227,0237,0365,0320,0177,'*',0353,'k',0222,0360,047,0374,'z','^',0177,0327,'A',0374,0253,0255,0257,0322,0216,'`',0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0254,0275,0177,'A',0263,0361,016,0225,'-',0215,0334,'`',0206,07,'k','c',0224,'=',0210,0255,'J',0216,'i',0222,010,'Z','Y',030,'*','(',0311,'&',0223,'I',0253,'2',0351,0324,0225,'9',')',0301,0331,0243,0346,'{',0357,06,'j',':','g',0210,037,'L',0271,'O',0225,016,'D',0240,'|',0256,0276,0242,0264,0357,0256,'#',0261,0266,'[',033,0134,0,07,0314,'E','u',036,'/',0327,0332,0366,0361,0232,'!',0271,0260,'V','0',07,' ','W',0,0345,0231,0311,'|',0356,047,0234,0327,0215,0212,0251,034,':','t',0351,0275,'_',0340,0216,0214,0333,':',0255,0214,'Q',0247,'-','-',0275,0273,0367,033,'E',024,0240,022,'@',03,'$',0327,0224,'x',03,0241,0211,0347,0220,'F',0203,'$',0327,0246,'x','/',0302,0302,'g','Y','$','_',0335,047,',',0177,0274,'}','+',033,0302,'~',033,0222,0356,0345,06,0337,0231,0271,'c',0375,0321,'^',0311,'e','g',025,0215,0252,'A',012,0200,0252,'1',0365,0257,0177,03,0205,0366,'Q',0347,0226,0354,0355,0243,'O',0225,'s','=',0311,0221,026,'4',010,0240,05,03,0,012,'u',024,0207,0201,'^',0201,0270,0265,0346,0277,027,0274,'K',0375,0235,0243,0307,0244,'@',0370,0236,0360,022,0370,0376,030,0307,0370,0327,0244,0261,012,0245,0217,'@','2','k',0346,'O',035,0353,047,'[',0361,'u',0355,0310,'b','c','F',0362,0243,0347,'<','/',0371,'5',0313,0213,0251,0311,013,'.',0247,0273,0303,0370,'E','_',025,0317,'-',0243,0257,0317,0241,0315,0325,0315,'/','N',0237,'W',0324,0355,0354,'-',0206,'e',0231,0302,0217,'o','z',0247,'^',0267,0360,'k',0303,0236,'d',0327,032,0364,0353,0362,0247,0356,0240,04,'w',0356,0177,0245,'y',0264,0251,0373,'I',0250,0237,'k',0217,0305,0254,'&',036,'U','_','M',0275,'z',036,0245,0240,'h',0326,0372,06,0215,'o',0247,0333,' ',013,022,0215,0304,0177,023,'w','&',0264,0350,0242,0275,0264,0222,'V','G',0346,023,0234,0252,'I',0316,'N',0355,0234,0347,0215,0177,0344,06,'?',0353,0252,0326,':',0276,0250,0260,0350,0302,0306,'(',0336,0331,0270,0273,'g',' ',025,'M',0234,025,0365,'9',0305,'l','x',0327,0376,'@','c',0376,0272,0255,'V',0323,0363,0375,0223,'o',0203,0203,0344,0214,'~','U',0362,0274,'[','.',0134,'5','7','k',0373,0337,0243,'*',0216,0347,033,'q','y',0361,'-','n','e',020,'i',0272,'9',0204,'9',0362,0313,0334,'`',0225,0317,031,0367,0305,'v',':','{','^',0276,0215,013,'j','I',032,'^',0230,0263,'2',0306,'r',0241,0261,0316,017,0245,'x',0336,0231,0242,'i','Z',0264,'w',027,'^',' ',0361,0336,0241,'m',0250,0375,0246,'T',0222,'(','/',02,'"',0355,'r',06,01,07,0250,0,0376,'5',0353,0332,'4',026,0366,0276,035,0264,0202,0322,0355,0356,0355,0343,0200,',','w',022,'6',0346,0220,01,0367,0211,0356,'O',0255,'|',0276,':',0224,')',0270,'F',')',']','5','{','E',0257,0305,0275,'M','b',0356,'M',0340,'O',0370,0364,0274,0377,0,0256,0203,0371,'W','[',0134,0217,0201,'?',0343,0322,0363,0376,0272,017,0345,']','m','~',0246,'r',0213,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',0,'H',03,047,0245,'y',0337,0215,'<','L',0270,'{','x',0237,020,0247,0336,'#',0370,0215,'o',0370,0257,0134,032,'}',0241,0267,0211,0300,0231,0307,047,0373,0242,0274,'S','U',0277,'k',0333,0222,0252,'I','@','x',0367,'5',0315,0212,0304,'*',020,0277,'^',0206,'u','j','r','!',0326,'w',0223,0317,0251,0357,012,030,0267,030,'=',0205,'_',0272,0261,0266,0275,'-',0345,0262,0254,0313,0327,025,'K','O',0266,0270,0264,0225,'g','x',0216,0302,'9',0365,02,0257,0210,0255,'#',0234,0336,',',0330,0343,'$','f',0276,':',0275,'G','*',0216,'w',0324,0371,'<','e','K',0327,0366,0224,0336,0266,0321,0255,'n',0373,'3',0237,0270,0267,0222,0332,'R',0222,014,037,0347,'Z',0272,'M',0212,'*',0375,0256,0343,0204,'^','F','j',';','h','d',0325,'o',0214,0262,037,0335,0251,0375,'*',0227,0211,'5',0177,0371,'p',0266,'8','E',0341,0310,0376,'U',0355,'`',0351,'r','C',0333,'U',0371,037,'a',0222,0345,0265,0261,0325,'#',031,'|',0317,0240,0274,'=',0246,0301,'c',0246,'D',0321,'a',0232,'U',014,0134,'w',0315,'k',0327,011,0360,0247,']',':',0267,0204,0226,0336,'V','&','{','&',0362,0211,047,0222,0275,'A',0374,0253,0272,07,'5',0356,0323,0232,0234,'T',0221,0321,0213,0303,0313,017,'Z','T','e',0321,0213,'A',0242,0212,0263,0234,0301,0361,0236,0252,'4','_',011,'j',027,0231,0303,0210,0212,0247,0373,0307,0201,0374,0353,0345,0342,'K','1','b','r','I',0311,'5',0355,0377,0,032,0257,0214,'Z',015,0225,0222,0267,0372,0351,0367,'0',0365,0,0177,0215,'x','}','y','X',0311,'^',0245,0273,037,'{',0303,'t',024,'0',0216,0247,'Y','?',0313,'A',0361,'F',0323,'J',0221,' ',0313,';',05,03,0334,0327,0324,0336,030,0322,0223,'E',0360,0345,0225,0212,014,'y','q',0215,0337,'S',0311,0257,0237,0276,036,'i','?',0332,0376,'5',0260,0211,0200,'1',0304,0336,'s',0347,0321,'y',0376,'x',0257,0246,'+','l',014,'4','r','<',0376,'(',0304,'{',0320,0240,0275,'_',0344,0277,'P',0242,0212,'+',0274,0371,'#',0234,0361,0257,0374,0200,0307,0375,'u','Z',0257,0247,0177,0310,'*',0333,0376,0271,'/',0362,0253,036,'5',0377,0,0220,030,0377,0,0256,0253,'U',0364,0354,0177,'e','[','g',0247,0224,0277,0312,0276,'K',0214,'?',0335,'i',0377,0,0213,0364,'f',0324,'w','8','m','#','K',0360,'f',0252,0227,0222,0352,'z','F',0217,05,0344,'w','r',0306,0352,'d',04,0266,033,0206,0311,'=',0301,07,0361,0256,0346,0322,033,'K','}','.','8','l',026,'5',0264,'H',0366,0304,0261,0234,0250,0134,'q',0217,'j',0362,035,'B',0373,0341,'b',0352,'w','I','&',0205,'s','s','2',0273,0264,0262,0305,03,0262,0223,0270,0206,'9',0317,'L',0347,0232,0365,'M',015,0254,0237,0303,026,'m',0246,0302,0360,'Y',033,'q',0344,'F',0340,0202,0211,0216,01,07,0245,'|',0316,':',0234,0342,0341,'7',0316,0223,'k','I','l',0275,'5','f',0221,'d',0376,04,0377,0,0217,'K',0317,0372,0350,'?',0225,'u',0325,0310,0370,023,0376,'=','.',0377,0,0353,0240,0376,'U',0327,'W',0352,'g','(','Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'U','=','S','P',0217,'M',0261,'{',0211,017,' ','|',0243,0324,0325,0246,'!','A','b','p',0,0346,0274,0267,0306,0376,'$',022,0312,0311,033,'~',0356,'?',0225,07,0251,0365,0251,0224,0224,'S',0223,0330,'M',0244,0256,0316,'g',0304,0372,0334,0267,'W',022,02,0344,0273,0234,0261,0364,036,0225,0207,0246,'"',0233,0350,0314,0203,0345,0317,031,0365,0250,'S','u',0325,0332,0207,'<',0273,'r','k',0241,0222,0315,'J',0254,'D',04,0205,';',0216,0244,0327,0311,0343,0361,'~',0322,'z',0236,016,'a',0214,0214,'}',0311,'u','O',0344,'I','8',0237,'i','D',0344,0271,0353,0331,'E','d',']','[',0255,0306,0242,0260,'[',0257,'A',0206,'"',0247,0324,'.','.',0255,0245,026,0361,0312,'Y','X','q',0307,'5',0321,'x','K',0303,0262,']',0334,'*',0220,'K','7',0315,'#','z',012,'2',0314,033,0255,'>','g',0360,0230,0345,'8','I',';','T','m','[',0313,0257,0251,0215,0253,0273,'h',':',',','l',0221,0221,0347,'e','Q',0261,0324,0367,0257,'>','v','g','r',0314,'r',0304,0344,0232,0372,03,0342,'v',0207,024,0236,04,0177,'%',0,0373,031,022,016,';','w',0257,0237,0253,0330,0305,0246,0246,0243,0323,0241,0373,017,015,'B',0222,0302,'^',013,'[',0352,'z','?',0301,0335,'W',0354,0276,'&',0226,0301,0230,0204,0272,0217,0201,0376,0320,0257,'y',0257,0225,'|','3','~','t',0317,023,'i',0327,'`',0340,'G',':',0347,0350,'N',017,0350,'k',0352,0225,'!',0224,021,0320,0214,0327,'V',012,'W',0203,0217,'c',0310,0342,'j',034,0230,0230,0325,'_','i','~','+',0372,'B',0321,'E',025,0330,'|',0321,0341,0377,0,032,0356,0213,0353,0226,'6',0337,0303,034,'%',0277,'3','^','_',']',0327,0305,0271,0226,'_',034,0312,0243,'?',0273,0205,024,0347,0327,0223,0134,'-','x',0265,0335,0352,'H',0375,';',')',0207,'&',012,0232,0362,0374,0365,'=','W',0340,0225,0220,'}','S','Q',0275,' ',037,'.','5',0215,'O',0246,'N','M','{',']','y',0207,0301,'H',025,'4',013,0331,0201,0345,0347,0301,0374,05,'z','}','z','X','U','j','H',0370,0214,0366,0247,'>','>','~','V','_',0200,'Q','E',025,0320,'y',07,'9',0343,'_',0371,01,0217,0372,0352,0265,'V',0303,07,'H',0266,'R','@',0335,020,03,'?','J',0265,0343,'_',0371,01,0217,0372,0352,0265,0313,'x',0212,0313,'F',0277,0360,']',0274,'Z',0345,0371,0260,0264,'_','-',0305,0302,0315,0345,0225,'p','>',0134,'7',0255,'|',0267,025,'A','N',0215,'(',0276,0262,0350,0256,0366,'}',':',0232,0322,0335,0234,0344,0376,032,0361,'6',0211,0245,'i',0355,0244,0351,0366,0227,0267,'1',0333,'K','c','<','M','0',0134,0306,0317,0225,0223,047,034,0216,'I',036,0365,0334,0350,026,027,032,'W',0205,0264,0373,013,0271,'|',0333,0213,'{','T',0212,'G',0316,'r',0301,'p','y',0257,036,':',0326,0265,0246,0314,0261,'x','+',0304,'z',0257,0210,020,035,0276,'M',0305,0221,'x',0307,0251,'3',022,'3',0370,'W',0263,'i',023,'_',0134,'x','~',0326,'m','N',021,015,0363,0300,032,'x',0307,'E','|','r','+',0346,'s',010,'V',0202,0207,0264,'q','i',0312,0373,'5','/',0232,'{','-',']',0277,'6','k',033,022,'x',023,0376,'=','/','?',0353,0240,0376,'U',0326,0327,'%',0340,'O',0370,0364,0274,0377,0,0256,0203,0371,'W','[','_',0247,0234,0241,'E',024,'P',01,'G','z',0206,0342,0356,013,'D','/','<',0252,0212,'=','M','a',0134,'x',0317,'M',0205,0310,']',0357,0216,0340,'q','@',035,035,025,0201,0247,0370,0263,'O',0277,0235,'a',033,0221,0233,0200,'[',0241,0255,0372,0,'(',0242,0253,0336,0335,0307,'e','i','%',0304,0207,012,0203,'?','Z',0,0300,0361,0206,0266,0272,'}',0211,0267,'G',0304,0216,'9','>',0202,0274,'G','P',0274,'{',0353,0242,'F','J',0347,012,'+','o',0305,0232,0344,0227,0367,0262,015,0334,0261,0347,0330,'z','V','-',0205,0253,'8','k',0214,0205,021,0362,'3',0320,0327,0207,0231,0342,0327,0360,0343,0363,'8','1','u',0324,021,'z',0333,'G','@',0212,'^','B','&',0306,'F',';','S',0344,0232,'[','i','?',0323,'I','d','_',0270,'T','p','O',0275,'I','g','0',0274,0206,'V','2',04,0221,0217,'>',0302,0230,0352,0372,0215,0350,0201,'N','`',0217,0251,0365,'5',0341,'Q',0245,'R',0275,'_','g',0375,'#',0347,0351,'B',0265,'|','C',0247,'S','^',0376,'^',0214,0261,0244,'X',0313,0252,'_',0254,0354,0204,0263,0234,'F',0265,0354,0372,036,0223,036,0225,'b',0261,0200,'<',0306,0345,0333,0336,0261,0274,'!',0240,0255,0245,0272,0335,0314,0230,'v',037,' ','#',0240,0256,0262,0276,0317,017,'B','4',')',0250,'D',0372,0272,'4',0243,'J',012,021,0331,031,0276,' ',0262,032,0207,0207,0265,013,'F',031,022,0333,0272,0376,'8',0257,0224,0210,'*',0304,036,0240,0342,0276,0276,'a',0271,'H','=',0306,'+',0344,0355,'j',021,'o',0256,'_',0302,016,'B',0134,'H',0240,0377,0,0300,0215,'r',0343,0227,0302,0317,0265,0341,'Z',0232,'T',0247,0350,0377,0,'2',0220,'$',020,'G','Q','_','W',0350,'7','F',0367,'@',0323,0356,'O','Y','-',0321,0217,0344,'+',0344,0372,0372,'s',0300,022,0211,'|',015,0244,0221,0236,' ',013,0317,0265,'N',05,0373,0315,032,0361,'L','/','B',022,0354,0377,0,'5',0377,0,0,0351,'(',0242,0212,0364,0217,0211,'>','s',0370,0251,0377,0,'#',0355,0347,0373,0211,0374,0253,0213,0256,0337,0342,0274,'M',037,0216,0356,'Y',0261,0207,0215,030,'}','1',0212,0342,'+',0303,0255,0374,'I','z',0237,0251,'e',0316,0370,'J','_',0341,'_',0221,0357,0377,0,07,'@',036,014,'$',01,0223,';',0344,0327,0240,0327,0233,'|',030,0233,0177,0205,0356,'"','.',016,0311,0316,027,0323,'"',0275,'&',0275,'l','?',0360,0242,'~',0177,0233,0246,0261,0325,'o',0334,'(',024,036,0224,0202,0266,'<',0323,0235,0361,0257,0374,0200,0307,0375,'u','Z',0344,0374,'O',07,0207,'n','<',017,04,'~',047,'}',0232,'q',0362,0316,0340,0345,'H','|','q',0310,0374,'k',0254,0361,0257,0374,0200,0307,0375,'u','Z',0317,0206,0302,0323,'Q',0321,0255,'"',0275,0266,0212,0342,'5','U','p',0222,0250,'a',0220,'8','8','?','Z',0371,'~','(',0250,0251,0322,0245,'6',0332,0264,0272,'h',0366,'{',032,0322,0325,0263,0304,'`',0325,0256,0354,0212,'[','|','7',0324,'u',0333,0364,'G',013,0344,'I','j',0257,02,0217,'B',0304,014,'W',0267,0350,0362,0352,023,0370,'v',0322,']','Z','%',0213,'P','x',01,0270,0215,'z','+',0343,0220,'9','?',0316,0257,0307,024,'p',0306,'#',0212,'5','D',035,025,'F',0,0374,')','d',0377,0,'T',0377,0,0356,0232,0370,0334,'V','a',034,'T',0340,0224,'-','g',0276,0362,'~',0255,'%',0371,033,'(',0330,0251,0340,'O',0370,0364,0274,0377,0,0256,0203,0371,'W','[',0134,0227,0201,'?',0343,0322,0363,0376,0272,017,0345,']','m','~',0264,'r',05,'b','k',0372,0374,'z','D',';','W',015,';',016,07,0247,0275,'m',0327,0220,0370,0372,0342,'h',0357,0356,'y','9','$','(',0366,025,023,0232,0204,0134,0237,'A','I',0331,0134,0311,0326,0374,'U','5',0304,0315,0231,'L',0257,0237,'^',05,'s','3','_',0134,'L',0331,'y','[',0350,015,'W',0353,'E','|',0355,'l',']','J',0257,'{','#',0202,'u','%','-',0315,']',037,'S',0226,0332,0361,03,'9','*','O',031,'=',015,'{',0366,0217,'x','/',0264,0270,047,07,'$',0256,017,0326,0276,'m',04,0251,04,'u',025,0354,0277,016,0265,'q','q','g',0366,'W','n','q',0271,0177,0255,'z','9','m','w','$',0341,047,0261,0276,036,'w',0367,'Y',0336,'W',0234,0374,'A',0361,022,0304,0246,0322,'&',0316,0336,0270,0356,'k',0261,0327,0365,'T',0322,'t',0311,'%',',',03,0221,0205,025,0340,0327,0372,0237,0333,'5','O','>',0134,0272,06,0316,'=','k',0247,031,0210,0366,024,0333,'[',0364,'.',0275,'N','H',0266,0267,07,0260,'-','i',0347,0314,0307,0317,0220,0374,0253,0353,'V',0355,0256,'"',0362,'~',0305,'t',0236,'Y',0306,'>',0265,'r','6',0202,0354,0244,0361,0235,0314,0203,0201,0351,'T','Z',0333,0211,0356,0257,0207,'=',025,'k',0343,0235,'G','R',0374,0373,0376,0247,0311,'}','c',0333,0336,025,0256,0232,0177,'4',0372,'X',0247,'s',0247,0264,'7','i',024,016,'[',0177,'L',036,0225,0350,'~',013,0360,0330,0231,0326,'I',027,0367,'1',0234,0261,'?',0304,'k',0235,0360,0276,0211,'-',0355,0322,'|',0244,0273,0236,0247,0370,'V',0275,0236,0302,0312,'+',013,'D',0267,0210,0,024,'s',0356,'k',0352,0262,0354,'+',0245,016,'i',0374,'L',0372,0214,'%',031,'B',011,0315,0335,0226,025,'B',0250,'P','0',07,'A','K','E',025,0351,035,'a','_','-',0370,0310,05,0361,0216,0254,0,0,'}',0245,0270,025,0365,'!',0340,'W',0312,'^','#',0230,0334,'x',0227,'S',0224,0270,'}',0327,'/',0363,016,0377,0,'1',0256,034,'w',0302,0217,0252,0341,'d',0375,0255,'G',0344,0214,0312,0372,'[',0341,0307,0374,0210,'z','g',0375,'s',0376,0265,0363,'M','}','3',0360,0362,'6',0213,0300,0272,'P','l','d',0305,0270,'}',015,'c',0202,0370,0337,0241,0350,'q','?',0373,0254,0177,0305,0372,'3',0247,0242,0212,'+',0324,'>',024,0360,0177,0214,0326,0336,'W',0212,0255,0347,0301,0375,0354,03,0234,0365,0301,0377,0,0353,0327,0233,0327,0262,0374,'n',0263,0315,0246,0233,'z',07,0335,'v',0214,0237,0250,0317,0364,0257,032,0257,033,022,0255,'U',0237,0245,'d',0265,'=',0246,06,0233,0354,0255,0367,036,0277,0360,'F',0360,'g','S',0262,047,0237,0226,'@','?','J',0366,032,0371,0343,0341,'F',0246,0272,0177,0215,'a',0211,0333,011,'t',0215,027,0374,013,0250,0376,'U',0364,'=','w',0340,0345,'z','v',0354,'|',0227,021,'Q','p',0306,0271,0177,'2','O',0364,0375,02,0220,'R',0321,']','G',0204,'s',0236,'5',0377,0,0220,030,0377,0,0256,0253,'P','i',0237,0362,014,0265,0377,0,0256,'K',0374,0252,0337,0214,'b','y','t',026,'*','3',0261,0303,037,0245,'f',0350,0267,')','q',0246,'B',0252,'F',0350,0324,'#',017,'L','W',0312,'q','u','9','K',07,031,'%',0242,0226,0277,'s','5',0243,0361,032,'4',0331,'?',0325,'?',0373,0246,0235,'U',0257,0356,'R',0322,0312,'I',0134,0201,0362,0220,0243,0324,0372,'W',0300,0341,0251,0312,0245,'h',0302,012,0355,0264,'t','7','d','G',0340,'O',0370,0364,0274,0377,0,0256,0203,0371,'W','[',0134,0257,0201,0242,'t',0323,0256,'%','#',012,0362,'|',0276,0370,025,0325,'W',0355,047,020,'W',0231,'|','I',0260,0375,0341,0230,016,035,'3',0237,'q','^',0233,0134,0327,0215,',','E',0336,0214,0134,014,0230,0316,0177,012,0231,0307,0232,'.','=',0305,'%','u','c',0300,0250,0251,'n','b','0',0334,'I',031,0354,'M','E','_',047,'(',0270,0266,0231,0346,0205,'t','~',025,0325,0237,'O',0274,033,037,014,0247,'+',0237,0345,0134,0345,'(','%','N','A',' ',0373,'V',0270,'z',0316,0215,'E','4','T','%',0312,0356,'v',036,'/',0361,'4',0372,0233,0210,0331,0200,'8',0306,0325,'<',012,0343,0251,'I',',','r','N','M','%','V',047,020,0353,0317,0231,0204,0346,0346,0356,0311,'`',0270,0222,0335,0303,0306,0304,032,0334,0262,0363,0265,0211,0343,'.',0237,0273,'C',0320,0177,021,0254,';','h',032,0346,'u',0215,'G','$',0327,0256,'x','#',0303,0252,0252,0267,'R',047,0356,0343,0373,0200,0367,'>',0265,0276,03,07,032,0263,0366,0262,'Z','!','R',0303,'S',0235,'E','R','K','T','t','~',031,0321,'W','L',0262,022,':',0217,'>','A',0223,0354,'=','+','z',0212,'+',0350,017,'H','(',0242,0212,0,0255,0250,0334,0255,0236,0233,'u','r',0307,02,'(',0231,0311,0372,012,0371,'.','i',014,0323,0311,'+','u','v',',',0177,023,'_','I','|','G',0324,06,0237,0340,'}','D',0356,0303,'L',0236,'J',0375,'[',0212,0371,0252,0274,0334,'t',0275,0344,0217,0266,0341,'z','V',0243,':',0235,0335,0276,0357,0370,'p',0257,0252,'<',')','m',0366,'O',011,0351,'p','c',05,'m',0223,'#','9',0355,'_','1','i','v',0215,0177,0253,'Z','Z','(',0311,0232,'e','O',0314,0327,0326,'P',0306,'!',0205,'#','^',0210,0241,'G',0341,'O',03,035,'[','3',0342,0232,0236,0345,':','~',0254,'}',024,'Q','^',0211,0361,0247,'!',0361,'/','J',':',0257,0202,'/','B','.','d',0267,0304,0353,0377,0,01,0353,0372,'f',0276,'n',0257,0257,047,0205,'n','-',0344,0205,0306,'V','E','*','G',0261,0257,0225,0274,'C',0245,0276,0215,0257,0336,'X','8',0307,0225,'!',013,0376,0357,'o',0322,0274,0334,'l','5','R','>',0323,0205,0361,'7',0247,':',017,0246,0253,0346,'U',0323,0356,0336,0303,'R',0266,0273,0214,0220,0360,0312,0262,02,'=',0216,'k',0352,0355,':',0362,'=','C','N',0267,0273,0214,0202,0222,0306,030,021,0356,'+',0344,0212,0367,0177,0203,0376,'!',027,0372,023,0351,'3','8',0363,0354,0317,0310,';',0230,0317,'O',0313,0245,',',024,0355,047,027,0324,0327,0211,'p',0256,0245,010,0326,0217,0331,0337,0321,0236,0223,'E',024,'W',0246,'|','0',0311,'#','I',0243,'h',0344,'P',0310,0303,04,036,0342,0270,0333,0377,0,011,0315,'i','p','f',0323,0257,'R','%','c',0302,0310,0373,'H',0366,0317,'z',0351,'u',0235,'H','i','Z','l',0227,'8',05,0307,010,017,'r','k',0210,0267,0323,0357,'u',0262,'n',0357,'.',0134,'+',0236,'3',0316,'~',0203,0260,0256,'l','^','&',0206,032,0223,0251,']',0332,'#','I',0267,0241,'k',0373,047,'[',0377,0,0240,0235,0277,0375,0377,0,0377,0,0353,'T',0226,0336,025,0273,0277,0234,'5',0366,0241,033,0306,0247,0221,033,0357,'?',0375,'j',0213,0376,021,0210,0177,0347,0346,'O',0310,'U','{',0235,'&',0357,'J','_',0265,0331,']','9',0362,0371,'8',0340,0217,0361,0257,'3',015,0234,'e','u','*','(','R',0222,'R','{','i','o',0320,0247,011,'%',0251,0350,'6',0326,0321,'Z','[',0244,020,0240,'X',0320,'`',01,'R',0326,'^',0201,0252,0377,0,'k','i',0253,'3',0,'%','S',0265,0300,0365,0255,'J',0367,010,012,0202,0362,01,'s','g',',',',','2',035,'H',0251,0350,0240,017,0236,'<','M','d','m','5',047,04,'c',0222,017,0324,'V','%','z','g',0304,0215,047,'e',0303,'N',0213,0303,0215,0337,0217,'z',0363,':',0371,0354,0302,0227,'%','k',0367,'8','k','F',0323,012,'(',0242,0270,'L','B',0200,'2','q','E','k','h','z','k','^',0335,0251,0332,'H',07,0,'z',0232,0326,0215,047,'V','j',010,0250,0305,0311,0331,035,027,0203,0274,'<',0367,0227,'(',012,0234,0267,',','}',05,'{','-',0275,0274,'v',0266,0351,014,'J',02,'(',0300,025,0231,0341,0355,'!','4',0253,05,05,'G',0232,0343,',',0177,0245,'l','W',0323,0323,0247,032,'q','Q',0217,'C',0320,0214,'T','U',0220,'Q','E',025,'e',05,024,'T','w',023,0245,0265,0274,0223,0312,0301,'R','5',',',0304,0366,02,0201,0244,0333,0262,'<',0207,0343,'V',0262,013,0331,'h',0361,0277,'O',0337,'J',01,0374,05,'y',015,'k',0370,0237,'X','}','w',0304,'w',0272,0203,0266,'D',0222,020,0236,0312,'8',037,0245,'d','W',0211,'Z','|',0363,'r','?','O',0313,'p',0277,'U',0302,0302,0227,'[','k',0352,0367,';','o',0205,'z','_',0366,0207,0215,' ',0224,0256,'R',0325,'L',0247,0353,0320,'W',0321,'U',0345,0377,0,06,'4','f',0267,0321,'n',0265,'I','S',015,'s','&',0310,0317,0373,'+',0377,0,0327,0315,'z',0205,'z','X','H','r',0323,0277,'s',0342,0270,0203,021,0355,0261,0256,'+','h',0351,0376,'a','E',024,'W','I',0342,05,'x',0307,0306,'o',016,0264,'w','v',0372,0354,011,0373,0271,07,0225,'>',';',021,0320,0377,0,'J',0366,'z',0315,0327,0264,0230,0265,0315,026,0353,'O',0230,02,0262,0241,0,0236,0307,0261,0254,0253,'S',0366,0220,'q',';',0362,0314,'c',0302,'b','c','S',0246,0317,0320,0371,'F',0267,0274,035,0257,0267,0207,'<','I','m','}',0223,0345,'g','d',0240,'w','C',0326,0262,0365,033,011,0364,0315,'F','{','+',0224,')','4','.','Q',0201,0252,0265,0342,0246,0342,0357,0325,037,0245,0316,020,0255,'M',0305,0352,0244,0277,'3',0353,0313,'y',0343,0272,0267,0216,'x','X','4','r','(','e','a',0334,032,0222,0274,0227,0341,037,0214,'<',0350,'?',0260,'/','e',0371,0343,0346,0331,0230,0365,'_',0356,0327,0255,'W',0267,'J',0242,0251,036,'d','~','c',0217,0301,0317,011,']',0322,0227,0313,0315,034,0307,0216,'?',0344,021,017,0375,'v',037,0310,0322,'X',0,'4',0353,'`',06,07,0224,0277,0312,0264,'<','M',0247,'>',0243,0244,':','D','3','*',035,0352,'=','q',0134,0276,0225,0255,0303,015,0272,0333,']',0223,033,0307,0362,0206,'#',0267,0275,'|',0367,023,0340,0253,0342,0260,0321,0366,'*',0356,'.',0366,0371,030,'R',0222,'O','S',0240,0246,'L',03,'A',' ','#',' ',0251,07,0362,0252,0237,0333,':',0177,0374,0374,0247,0353,'T','5','=','z',017,0263,'<','6',0254,'d',0221,0306,0335,0300,'p','+',0342,0360,0231,'F',':',0245,'x',0257,'f',0326,0253,'V',0255,'c','g','8',0333,'s','C',0300,0237,0361,0351,'w',0377,0,']',07,0362,0256,0266,0260,'<',047,0246,0311,0247,0351,'E',0246,'R',0262,'L',0333,0312,0236,0240,'v',0255,0372,0375,'d',0344,012,'(',0242,0200,'0','<','Y',0246,0177,'h','i',016,'U','r',0361,0362,'>',0225,0340,0332,0205,0253,'Z',0335,0274,'d','`','g',0212,0372,']',0200,'e','*','F','A',0340,0327,0233,0370,0247,0300,0322,0335,0134,0264,0226,0261,0356,'F','9',033,'z',0255,'r','c','0',0336,0336,026,'[',0243,'*',0264,0371,0326,0233,0236,'M','E','u',0315,0340,035,'H',0177,0313,')','?',0357,0232,'X',0274,01,0251,'H',0330,'1',0311,0377,0,'|',0342,0274,0217,0354,0372,0375,0216,'_','c','>',0307,'+','o',03,0134,'L',0261,0240,0344,0232,0366,037,03,'x','u',' ',0205,'n',0345,'O',0225,'~',0340,'#',0251,0365,0252,'z',017,0303,0306,0267,0221,'d',0271,0302,'/','~',0344,0327,0242,0303,012,'A',012,0305,032,0205,'E',030,0,'W',0253,0203,0302,'{',05,'y','n',0316,0232,'T',0271,'5','{',0217,0242,0212,'+',0264,0330,'(',0242,0212,0,'+',0315,'~','.','x',0240,'i',0272,':',0350,0366,0357,0376,0225,'v','>','|',0177,014,0177,0375,'z',0356,0265,0255,'^',0327,'C',0322,0247,0324,'.',0334,',','q','.','}',0330,0366,02,0276,'b',0327,0365,0273,0237,020,'k','3',0352,027,',','w','H',0337,'*',0377,0,'u','{',012,0344,0305,0325,0344,0217,'*',0335,0237,'C',0303,0371,'{',0257,'[',0333,'M','{',0261,0374,'_',0374,03,'2',0255,0351,0226,023,'j',0232,0225,0275,0214,013,0231,'&','p',0203,0374,'j',0245,'z',0337,0301,0337,013,0227,0270,0223,'_',0271,'O',0221,01,0216,0334,021,0324,0367,'o',0351,'^','u','*','n',0244,0324,'O',0261,0307,0342,0343,0204,0303,0312,0253,0351,0267,0257,'C',0326,'4','}',':','-','#','H',0265,0260,0205,'B',0244,021,0205,0,'U',0332,'(',0257,'m','+','+','#',0362,0371,0311,0316,'N','R',0335,0205,024,'Q','L',0220,0242,0212,'(',03,0312,'>','.','x','@',0134,'[',0177,'o',0331,0305,0231,0243,0,0134,05,037,'y',0177,0275,0370,'W',0213,'W',0327,0262,0304,0223,0304,0361,'H',0241,0221,0301,'V','S',0320,0203,'_',':','|','A',0360,'l',0276,030,0325,0232,'h',020,0235,':',0341,0211,0211,0277,0272,0177,0272,'k',0315,0305,0321,0263,0347,'G',0332,0360,0366,'f',0247,037,0252,0324,'z',0255,0275,';','|',0216,'J',0336,0342,'k','K',0230,0356,'-',0344,'h',0346,0215,0203,'#',0251,0301,04,'W',0321,0276,04,0361,0245,0277,0212,0264,0300,0256,0312,0272,0204,'*','<',0350,0375,0177,0332,036,0325,0363,'m','_',0321,0365,0213,0315,013,'R',0212,0372,0306,'R',0222,0241,0374,030,'z',037,'j',0302,0205,'g','J','^','G',0255,0232,'e',0260,0307,'R',0266,0322,'[','?',0353,0241,0365,0215,'f','^',0350,032,'m',0374,0206,'Y',0355,0227,0314,'=','Y','N',011,0372,0342,0262,0374,037,0343,'K',017,025,0330,'+','#',010,0357,'T','~',0366,02,'y',07,0324,'z',0212,0351,0353,0327,0214,0224,0225,0321,0371,0315,'j',025,'(','M',0323,0250,0254,0321,0205,0377,0,010,0216,0221,0377,0,'<',037,0376,0373,'5','f',0323,0303,0272,']',0224,0242,'X',0255,0224,0270,0344,'3',0235,0330,0374,0353,'R',0212,0243,' ',0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0250,0346,0232,';','x','^','i',0234,'$','h',013,'3',036,0200,'Q','<',0361,'[','@',0363,'L',0352,0221,0240,0313,'3',034,0,'+',0303,'>','!',0374,'F',0223,'Y',0226,'M','/','J',0223,'e',0202,0360,0362,0203,0314,0247,0374,'+','*',0325,0243,'J','7','g',0241,0227,'e',0325,'q',0265,'9','a',0262,0335,0366,'3',0276,'!',0370,0341,0274,'Q',0177,0366,'k','F','#','N',0201,0276,'N',0336,'a',0376,0361,025,0303,0321,'R','[',0301,'-',0325,0304,'p','@',0205,0345,0221,0202,0252,0216,0244,0327,0215,'9','9',0312,0354,0375,037,017,'B',0236,032,0222,0247,'M','Y','#','O',0303,'Z',05,0317,0211,'5',0270,'4',0373,'p','p',0307,'2','>','8','E',0356,'k',0351,0355,'3','N',0267,0322,'t',0330,',','m','P',',','0',0250,'U',02,0271,0217,0207,0276,016,036,027,0321,0203,0334,05,':',0205,0307,0315,')',037,0303,0350,0277,0205,'v','U',0352,'a','h',0373,'8',0335,0356,0317,0205,0317,'3','/',0255,0326,0366,'t',0337,0271,037,0305,0367,0377,0,' ',0242,0212,'+',0250,0360,0202,0212,'(',0240,02,0212,'(',0240,02,0250,'k',032,'E',0246,0271,0246,'M','a','y',022,0274,'R',014,'r',':',037,'Q',0357,'W',0350,0244,0322,'j',0314,0250,'N','P',0222,0224,']',0232,'>','_',0361,'o',0204,0357,'|',')',0252,'5',0275,0302,0226,0267,'s',0230,'f',03,0207,037,0343,0134,0375,'}',']',0256,'h','v','^',' ',0323,'d',0261,0276,0214,'4','n','8','n',0352,'}','E','|',0363,0343,017,04,0337,0370,'N',0360,0371,0200,0315,'d',0307,021,0334,01,0301,0366,'>',0206,0274,0254,'F',035,0323,'w',0216,0307,0337,0345,031,0314,'1','q','T',0352,'i','?',0317,0323,0374,0214,013,015,'B',0357,'L',0273,'K',0253,')',0336,031,0220,0344,'2',034,'W',0272,'x','7',0342,0205,0216,0264,0221,0332,'j',0216,0226,0267,0374,'(','$',0341,'$','>',0336,0225,0340,'T',02,'A',0310,0340,0326,'T',0253,'J',0233,0320,0355,0307,0345,0264,'q',0260,0265,'E',0252,0331,0365,'>',0300,04,021,0220,'r','(',0257,0236,0374,'-',0361,'G','U',0320,0225,'-',0257,'3','{','f',0274,05,'c',0363,0250,0366,'5',0354,'^',036,0361,0266,0211,0342,'H','A',0264,0272,011,'6','>','h','e',0371,0134,0177,0215,'z',0224,0261,020,0251,0352,'|','6',';',047,0304,0341,033,'m','^','=',0327,0365,0241,0321,'Q','E',025,0271,0345,05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',05,024,'T',027,'W',0226,0326,'P',0264,0327,'S',0307,014,'j','2','Y',0333,02,0215,0206,0223,'n',0310,0236,0263,'u',0255,'{','N',0320,',',0315,0326,0243,'r',0221,047,'`','O',',','}',0,0357,'^',0177,0342,'o',0214,'6','V',0233,0355,0264,'H',0215,0314,0243,0217,'=',0270,'@','}',0275,'k',0310,'u','}','o','P',0327,'o','Z',0353,'P',0271,'y',0244,'=',01,'<','(',0364,03,0265,'q',0325,0305,0306,':','C','V','}',026,'_',0303,0325,0253,'5',':',0376,0354,0177,027,0376,'G','K',0343,'o',0210,'W',0276,'(',0224,0333,0333,0227,0266,0323,0324,0361,030,'8','2','{',0267,0370,'W',025,'E','K','o','o','5',0335,0302,'A','o',033,'I','+',0234,'*','(',0311,'&',0274,0331,'J','S','w','g',0332,0320,0241,'K',015,'M','B',0232,0262,'D','j',0254,0356,021,024,0263,'1',0300,03,0251,'5',0355,0377,0,016,'>',037,'>',0220,0321,'j',0372,0234,'j','n',']','r',0221,'0',0377,0,'T','=','~',0265,047,0303,0377,0,0206,0261,0351,013,026,0251,0253,0240,'{',0342,'2',0220,0221,0221,027,0377,0,'^',0275,'2',0273,0360,0330,'k','{',0363,'>','K',':',0316,0324,0357,0207,0303,0275,':',0276,0376,'H','(',0242,0212,0357,'>','P','(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'*',0275,0355,0225,0266,0241,'j',0366,0327,'p',0244,0320,0270,0303,'+',014,0212,0261,'E',026,0270,0323,'q','w','[',0236,037,0343,017,0204,0327,'6',06,'[',0335,014,0264,0366,0374,0261,0267,'?','y',07,0267,0255,'y',0203,'+','#',0224,'u','*',0312,'p','A',030,' ',0327,0327,0365,0311,0370,0233,0341,0356,0213,0342,'@',0362,0274,'"',0336,0354,0377,0,0313,'x',0206,011,'>',0376,0265,0301,'[',07,'}','`','}','V',']',0304,'n',013,0331,0342,0265,']',0377,0,0314,0371,0256,0235,034,0217,023,0207,0215,0331,030,'t','e','8','"',0272,0377,0,022,'|','6',0327,'t',07,'g','H',015,0345,0247,'i','a',031,'#',0352,':',0212,0343,0331,'Y',030,0253,02,0254,'8',' ',0214,021,0134,022,0204,0242,0355,'$','}','m',032,0364,0253,0307,0232,0234,0223,'G','a',0242,0374,'L',0361,'&',0216,'U','~',0324,'.',0341,037,0362,0316,0340,'g',0217,'c',0326,0275,07,'I',0370,0317,0245,0134,0205,'M','J',0322,'[','W',0356,0311,0363,0257,0370,0327,0206,0321,'Z',0303,021,'R',033,'3',0213,023,0223,0340,0361,032,0312,026,'}',0326,0207,0323,0326,'^',':',0360,0335,0360,036,'V',0253,0,047,0263,0266,0323,0372,0326,0304,':',0215,0224,0343,'1',']',0300,0343,031,0371,'d',06,0276,'I',0245,'V','e',0373,0254,'G',0320,0326,0353,035,'.',0250,0362,'g',0302,0324,'_',0301,'Q',0257,0225,0377,0,0310,0372,0364,':','0',04,'2',0220,'{',0203,'M','{',0210,'c',0316,0371,'c',0134,'z',0260,025,0362,'b',0352,'7',0250,0241,'R',0362,0341,'T','p',0,0225,0200,037,0255,'G','%',0314,0363,'6',0351,'g',0221,0333,0246,'Y',0311,'5','_','^',0376,0351,0212,0341,']','u',0253,0370,0177,0301,'>',0247,0271,0361,036,0215,'f','3','>',0247,'j',0237,'Y',05,'s',0272,0207,0305,'O',014,'X',0251,0362,0356,0232,0345,0307,'E',0211,'s',0237,0306,0276,'u',0242,0242,'X',0331,0275,0221,0325,'K',0206,'0',0321,'~',0374,0233,0374,017,'R',0326,0276,'4','j',027,01,0243,0322,'l',0343,0266,'C',0322,'I','~','f',0374,0272,012,0363,0355,'O','^',0325,'u',0227,0337,0250,'_','M','9',0364,'f',0343,0362,0254,0352,'+',0232,'u','g','?',0211,0236,0326,033,01,0206,0303,'/',0335,'A','/','>',0277,'x','Q','W',0364,0335,027,'R',0326,047,'X','l',',',0345,0235,0330,0343,0345,'^','?','>',0225,0352,0236,031,0370,'8',0251,0262,0347,'_',0230,';','u',0373,'4','G',0217,0241,'=',0351,0323,0243,':',0217,0335,'D',0342,0363,034,'>',021,'^',0254,0265,0355,0324,0363,0177,016,'x','W','T',0361,'=',0330,0206,0306,03,0345,0203,0363,0314,0303,0344,'O',0306,0275,0337,0301,0376,0,0323,'|','+',027,0233,0217,0264,0337,'7',0336,0231,0307,'O','e',035,0253,0245,0261,0323,0355,'4',0313,'U',0266,0262,0267,0216,010,'W',0242,' ',0300,0253,'5',0351,'Q',0303,'F',0236,0257,'V','|','V','e',0236,'V',0305,0336,020,0367,'a',0333,0253,0365,012,'(',0242,0272,'O',014,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,010,04,'`',0214,0212,0347,'5',0257,03,'x',0177,']','V','7','V','(',0262,0237,0371,'k',027,0312,0337,0230,0256,0216,0212,0231,'E','I','Y',0243,'Z','U',0252,'Q',0227,'5','9','4',0374,0217,031,0325,'~',011,0316,0254,0317,0245,'j','J',0351,0332,'9',0327,07,0363,025,0310,'j',037,016,'|','O',0247,0223,0273,'N','y',0224,0177,024,047,'u','}','+','E','s','K',07,'M',0355,0241,0355,0320,0342,'<','e','=',047,'i','z',0377,0,0300,'>','H',0270,0323,0257,'m',016,'.','-',047,0210,0377,0,0267,031,025,'Z',0276,0274,'x','"',0224,'b','H',0221,0307,0373,'J',015,'Q',0233,0303,0332,'5',0312,0262,0315,0245,0331,0270,'c',0223,0230,'W',0237,0322,0261,'x',027,0322,'G',0243,016,'*',0217,0333,0247,0367,'?',0370,07,0312,'4','W',0324,0277,0360,0207,'x','o',0376,0200,0226,'?',0367,0344,'S',0242,0360,0237,0207,0341,0220,'I',036,0215,'d',0254,':',021,010,0245,0365,031,'w','5',0377,0,'Z','h',0177,'#',0374,017,0226,0222,'7',0221,0202,0306,0214,0344,0364,012,'3','Z',0326,'^',025,0327,'u',02,'>',0315,0245,']','8','=',011,'B',0243,0365,0257,0247,0241,0323,'l','m',0277,0324,'Y',0333,0307,0316,'~','H',0300,0253,' ',01,0320,01,0364,0252,'X',036,0354,0347,0251,0305,'/',0376,']',0323,0373,0331,0340,':','o',0301,0377,0,020,0336,'`',0334,0274,026,0212,0177,0274,'w',021,0370,012,0356,0264,'O',0203,0372,'&',0236,'V','M','B','I','/',0345,034,0341,0276,'T',0374,0253,0321,'h',0256,0210,'a','i',0307,0245,0317,'+',021,0237,'c','k','+','s','r',0257,'-','?',035,0312,0326,'v',026,0232,'|','"','+','K','x',0341,0214,'t','T','P','*',0315,024,'W','B','V','<','y','I',0311,0335,0260,0242,0212,'(',020,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,01,0377,0331,0377,0341,015,'7','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0,'<','?','x','p','a','c','k','e','t',' ','b','e','g','i','n','=','"',0357,0273,0277,'"',' ','i','d','=','"','W','5','M','0','M','p','C','e','h','i','H','z','r','e','S','z','N','T','c','z','k','c','9','d','"','?','>',' ','<','x',':','x','m','p','m','e','t','a',' ','x','m','l','n','s',':','x','=','"','a','d','o','b','e',':','n','s',':','m','e','t','a','/','"',' ','x',':','x','m','p','t','k','=','"','X','M','P',' ','C','o','r','e',' ','4','.','4','.','0','-','E','x','i','v','2','"','>',' ','<','r','d','f',':','R','D','F',' ','x','m','l','n','s',':','r','d','f','=','"','h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#','"','>',' ','<','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n',' ','r','d','f',':','a','b','o','u','t','=','"','"',' ','x','m','l','n','s',':','x','m','p','M','M','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/','"',' ','x','m','l','n','s',':','s','t','E','v','t','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#','"',' ','x','m','l','n','s',':','d','c','=','"','h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/','"',' ','x','m','l','n','s',':','G','I','M','P','=','"','h','t','t','p',':','/','/','w','w','w','.','g','i','m','p','.','o','r','g','/','x','m','p','/','"',' ','x','m','l','n','s',':','x','m','p','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','"',' ','x','m','p','M','M',':','D','o','c','u','m','e','n','t','I','D','=','"','g','i','m','p',':','d','o','c','i','d',':','g','i','m','p',':','e','5','9','4','4','0','5','e','-','8','d','f','0','-','4','a','b','a','-','a','2','d','a','-','c','d','f','c','8','0','0','2','8','5','9','e','"',' ','x','m','p','M','M',':','I','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','6','5','e','5','2','f','1','b','-','1','7','2','0','-','4','4','b','d','-','9','1','c','4','-','e','d','8','7','9','1','a','d','8','6','1','3','"',' ','x','m','p','M','M',':','O','r','i','g','i','n','a','l','D','o','c','u','m','e','n','t','I','D','=','"','x','m','p','.','d','i','d',':','8','0','6','1','1','f','0','9','-','1','5','8','1','-','4','b','9','c','-','b','4','5','8','-','9','8','4','f','e','e','c','e','1','2','6','0','"',' ','d','c',':','F','o','r','m','a','t','=','"','i','m','a','g','e','/','j','p','e','g','"',' ','G','I','M','P',':','A','P','I','=','"','2','.','0','"',' ','G','I','M','P',':','P','l','a','t','f','o','r','m','=','"','L','i','n','u','x','"',' ','G','I','M','P',':','T','i','m','e','S','t','a','m','p','=','"','1','6','7','8','6','3','7','7','4','7','6','9','4','3','5','9','"',' ','G','I','M','P',':','V','e','r','s','i','o','n','=','"','2','.','1','0','.','3','0','"',' ','x','m','p',':','C','r','e','a','t','o','r','T','o','o','l','=','"','G','I','M','P',' ','2','.','1','0','"','>',' ','<','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','r','d','f',':','S','e','q','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','9','2','f','7','c','d','9','7','-','d','a','8','4','-','4','9','3','e','-','b','e','0','8','-','b','c','6','3','2','3','4','5','b','d','7','2','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','2','-','1','2','T','2','0',':','5','9',':','4','9','+','0','0',':','0','0','"','/','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','9','3','6','3','e','3','2','f','-','1','e','b','b','-','4','c','7','2','-','b','5','7','4','-','1','b','b','3','4','a','8','0','b','3','9','9','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','3','-','1','2','T','1','6',':','1','5',':','4','7','+','0','0',':','0','0','"','/','>',' ','<','/','r','d','f',':','S','e','q','>',' ','<','/','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','/','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n','>',' ','<','/','r','d','f',':','R','D','F','>',' ','<','/','x',':','x','m','p','m','e','t','a','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','<','?','x','p','a','c','k','e','t',' ','e','n','d','=','"','w','"','?','>',0377,0342,02,0260,'I','C','C','_','P','R','O','F','I','L','E',0,01,01,0,0,02,0240,'l','c','m','s',04,'0',0,0,'m','n','t','r','R','G','B',' ','X','Y','Z',' ',07,0347,0,03,0,014,0,016,0,'&',0,'7','a','c','s','p','A','P','P','L',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,0366,0326,0,01,0,0,0,0,0323,'-','l','c','m','s',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,015,'d','e','s','c',0,0,01,' ',0,0,0,'@','c','p','r','t',0,0,01,'`',0,0,0,'6','w','t','p','t',0,0,01,0230,0,0,0,024,'c','h','a','d',0,0,01,0254,0,0,0,',','r','X','Y','Z',0,0,01,0330,0,0,0,024,'b','X','Y','Z',0,0,01,0354,0,0,0,024,'g','X','Y','Z',0,0,02,0,0,0,0,024,'r','T','R','C',0,0,02,024,0,0,0,' ','g','T','R','C',0,0,02,024,0,0,0,' ','b','T','R','C',0,0,02,024,0,0,0,' ','c','h','r','m',0,0,02,'4',0,0,0,'$','d','m','n','d',0,0,02,'X',0,0,0,'$','d','m','d','d',0,0,02,'|',0,0,0,'$','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,'$',0,0,0,034,0,'G',0,'I',0,'M',0,'P',0,' ',0,'b',0,'u',0,'i',0,'l',0,'t',0,'-',0,'i',0,'n',0,' ',0,'s',0,'R',0,'G',0,'B','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,032,0,0,0,034,0,'P',0,'u',0,'b',0,'l',0,'i',0,'c',0,' ',0,'D',0,'o',0,'m',0,'a',0,'i',0,'n',0,0,'X','Y','Z',' ',0,0,0,0,0,0,0366,0326,0,01,0,0,0,0,0323,'-','s','f','3','2',0,0,0,0,0,01,014,'B',0,0,05,0336,0377,0377,0363,'%',0,0,07,0223,0,0,0375,0220,0377,0377,0373,0241,0377,0377,0375,0242,0,0,03,0334,0,0,0300,'n','X','Y','Z',' ',0,0,0,0,0,0,'o',0240,0,0,'8',0365,0,0,03,0220,'X','Y','Z',' ',0,0,0,0,0,0,'$',0237,0,0,017,0204,0,0,0266,0304,'X','Y','Z',' ',0,0,0,0,0,0,'b',0227,0,0,0267,0207,0,0,030,0331,'p','a','r','a',0,0,0,0,0,03,0,0,0,02,'f','f',0,0,0362,0247,0,0,015,'Y',0,0,023,0320,0,0,012,'[','c','h','r','m',0,0,0,0,0,03,0,0,0,0,0243,0327,0,0,'T','|',0,0,'L',0315,0,0,0231,0232,0,0,'&','g',0,0,017,0134,'m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'G',0,'I',0,'M',0,'P','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'s',0,'R',0,'G',0,'B',0377,0333,0,'C',0,03,02,02,03,02,02,03,03,03,03,04,03,03,04,05,010,05,05,04,04,05,012,07,07,06,010,014,012,014,014,013,012,013,013,015,016,022,020,015,016,021,016,013,013,020,026,020,021,023,024,025,025,025,014,017,027,030,026,024,030,022,024,025,024,0377,0333,0,'C',01,03,04,04,05,04,05,011,05,05,011,024,015,013,015,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,0377,0302,0,021,010,02,'Z',02,'X',03,01,021,0,02,021,01,03,021,01,0377,0304,0,034,0,01,0,02,02,03,01,0,0,0,0,0,0,0,0,0,0,0,06,07,05,010,01,03,04,02,0377,0304,0,034,01,01,0,01,05,01,01,0,0,0,0,0,0,0,0,0,0,0,05,02,03,04,06,07,01,010,0377,0332,0,014,03,01,0,02,020,03,020,0,0,01,0332,0220,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,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,01,0361,0345,'@',01,0367,0355,' ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0362,'Q','~',')',0213,';',021,0307,0232,0210,0343,'L',0307,0254,0311,0341,0255,'f',0342,0255,0345,0364,'y','p',01,0231,0273,0205,0220,0257,032,'A','z',':','Q','~','"','a',0223,013,'.',0312,0202,0314,']',0217,0347,0337,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,03,0203,01,0217,'-','X','`','m',0325,0276,016,0321,06,0305,0235,0307,0371,'p',0,0,0,0,0,0356,'y',')',0275,033,'c','g','k',026,0206,'~',0245,'5',0313,0327,'{',0252,0266,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,017,'-',027,0352,0370,0375,0306,0234,0214,0335,0340,'X',0263,0275,'/','@',0,0,0,0,0,0,03,0222,'G','s',06,0332,0221,0323,0256,'I','M',027,'=','~',',',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,01,0345,0242,0375,'A',031,0275,'Q','1',';',0374,'z',0336,'h',0,0,0,0,0,0,0,0,0,036,0237,'i',0267,0244,'4',0373,0336,'_',0235,0310,0262,'"',0,0,0,0,0,0,0,0,0,0,0,0,0,0,01,0361,0345,'U',0204,'~',0337,'@',0304,0364,010,0375,0274,0320,'>','<',0257,0305,'o','0',0,0,0,'v','=',0372,07,'K',0300,0,0,0,0,036,0237,'i',0271,0244,'t',0273,0356,'g',0233,0345,0256,0340,0,0,0,0,0,0,0,0,0,0,0,0,0,04,'s',036,'^',0230,0303,0330,0376,'d','t',0316,0345,0237,0272,03,0212,0235,'U',0373,020,0213,0337,'+',0230,'N',0235,0362,0364,'{','=',0246,']','~','"','_',0223,013,',',0310,0206,0222,'_',0214,0315,0335,0300,0310,0334,0303,0364,0325,'`',0367,015,'j','G',037,'o','&','?','f','J','-','b','Z',033,0213,'9',020,0307,0231,0302,0321,0223,0300,0,0,01,0232,0257,027,'d',0246,0371,0215,0247,'#',0245,0363,0357,0200,0,0,0,0,0,0,0,0,0,0,0,037,'>','U','N','E','o',0224,'<','n',0357,'i','l',0334,':','Y',0241,0327,'0',0344,0271,0235,0230,0236,0216,'.',0243,0373,0376,'4',027,0256,0342,'@',' ',0372,0274,0202,0214,0273,'Z','C','O',0236,0346,'k','Y','+',0270,'@',0,0,0,01,0323,'M',0310,0216,',',0375,']',0201,0266,0325,'q',0373,'l','f',0324,0207,0,0,01,0364,'[',031,0332,0256,0311,0316,0362,0234,0235,0334,' ',0,0,0,':','N',0260,0,'9','=',07,' ',0,0,0,03,0313,'E',0375,'g',0201,0353,'U',026,06,0331,'1',0222,0322,'l',0351,'N','S','j','|',0323,047,0316,'?',0240,01,0,0357,0221,0371,0215,0256,0213,'K',0332,'@',0,0,0,0,0,0,0352,0362,0270,'.',026,0315,'I','E','o',0225,0206,026,0317,0324,0364,0,0,0222,']',0300,0332,0335,0203,0220,'K',0362,0340,0,0,016,014,'1',011,'#','~','<',036,'y',0327,'E','=','T',0322,0363,0316,0332,0353,0365,0334,0256,0334,0365,' ',0,0,0,0,0302,0331,0221,0325,'m','{',0260,0300,0261,0246,0304,0326,'O','E',0265,'/',0362,0353,'3',0346,0331,'0',0,020,0276,0321,0203,0354,0350,026,'-','0',0,0,0,0,0,0,0,04,'G',022,'z',0204,0210,0350,0325,'^',016,0323,0360,0,0,0367,0373,'o','i',0247,0271,'5',0227,'#',0247,0200,07,'Y',01,'+',0312,'i',0301,'`','c',0341,'b','q','|',030,026,'z',',',0323,0363,'o',0307,0216,0313,0365,'M',0366,0371,'K',0217,'.',0374,0330,0,0,0,030,'+',022,'z',0213,0256,'v',0230,0265,0231,020,'&',0262,'z','-',0251,0177,0227,'Y',0237,'6',0311,0200,0,0205,0366,0214,037,'g','@',0261,'i',0200,0,0,0,0,0,0,0,07,04,013,07,'h',0326,0270,'>',0245,021,0263,'&',0,03,0275,0346,0317,0316,0362,0273,'j','O','G',03,0340,0255,0312,0307,016,0304,'G','Z',0216,0307,0305,0332,0342,0237,0,03,0333,'#','r',0306,0334,0245,0357,033,0225,0345,0,0,0,014,025,0211,'=','E',0327,';','L','Z',0314,0210,02,'k',047,0242,0332,0227,0371,'u',0231,0363,'l',0230,0,010,'_','h',0301,0366,'t',013,026,0230,0,0,0,0,0,0,0,0,01,0344,0242,0375,01,013,0323,'h',0350,0315,0343,0251,0350,0,'w',0274,0331,0371,0336,'W','m','I',0350,0374,020,'"',0241,0301,0306,0205,'j',021,0235,030,0264,0200,0,0354,0277,'T',0337,'r',0223,0267,'3',0262,'l',03,0220,0,0,030,0373,'y','z','}',0255,'v',0350,0205,0211,'@',0,0232,0311,0350,0266,0245,0376,']','f','|',0333,'&',0,02,027,0332,'0','}',0235,02,0305,0246,0,0,0,0,0,0,0,0,0,'p','q',0347,0265,0254,'~',0337,0253,0220,']','c',035,'M',0320,0,0357,'y',0266,';',07,' ',0315,'H','j','T',0346,'5',0230,016,0235,025,0346,0302,0240,0,07,0325,'~',0313,'6',0314,0373,':','_',':',0327,0365,0332,0,0,03,0242,0233,0272,0243,0256,'v','j',0323,023,'b',0,016,0367,0227,'T',0357,'+',0314,'Q',0244,0331,0237,'6',0311,0341,0263,0251,0325,016,0307,0206,'=','6',0233,'!',0313,'r',0372,0272,'v',047,0263,0240,'X',0264,0300,0,0,0,0,0,0,0,0,0,04,'G',026,'{','T','u',0356,0301,033,0265,0236,0,023,0331,035,'.','y','3',0311,'+',0355,'J','#',037,027,'h',0,07,'>',0244,033,'&','e',0215,0260,0310,0334,0236,0373,0355,0,0,0,'5',0346,017,0250,0320,0261,'{',0340,0,'w',0274,0331,0371,0336,'W',')',0223,0321,0353,0230,0232,0254,0317,0233,'d',0342,'S','4','S',0233,0305,0213,'s','K',0275,0256,0335,';',027,'+',0207,'U',0351,0223,'O',0263,0240,'X',0264,0300,0,0,0,0,0,0,0,0,0,0,0301,'X',0223,0324,']','s',0264,0305,0254,0310,0201,0230,0277,023,'j','l','<','Z',')',0256,0353,0230,'h',',','`',0,03,'-','7',0221,'`',0355,'2',0227,'-','u','g',0,0,0,012,0373,07,'i',0324,']','w',0261,0365,'=',0,'}',033,'?','7',0313,'m',0371,']',022,034,'W','1','5','Y',0237,'6',0311,0341,0363,0251,0322,016,0375,037,0352,0263,0355,0317,0242,0337,0371,0365,'j','M',0333,0366,'t',013,026,0230,0,0,0,0,0,0,0,0,0,0,03,05,'b','O','O','5',0256,0333,037,0267,0233,0355,0273,0203,'i',0354,034,'w',033,031,0251,'F',0265,'|',036,'<',0,0,0366,0310,0334,0236,0356,022,0326,0355,0353,0223,020,0,0,03,0303,'o',047,'L',0365,0216,0351,031,0265,' ',0,033,01,'+',0240,0337,0363,'|',0303,0222,034,'W','1','5','Y',0237,'6',0311,0212,0327,'j',0265,034,0224,0242,'w',0256,0334,0231,'A',0334,0205,0366,0214,037,'g','@',0261,'i',0200,0,0,0,0,0,0,0,0,0,0,04,'C',022,0177,'P',0365,0356,0307,'?',0234,0345,']',0364,'h',0360,0375,'>','7',0342,0337,0200,0,';',0262,'j',0234,'n','R',0266,0216,'e',0373,034,0372,0,0,0,'5',0276,07,0253,'Q',0361,0273,0270,0,'Z',0271,0272,0306,0324,'l',0134,'o',0357,0332,'D','8',0256,'b','j',0263,'>','m',0223,0206,0316,'[',0323,0336,0335,0205,'g',0352,'W','g',0332,0345,0333,0237,'E',0277,013,0355,030,'>',0316,0201,'b',0323,0,0,0,0,0,0,'>','O',0240,0,0,0,0,'>','J','r',0304,0244,'*',0334,',','#','M',0211,0350,0305,0244,0,07,0325,0317,'f',033,'t',0215,0213,'+',0231,'m',0235,0300,0,0,04,'O',026,'w','M','5',0256,0335,0346,0362,0240,04,0202,0346,026,0346,0354,0374,'3',047,'w',010,010,'q',0134,0304,0325,'f','|',0333,047,0207,0316,0247,'Q',0373,'F',025,0265,0246,'_',0226,0303,'W','d',0352,0267,'a','}',0243,07,0331,0320,',','Z','`',0,0,0,0,0,0,0,0,0,0,01,032,')',0273,'t','@','5',010,0234,'|',']',0240,0,034,0372,0221,0354,0331,0263,0351,0371,013,0227,0337,'r',' ',0,'p','r',0,'5','[',']',0354,0225,'F',016,0322,0,0373,'6',0317,'`',0344,'6','T',0206,0240,0,0207,025,0314,'M','V','g',0315,0262,'~',014,0237,')',015,0373,034,'L','!','+',0263,0265,';',0320,0276,0321,0203,0354,0350,026,'-','0',0,0,0,0,0,0,0,0,0,0,06,'0',0246,0374,0362,01,0254,0304,0372,0264,0235,027,05,0235,0262,'x','2','3',0300,03,'/','7',0221,'=',0332,'e','.','*',0352,0221,0,0,'8','9',0,0210,0342,'O','i',0226,0265,0333,0272,0236,0200,'-',0214,0355,'W','i',0366,'.','9',0310,0,0207,025,0314,'M','Y',0276,023,'!',017,0233,0267,'P','n',0326,05,0221,0253,']',0276,'9',0336,'L','/',0264,'`',0373,':',05,0213,'L',0,0,07,07,' ',0,0,0,0,0,0,03,0316,'T',05,'{',021,0205,025,0324,'"',0345,0220,0272,'N','O',027,'_',0216,0311,'n',0230,011,015,0217,0343,0332,0207,0262,'B',0344,0357,'p',0226,0266,0357,0334,0233,0,0,07,07,' ',032,0273,0257,'v',012,0207,03,'m',0,'z','}',0247,'u','v','~',027,'"',0310,0210,0,010,'q',0134,0304,0325,'=',0371,0326,'K',0303,0221,0346,033,'>',0236,0272,0231,'l','/','d',0221,'u',0302,0373,'F',017,0263,0240,'X',0264,0300,0,0,0,0,0,0,0,0,0,07,0311,'Z',0225,0226,'%',0210,'6',0231,025,0325,0213,'D',0316,033,'D',0363,0134,0313,0313,'b','k',0336,'+',0362,0220,0371,0215,0357,0234,0233,0263,'m',0316,'S',0317,'N',0345,0261,0371,'P','Y','k',0270,'@',0,0,03,017,'f','G','H','u','n',0365,0345,0362,0240,05,0317,'#',0246,0354,0314,0377,0,'$',0,01,016,'+',0230,0232,0254,0317,0233,'d',0343,'r',0224,'h',0327,0320,'Q',0371,0254,012,0255,0255,'2',0366,0312,0362,0274,0270,'_','h',0301,0366,'t',013,026,0231,0300,07,' ',0,0,0,0,0,0,0,0,'"','E','C','n',0210,036,0243,025,0216,0212,0263,0367,'M',023,0330,036,'g',0200,0317,0332,0373,0350,0307,0356,0243,026,')','3',0272,0312,0266,0311,034,0214,0216,0307,'T',0353,0275,0237,'`',0244,0364,'k',0272,'_',0236,0,0,0,012,'>',047,0240,'k','|','/','M',0,'w','<',0335,'m',0237,0205,0311,'2','a',0300,0,'C',0212,0346,'&',0253,'3',0346,0331,'<',024,0205,':',0341,0324,'q','v',07,0233,0344,0344,'1','}',0315,0340,'U',013,0355,030,'>',0316,0201,'b',0323,'8',0,0344,0,0,0,0,0,0,0,0,'1',0205,'3',0347,0220,035,'z',':','=',0255,0341,0372,'-','X',0312,'b',0304,'z',0354,0341,0347,'0','u','O',0237,'n','B',0247,':','.','G','f',0226,0225,0354,'3',0265,'v',0277,0331,'0',030,0233,04,0322,0374,'N',0345,'m',034,'%',0357,0237,'@',0,01,0301,0247,'z',0307,'q',0202,'c','N',0,',',0354,0315,'k','l',0266,'N','.',0,0,'C',0212,0346,'&',0253,'3',0346,0331,'<','6','u',':',0241,0330,0360,0305,0227,0252,0335,0277,'y',0306,'L','/',0264,'`',0373,':',05,0213,'L',0,0,0,0,0,0,0,0,0,035,'E','J','W','q',0270,0220,0315,':','7',0233,'T','L',0341,'t','/',']',0230,0317,06,'D',0316,047,'.','{',025,0227,'+',0351,0227,0313,0234,'m',0322,0361,'(',0276,0227,'^',0304,'t','N',017,0263,'u','6','n',033,'&',0311,0205,0373,0367,0300,0,03,015,'f','K','G',0265,'^',0365,0322,0364,01,0265,0323,0334,0232,0322,0222,0322,0300,0,010,'q',0134,0304,0325,'f','|',0333,047,0341,0310,0362,0201,0350,0370,0333,031,0314,'2',0200,0205,0366,0214,'/','g','@',0307,0264,0300,0,0,0,0,0,0,0,0,01,04,'*',0213,026,0240,'z','l','O',0227,06,0217,']',0234,'Y',0254,'/',';',0350,0257,'3',027,0225,'7',0351,0267,0203,027,0330,'7','y',0316,0347,'+',0321,'F',0337,'T','k',0375,'{',0315,'M',0360,'6','2','c',0234,'^',0223,034,0344,0,0,025,'$','^',0363,0253,'P','}','P',01,0223,0252,0326,0360,'m','|',03,0333,'^','0',0,01,016,'+',0230,0232,0254,0317,0233,'d',0360,0371,0264,0351,'/','|',0300,0231,'A',0327,'d','j',0327,'o',0216,'w',0223,012,0355,030,'~',0336,0201,0215,'i',0200,0,0,0,0,0,0,0,07,036,'9',0365,0210,')','j','|',0200,'j',0361,'x','h',',','o',']',0254,'_','e',0234,'<',0374,'~',0247,0356,0261,023,0321,'^','|','B','s','}',0220,0356,0223,0263,0331,'l',0330,'|',017,'V',0246,0343,'w','p',05,0215,0227,0257,0355,0326,0313,0304,0200,0,01,0254,0260,035,'n',0231,0216,0334,0200,026,0266,'v',0257,0265,'[',027,032,0,0,04,'8',0256,'b','j',0263,'>','m',0223,0351,0255,022,0232,0266,'2','x',0225,'H','#','j',0204,'v',0234,'?','~',0377,0,0215,'i',0200,0,0,0,0,0,0,0,07,0307,0236,'|',0373,0355,'D','V',0360,0370,'1','-','K',03,0356,0335,0271,0244,'.',0203,0341,0277,')',0331,'M',0214,'v','L',0276,'/','*','W','+',0263,'I',0316,0366,'I','+',0223,0337,'a',0361,0373,0206,0245,'k',0375,'t',01,0220,0366,0336,0363,'m',0237,'>',0372,0253,0260,0,03,0203,'L',0265,'n',0361,015,0261,'*',0,0331,0331,0276,'_','q',0312,0350,'@',0,0,0207,025,0314,'M','V','g',0315,0262,'x',0274,0277,'4','w',0350,010,0357,'=',0305,0273,0245,0337,0332,036,'I',0227,012,0355,030,'>',0336,0201,'b',0323,0,0,0,0,0,0,0,0,01,05,'*','L','k','0','=','.',047,0243,026,0237,'}',0214,031,0244,047,'8',0371,0366,0347,'*','#',022,0233,0277,0217,'a',0330,0247,0233,'|',0265,0261,'r',0271,0251,0340,0267,0225,0243,'Z',0247,0320,'>','?','*',03,0223,'t','6','^','%','/',0313,0327,0300,0,'y','h',0277,0243,032,0237,0320,'~',017,'+',03,0223,'t','6','^','%','/',0313,0327,0300,0,01,016,'+',0230,0232,0254,0317,0233,'d',0340,';',035,0272,'c','z',0307,0227,'B',0327,017,0233,0243,'i',0371,016,'d','/',0264,'`',0373,':',05,0213,'L',0,0,0,03,0203,0220,0,0,0,014,'Y','J','S','M','w',0252,'E','b',0241,'l','w','Q','k',0327,'k',023,'1',0205,01,0312,0254,0226,'4',',','K','a',0350,022,0375,0342,'z',0306,0314,0277,'h',0237,'g',06,0231,'j',0335,0342,033,'b','T',01,0264,0263,0234,0256,0333,0224,0321,0200,0,'F',0261,0246,0264,0233,'X',0356,0177,' ',036,0337,'i',0336,'}',0263,0347,0317,'e','x',0340,0,0,0207,025,0314,'M','V','g',0315,0262,'x',0254,0312,'`','[',035,0272,'3',0240,'c',0335,'Z',035,0373,'o','L',0277,013,0355,030,'>',0316,0201,'b',0323,0,0,0,0,0343,0307,'>',0200,0,0,07,0301,'T',025,'d','.',04,'W','T',0301,0355,0265,'f','g',013,0240,'{',',',0304,0341,'s','v',0217,025,0371,'?','.','F','f','g','v',0330,0347,0263,031,0327,031,0353,0,0326,015,0177,0257,0323,0321,0373,'p',02,0375,0225,0320,'v',016,'o',0230,0,0,0257,'0','6',0315,'B',0327,0273,010,02,'U','v',';','u','v',0256,011,0317,0276,0,0,02,034,'W','1','5','Y',0237,'6',0311,0351,0217,'t',0300,0264,'5','+',0326,0206,0245,'z',']',013,'X',0205,0366,0214,037,'g','@',0261,'i',0200,0,0,0,'q',0343,0237,'@',0,0,02,'&','R',0330,0266,' ','Z',0134,'W','N','5','2','(',0355,'k','!',0217,033,0351,0265,0205,0335,'F',06,06,'C','m',0363,'m',0373,'|',0363,'g',0224,0270,0352,0367,'>',0,'(',0210,'n',0221,0256,0321,035,024,01,'n',0347,0352,'{','G',0260,0361,0340,0,025,'d','n',0353,0252,'P','=','`',01,'d',0345,0353,0333,'o',0262,0361,'0',0,034,034,0202,034,'W','1','5','Y',0237,'6',0311,0301,0266,013,'u','V',0341,'g','_','z','V','-',0307,0243,0344,'m','o',035,0314,0205,0366,0214,037,'g','@',0261,'i',0200,0,0,03,0316,'b','O','1',0330,'g',016,0360,0,07,0220,0245,')',0246,0262,0324,0342,0261,'P',0326,'=',0226,'p',0362,0230,0261,'}',0224,0331,0314,'a',0353,'}','U','e',0306,'6',0235,0376,'q',0272,'M','Z','w',0256,'O',016,'@',05,'Q',031,0273,0352,0264,027,'V',0,'Y',0271,0232,0346,0331,0354,0234,'T',0,05,047,021,0320,0265,0256,033,0245,0200,'-',0234,0355,'W','i',0366,'.','8',0,03,0203,0220,'C',0212,0346,'&',0253,'3',0346,0331,'=',027,0372,016,';',0242,0342,0353,0320,0362,'-',0315,'.',0364,0242,'"',0270,'_','h',0301,0366,'t',013,026,0230,0,0,017,021,07,'!',0236,'y',0205,0263,'o',0307,'b',0337,0262,0375,0311,0265,0373,0266,0311,0366,0,'8','+',0202,0234,0206,0301,0211,0352,'x',037,'v',0355,0313,'"','t',0274,'n','L',0276,'/','*','^','I',033,0251,'b','d',0266,031,06,0371,0264,0330,'r',031,'V',0311,0330,0,05,'q',037,0267,'j','6',0277,0327,0300,023,'K',0361,';',0231,0264,0360,0200,0,024,0234,'G','B',0326,0270,'n',0226,0,0275,'$',0364,'m',0214,0235,0345,'`',0,'8','9',04,'8',0256,'b','j',0263,'>','m',0223,0244,0367,0334,'z',0277,'m',0265,033,0224,0242,0357,0320,'r','/',036,0177,0221,013,0355,030,'>',0316,0201,'b',0323,0,0,'p','F',012,0313,0317,'#','8','v','#','P','8','8',0270,0253,037,026,'|',0356,0312,0252,'w',0270,0312,0337,'9','w',0363,0240,03,014,'Q','X',0326,'`',032,'L','6','B','*',023,0305,'{','>','g',013,0316,'|','w',0244,0342,0322,0273,0257,0222,0376,0134,0223,'g',0315,0236,'O','H',0134,0336,0373,0221,0,0,'D',0361,047,0364,0257,'Z',0355,0300,011,0245,0370,0235,0314,0332,'x','@',0,012,'N','#',0241,'k',0134,'7','K',0,'^',0222,'z','6',0306,'N',0362,0260,0,0340,0344,02,034,'W','1','5','Y',0237,'6',0311,0352,'o','e',0302,0201,'l','V',0375,0370,0336,0337,'|',0353,'&',0345,0321,0257,0302,0373,'F',017,0263,0240,'X',0264,0300,0,021,'b',0245,0247,0310,0214,'&',04,'s','[',0302,0353,0263,0340,03,'1','9',0221,'z',0355,'R',0266,'_',0276,0201,0360,'T','T',0371,'O',0352,0261,'^',0375,'G','K',0365,'Y',0302,0305,'e',0316,0370,'o',0347,0311,'c','4',0376,'^',0307,0267,016,0203,'<',0333,0245,0356,012,0352,0224,0200,0,04,'O',022,0177,'J',0365,0256,0334,0,0232,'_',0211,0334,0315,0247,0204,0,0,0244,0342,':',026,0265,0303,'t',0260,05,0313,'!',0247,'l',0336,0301,0310,0300,03,0203,0220,010,'q',0134,0304,0325,'f','|',0333,047,'S','n','V','l',0255,'Z',0357,0277,033,0320,'!','}',0243,07,0331,0320,',','Z','`',0,'u',0224,0271,'^',0302,0340,'E',0265,'L',036,')',0360,0,';','r','=',0265,'7',0211,0213,0342,0375,0336,0360,'E',012,026,047,012,'=',0244,'k',0263,'(','>','s',0205,0315,0332,0362,030,0360,0261,')','}',0353,0335,0217,037,0341,0223,0230,0231,0356,0363,'v','f',']',0373,',',0344,0,0,' ',0230,';','>',0235,'k',0275,0230,01,'4',0277,023,0271,0233,'O',010,0,01,'P','E',0357,'z',0275,07,0324,0200,026,0246,'n',0261,0265,0233,037,031,0,016,016,017,0240,'C',0212,0346,'&',0253,'3',0346,0331,'0',0,020,0276,0321,0203,0354,0350,026,'-','0',0,':',012,'6',0237,'*',0355,'6',037,0303,031,'h',0,0,0226,0355,0322,027,0374,0316,'t',0260,0363,024,'u',0213,'U','V',0231,023,0365,033,0205,',',0210,0321,0262,'8',0360,030,014,0375,0327,0321,'o',013,0311,0221,'!',0335,0277,0357,'V',04,0316,'u',0306,'z','@',0,0,'V','q',0333,0216,0245,0300,'u',0300,05,0203,0225,05,0267,0373,'7',017,0,01,'Y',0307,'n',':',0227,01,0327,0,023,'[',0361,';',0227,0264,0360,0200,0,0340,0371,'>',0301,016,'+',0230,0232,0254,0317,0233,'d',0300,0,'B',0373,'F',017,0263,0240,'X',0264,0300,0,0371,')',0177,'<',0250,0264,0370,0214,'t','M',0220,0,03,'#','+','z',0336,0334,'%',0356,':',0275,0256,0374,0362,0216,0326,0243,'0','Z',0366,'(',0373,0362,0231,04,'v',0263,'"',0216,0323,'|','w',0245,'0',';',0267,'J',0235,'m',0223,'7','5','^',0347,'@',0,0,012,'R','#',0241,'k','T','7','K',0,'Z',0231,0272,0306,0326,'l','|','d',0,04,'C',023,'a',0322,0355,'k',0266,0,'2',0265,'Y',0336,'M',0263,0347,0336,0372,0255,0,'8','8','>',0201,016,'+',0230,0232,0254,0317,0233,'d',0300,0,'B',0373,'F',017,0263,0240,'X',0264,0300,0,025,0251,'H',0353,0221,0221,0375,'o',020,0,0,0372,0271,0354,0353,'v',0224,0232,0346,0344,0302,'c',0261,'`',0332,'l','g',0315,0277,0,031,014,'|',016,0334,0353,0263,015,0347,'c',0265,0262,'.',0317,'@',0,0,01,0255,0260,'=','^',0221,0215,0335,0200,027,0214,0236,0221,0261,0363,0274,0244,0,06,'6',0326,'n',0214,0352,0237,'@','y',0300,'>',0336,0356,0376,0321,0301,0263,0331,021,'@',01,0301,0310,'!',0305,'s',023,'U',0231,0363,'l',0230,0,010,'_','h',0301,0366,'t',013,026,0230,0,02,'.','P',0221,0230,0220,0255,'2','1',0340,0,0,0312,'L','_',0222,'l',031,0261,'-','Z','?',0311,0201,'l',0,'9',0257,0331,0206,0337,'#','c',0312,0346,'[','g','h',0,0,0,'5',023,'Y',0355,0325,0326,',',0370,03,'e','f','y',0235,0327,'/',0317,0200,0,'|',0371,0356,0222,'j',0235,0376,'9','o','4',01,0266,'3',0374,0222,0317,0221,0323,'@',0,01,016,'+','h',0357,'l',0377,0,0232,0245,024,0200,02,017,0333,0360,'2',033,0315,0233,'L',0,01,0344,'(','[','6',0353,035,032,037,0253,036,0220,0,01,0353,0352,0257,'~','h',0360,0,06,'n','{','&',0300,0332,'%','.',0237,'}',0312,0,0,0,03,0246,0233,0232,';',0251,0375,05,0207,0246,0370,03,'p','6','.','9','`','g','j',0240,0,06,0250,'k',0235,0232,0256,0302,0331,0300,027,0214,0236,0217,0261,0363,0274,0250,0,0,030,'R',0222,0361,'b','q',014,0354,0306,0217,'|',01,0346,0230,0242,0264,0372,022,':',0304,0314,0362,'v',0,0,0340,0250,0374,0362,0231,0324,'b','q','P',0366,0,0,0,0,0,'z','s','k',0237,'n','r',0326,0365,0373,0263,'0',0,0,0,010,'~','&',0301,0246,':',0327,'m',0371,0,0357,'7',0217,'k',0340,'9','k',0270,0,0,05,031,017,0321,0265,0312,037,0243,0200,'%','7','c',0267,'S','j',0340,0277,'~',0322,0,0,012,0270,0205,0320,0316,'j',0227,'}',030,025,016,0273,0376,'a','v',0273,'y',',',0272,'n','c',0274,0,0,'!',0305,013,015,0203,022,0324,0243,0336,0,0,0,0,037,'U',0373,'1',0334,'$','l',0331,'L',0313,'T',0373,0,0,0,0,0241,'a',0272,'V',0274,0304,'t','0',04,0276,0364,'f',0350,'m','<',033,0237,'|',0,0,'!',0370,0233,06,0230,0353,']',0267,0344,03,0350,0334,0335,0227,0211,'L','r',0365,0360,0,0,'p','D',0310,0351,0362,01,0227,'&',0207,'p',0,0,017,011,'A','c',0332,0255,0264,'x','~',0273,036,0,0,0,0,'3',0233,06,'U',0213,0263,'I',0335,036,0373,0357,0,0,0,0,0371,0363,0335,'4',0325,0373,0274,'2',0304,0250,02,0361,0223,0321,0366,'>','w',0225,0,0,03,0246,0233,0232,'K',0252,0367,0330,0375,0274,0300,05,0345,047,0243,0354,'t',0357,'*',0,0,07,'A',02,'0',047,0,031,'r','|','{',0200,0,0,'p','T','>','y','M','j','1','8',0270,'{',0,0,0,0,'z','s','k',0260,'7','I','{',0222,0365,0311,'X',0,0,0,0,0207,0342,'l',032,'c',0255,'v',0337,0220,01,0267,'{',017,037,0261,'s',0365,' ',0,0,015,'p',0202,0352,0324,'t','f',0356,0,0313,0327,0217,0273,0273,'W',03,0366,'W',0214,0,03,0254,0246,'L','f',017,0262,'-',032,0377,0,'v',035,'C',0342,0377,0,0221,0375,0332,0307,'2',0324,0335,0207,0254,0,0,04,'D',0241,'b','0',0241,0372,0204,'s',0300,0,0,07,0325,'~',0313,0366,0371,033,'V','W','2',0320,'>',0200,0,0,0,06,0265,'@',0365,0212,'R','7','u',0,'f','k',0307,0335,0375,0257,0200,'z','*',0262,0,0,01,013,0303,0330,0264,0327,'[',0355,0177,' ',03,'e',0346,0271,0235,0323,'-',0317,0200,0,'D',0312,0242,0322,0316,0371,0342,'G',0325,07,'p',01,0327,0235,'M','g',0364,'L','t',0352,'F',0233,04,0,0,07,0220,0241,0354,0333,0254,'t',0210,'~',0214,'Z','@',0,0,'3','3',0271,'6','V',0321,')','t','U',0357,0264,0,0,0,0,'a',0354,0310,0351,'6',0255,0335,0374,036,']',0,']',0322,'Z','N',0311,'O','r',0200,0,0,01,0361,0345,'Z','q',0254,'w','8','N','<',0300,02,'C','s',013,'u','v',0236,015,0352,0256,0300,0,'@','H','n',0273,'r',0305,0371,0346,'D',0,04,'#',0266,0340,0373,0367,0273,026,0230,0,0,01,'X','x',0245,'u',0310,0314,06,0271,0210,0,0,017,'F',']','v',06,0351,'-','t','d',']',0224,0,0,0,0,01,0256,0320,'}','J',0210,0213,0336,0300,037,'f',0346,0354,0274,'F','a',0227,0,0,0,0,05,'M',031,0274,'j',0304,027,'U',0,015,0216,0230,0346,0367,0224,0307,':',0,010,011,017,0326,'n','X',0177,'>',0310,0200,0,0205,0366,0214,037,'g','@',0261,'i',0200,0,0,030,'r',0207,0306,0263,'^','i','1','=','X',0364,0200,0,0346,0257,'e',0273,'t',0205,0271,'/',0233,'f',037,'@',0,0,0,02,'?',0217,'+',0245,0332,0307,'s',0360,'y','t',01,'d','e',0353,0333,'o',0262,'q','N','}',0360,0,0,0,016,0232,'n','i',0216,0257,0335,0242,'v','d',0300,031,'J',0254,'n',0206,0317,0303,'3',0227,0343,0,020,'r',0274,0217,0366,0317,0371,0262,'O',0233,'^',0200,036,0253,0337,0240,'c',0244,033,'5',0273,'4',0,0,0,0340,0254,'|',0362,0240,0205,0301,0214,'k',030,'?','4','x',0363,0336,016,'}',0363,0262,0365,'Y',0351,0354,0253,022,'~','F',0346,0253,0337,'X',0,0,0,0,0343,0317,'u','g','^',0354,'U','6',016,0324,0,0372,'7',013,'c',0343,023,0314,0335,'d',0,0,0,0,'*','h',0315,0343,'V',' ',0272,0250,0,'Z',031,0232,0326,0327,'l','|','g',0353,0332,'@',0307,024,'q','!',0321,'/',0313,'9','v','W','v','/',0243,0342,0362,'7',0320,0261,0241,0375,'7',032,0345,0365,'!',0,0,0,07,0220,0251,0374,0362,'%',0215,'k',0313,'n',0216,0273,'t',0374,0322,0364,']',0367,'1',0221,'z','_','z',0273,03,0337,'r',' ',0,0,0,0,'U','q',0273,0256,0252,0300,0365,0217,0220,01,'d','e',0353,0333,'o',0262,'q','N','}',0360,0,0,0,0,'>','<',0253,'O','u',0236,0343,04,0306,0232,0,'r','l',0304,0327,'2',0271,0345,0271,0370,02,'0','U',0247,0207,0300,03,0321,0352,0311,'&',0300,0,0,0,03,0340,0361,0235,'G',0301,0301,0334,'{',016,0323,0220,0,0,0,0,'0','6','%','4',0327,'Y',0356,030,'z','2','@',035,0317,'7','/','e',0342,'2',0374,0270,020,0,0,0,0,02,037,0211,'?',0247,032,0337,'l',0363,'y','P',03,0331,0355,0275,0271,0330,0270,0344,0357,'7','Y',0,'|',0236,03,0200,017,'q',0330,0,0,0,0,0,0,0,0,0,0,0,0,'y','h',0277,0250,0232,0337,'l',0202,'c','M',0,05,0363,')',0242,'l','<',0347,'-',0,0,0,0,0,0,0240,0341,'z','f',0275,0304,0364,020,0,0315,'W',0213,0270,'{','/',023,0221,0344,'D',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'|','y','V',0256,'k',0335,0206,0245,0301,0332,0200,02,'[','z','3','r','v','~',031,0352,0256,0300,0,0,0,0,0,07,0236,0233,0272,0203,0254,0366,0370,'.','<',0310,0,'J','o','G','m',0326,0307,0305,0263,0267,0343,0,0,0,0,0,0,0,0,0,0,0,0,0,0,017,0217,'*',0327,030,'.',0255,'H','F',0356,0240,01,0351,0366,0235,0277,0330,0370,0274,0337,'3',0134,0344,0,0,0,0,0,0,021,0314,'y','}',';',0326,0273,'f',032,0214,0240,0,0224,0336,0216,0333,015,0207,0216,'I',0362,'a',0200,0,0,0,0,0,0,0,0,0,0,0,0,03,0317,'M',0335,'q',0202,0352,0324,0254,'v',0344,0,037,'F',0311,0314,0363,'K',0256,'_',0236,0374,0370,0372,0364,0,0,0,0,0,0,04,03,07,'h',0324,0255,'{',0260,0370,0374,0270,0,031,0232,0361,'v',0242,0177,0222,'O',0363,0265,'p',0,0,0,0,0,0,0,0,0,0,0,0,'1',0326,0362,0365,'o','^',0354,025,0246,'&',0304,0,02,0355,0222,0322,0266,'J','w',0224,'s',0357,0200,0,0,0,0,0,0,0,'*','h',0315,0343,'W',0340,0272,0247,'C',0320,0,0364,0373,'N',0304,'K',0363,0213,0262,'_',0236,0375,0373,'H',0,0,0,0,0,0,0,0,0,0,0,'!',0230,'{',016,0256,'@',0365,0270,0255,0231,020,0,026,0226,'n',0263,0262,0263,0374,0223,'3','s',014,0,0,0,0,'8','9',0,0,0,05,'K',031,0274,'k',04,027,'T',0350,'z',0,02,0307,0313,0327,0366,'Z','w',0224,0310,0362,'"',0,0,0,0,0,0,0,0,0,0,03,0317,'M',0332,'.',037,0243,0320,0221,'[',0377,0,0233,0312,0200,0,'Z',0271,0272,0306,0321,0354,'<','{',0321,'U',0240,0,0,0,0,0,0,0,0,01,'T','F','n',0332,0311,07,0324,0374,'>',0134,0,01,0357,0366,0325,0343,')',0242,'^',022,0374,0367,'!','s',020,0,0,0,0,0,0,0,0,03,0343,0312,0253,'|',015,0267,']',0241,'z','d','N',0314,0220,0,01,'o','g',0352,'{','5','?',0310,0375,025,'Z',0,0,0,0,0,0,0,0,0,0,'A','0',0266,'m','T',0327,0372,0356,026,0214,0240,0,03,'/','^','=',0341,')',0241,0334,'r',0232,'.','Z',0356,0,0,0,0,0,0,0,0,'t',0323,'r',0270,0300,0333,'h','h',0216,0205,06,0307,0232,0340,0,01,0366,'_',0262,0272,015,0373,'5',0314,0276,0375,0244,0,0,0,0,0,0,0,0,0,0,06,06,0304,0246,0257,'@','u',0312,0373,026,'t',0,0,036,0377,0,'m','Y',0371,0332,0275,0273,'%',0246,'O','s','u',0217,'E','V','@',0,0,0,0,017,0237,'=',0214,0343,'M','U','1',0373,0215,'I',035,0270,0306,'-','H',0,0,03,'+','U',0215,0232,0234,0345,0226,0204,0226,0231,0310,0,0,0,0,0,0,0,0,0,0,0,016,0252,'k',0244,0242,'z',036,0277,'D','t','?',027,0227,0,0,0,'3','5',0343,0330,'9','z',0344,0377,0,'3',0134,0230,'d',0302,0311,'r','!',0375,0367,'1','>',0375,0244,0,'>','|',0367,0317,'M',0354,'%',0231,'8','v',',',0344,'+',026,'v',0271,0302,0331,0342,'v','d',0376,0,0,0,'r','Y',0371,0232,0326,0312,'N',0362,0254,0345,0370,0300,0,0,0,0,0,0,0,0,0,0,0,0,04,'[',032,'o','[',0340,0372,0225,'s',0211,0260,'p',0,0,0,01,0350,'2',0225,0343,'f','.','a','e','n','b','z',0352,0262,'0','6',0244,'<',024,'d','a',0355,0346,'x',0274,0257,0344,0,0,0,03,'=','s',017,'a','f','9',0305,0267,047,0243,0375,'{','H',0,0,0,0,0,0,0,0,0,0,0,0,0,017,0237,'*',0255,0360,'6',0332,016,037,0242,'A',0261,0346,0270,0,0,0,0,0,0,0,0,0,0,031,'z',0361,0357,011,'M',016,0351,0225,0320,'r',027,'1',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,07,0307,0225,'W',030,033,'m','!',025,0276,0327,0330,0233,07,'K',0320,0,0,0,0,0,0,0,03,0222,'G','s',06,0347,0224,0321,0356,'Y','M',017,'!','s',020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,07,04,'s',036,'b',0251,0216,0334,0252,0310,0375,0272,'%','b','S',0245,0350,0,0,0,0,0,07,'&','n',0274,'k','+',';','W',0265,0344,'4',0351,0356,'n',0261,0335,'U',0260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'8',0363,0334,035,0231,'8',016,026,0313,04,0304,0330,'"','8',0363,'Q',0213,022,0230,0372,'o',0365,'<',0,0,'>',0217,'_',0264,0347,'n','`','K',0362,'a',0246,0231,'P','V',06,'f',0267,'-',0312,0201,0356,0252,0330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,035,024,0335,0307,'[',0314,0305,0332,0316,0304,'[',0315,0363,'S','t',01,0235,0275,037,0356,0257,033,'+','v','?',0327,'U',0216,'}',0360,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,'p','r',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,07,0377,0304,0,'3',020,0,01,04,01,02,05,03,03,05,01,01,0,01,05,0,0,04,01,02,03,05,06,0,' ',07,022,023,'0','4',021,024,'@',020,025,'3',026,027,'!','1','P','5','6','#','%','2','`','p',0200,0377,0332,0,010,01,01,0,01,05,02,0377,0,0371,'3',0231,023,0134,0355,0327,';','u',0316,0335,'s',0267,0377,0,0300,'e','.',030,'4','V','c','V','+','H',0342,'X','Q',0310,'G',023,0210,'{',047,0342,015,0244,0321,0376,0261,0266,0324,0367,0307,0221,047,0335,0315,0327,0335,0315,0327,0335,0315,0327,0335,0315,0323,'2',0353,'V','4','l',0346,0324,'w',0213,0304,0243,0243,'x',0334,'O',0213,0220,'L',0362,0254,0225,032,0340,'2',0321,025,027,0375,'o','_','M',035,'z',025,'{','l','x',0231,04,'J','~','{','d','[',0247,0260,'$',0237,0201,034,0317,0205,'B',0312,0354,0201,0320,034,'M',0221,0272,0256,0314,0353,'l','u',034,0254,0225,'?',0320,' ',0250,0205,'e',0317,020,0203,07,'V',0271,0275,0215,0222,'I','+',0346,'w',0305,0376,0265,']',0220,035,'X',0372,0256,'%',0257,'0',027,0201,0331,047,0371,0204,025,020,0254,0273,0342,',',03,'j',0316,0364,0313,'g',0374,0270,010,0224,'W',0322,'q',026,'q','u','Y','~',035,0263,'?',0310,'{',0333,033,'n','3','h',0207,'e',0231,0326,0266,0317,0366,04,'k',0330,021,0257,'`','F',0234,024,0354,'N',0323,'X',0347,'k',0243,'&',0272,'2','w',0340,'"','Q','_',0217,0361,016,'A',0365,'_','h','5',0244,'?',0342,0333,0336,0213,'M',011,'W','E','d','.','d','m',0215,0250,0305,'v',0272,'/',0327,'E',0372,'X',0334,0335,'z','z',0352,0326,0225,0263,'5','Q','Z',0277,'H',04,0230,0235,011,0205,0332,024,0341,0270,'d',0134,0214,037,0206,'B',0263,'Q',0340,'5','Q',0277,0364,0265,'f',0240,0245,010,'f','}',0264,']','}',0264,']','.','/','X',0252,'V',025,'V','V',0212,0341,0275,'|',0332,'#',0205,0353,0324,'+',0,0264,031,0245,'R',0232,022,0377,0,']',0252,0313,'r','j','f',0307,'s',0221,0355,021,027,0325,'?',0301,'s',0221,0215,0311,0263,0310,0300,'X',0345,0236,0356,0305,0255,'F','6',0266,0257,0252,0214,0215,0261,0247,0321,'Z',0213,0243,0252,0231,'+','U','9','V',0326,0232,'R',014,0255,0341,0321,0305,'j',0267,0,0256,013,'B',0327,014,033,'{',0262,'B',0311,'P',0354,'F',0264,0344,0262,0341,0223,0223,'V','8',0331,0365,'z',0376,0273,010,0252,0325,0307,'3',0271,0353,'T',033,010,',','a',0355,0254,0255,'n',0275,0324,'z',0367,'Q',0353,0335,'G',0257,'u',036,0275,0324,'z','B','#','^',0361,04,0306,'$','y','N','o','1',0357,0376,0365,0215,'5',024,0221,0343,0352,0316,0211,0312,0233,'n','b',0351,0227,0213,'y',0177,016,'H',0231,'+','m',0260,0272,0373,'6',0333,0360,0374,0332,0366,0311,023,0341,'~',0372,'k',0342,0251,'&',0240,0310,0307,0273,033,0177,0257,0246,0212,0264,0210,'d','+','"','s',0265,'-',0224,0322,'i','K','v',0224,0365,'M','}',0313,'_','s',0323,'O','W','j','2',0344,'c',0252,014,0367,'P','v',0355,'-',0207,0250,037,047,0312,'e',0275,'#',0351,0214,0376,'j',0377,0,'7','u',0367,0345,0305,'|',0337,0215,'o',0213,0203,'n',0313,0274,0,0272,0375,'9',0252,0307,'n',010,0331,'@',0237,031,0314,0207,0270,'f',0327,0275,030,0226,0227,0236,0232,0234,0245,'r',0315,'b',0326,'j','K',047,'.',0234,'S',0335,0256,0253,0265,0316,0272,0347,']','6','g','"',0204,0365,'|','x',0343,025,0260,0366,0255,0355,0340,0247,026,0376,0376,'{',0322,0276,0270,0317,0346,0257,0363,'w','_','~',0134,'W',0315,0370,0377,0,0336,0256,0360,0340,0255,0231,'y',0215,027,'I','&',0350,'f','x',0362,'a',0371,0203,'-','#',0372,0271,0310,0304,0271,0267,0346,'R',0215,'H',0365,'9',0216,0225,'}','w',015,012,0312,0360,'F',0346,'Z',0361,0375,0270,0375,0233,'{','x',')',0305,0277,0277,0236,0364,0255,0230,0317,0346,0257,0363,'w','_','~',0134,'W',0315,0371,'$',0215,021,'Q',0344,0330,07,'E','$',0215,0321,'?','l','3','<','y','0',0374,0301,0226,0221,0351,'W',0323,'W','V',0334,0250,'q',0274,0232,0226,'U',0221,0333,0230,0305,'{',0201,023,0246,0332,'*',0317,'N',0321,0307,'E','^','>','K','}','%',0331,0373,'q',0237,0315,'_',0346,0356,0276,0374,0270,0257,0233,0362,0275,'5',0222,0341,0243,0333,0260,0320,047,0257,0233,'l','3','<','y','1',014,0232,';','p',0356,'-',020,'v',034,'g',0246,0247,0231,'e','v',0344,'O','U',0,'?','M','S','V',',',0357,0215,0211,033,'{',023,0316,0301,0342,0314,0262,0177,0275,025,0266,030,'^','D',0225,0370,0264,0264,0300,'W',0371,0272,0272,')',0340,0323,0376,0352,0336,'k',0367,'V',0363,'P','q','b',0342,'7',0343,031,'$',031,'=','u',0367,0345,0305,'|',0337,0231,0220,'c',0320,'^',013,'u','B','M','$',0373,'h',05,0222,011,'L','5',']',0242,0210,'Y',0237,0274,0,0371,0226,0260,05,'&','A','F','h',0361,0366,'s',0334,0247,0235,'v',0303,013,0310,0223,017,0303,0331,'W',036,'Q',0377,0,'>',0277,0315,0326,'Z','g',0260,0306,0270,'_','K','[','g','L','F',037,'I','(',0374,'?',0255,07,'"',027,0203,0323,0253,'l',0357,0277,'.','+',0346,0374,0333,'z',0210,'.',05,0277,0240,0236,0210,0257,0255,'p','j','D',0254,'j',017,021,0245,0254,0216,0336,020,0253,'+',0202,021,'d','u','h',010,',',']',0234,0303,' ','J','Z',0371,'$','t',0262,'l','k','U',0356,0302,0261,'8',0300,037,'Y','G',0201,'_',0346,0352,0342,0271,0266,0365,'|',0367,030,'U',0221,0231,0325,0351,0343,0360,0326,0200,0252,0220,'8',']','@','u','Q',0227,0337,0227,025,0363,'~','u',0275,'D',027,02,0335,0324,'I','L','v',0205,031,'H',0220,'!',032,',','v',06,'v',06,0201,'f','x',0243,'r',0352,0232,0261,' ','g','d',0322,0330,010,0331,05,0303,0356,0254,'v',0340,0230,0242,'*','"','z','}','2',0217,02,0277,0315,0372,0134,'e',0370,0334,'n',033,'-',0303,'B','}','6','_','W','~','V',0257,0277,'.','+',0346,0374,0374,0216,0202,033,0260,0347,0255,0230,'b',0353,0,'H',030,'q','}','6',0271,0334,0313,0272,'(',0326,'G',06,'/','I',0264,'u','~',0272,'D',0364,'N',0317,020,0262,'%',0232,'m',0270,'F','4',0266,0245,'1',0211,033,'~',0231,'G',0201,'_',0346,0353,'2','"','Q','1','|','c',024,'/',')',0233,0366,'x',0275,'a',0230,024,0330,0265,0246,0257,0277,'.','+',0346,0374,037,'_',0347,0272,0253,0312,0231,',','p',024,'Y','S',0244,014,0226,'E',0221,0333,0232,0234,0312,0,0234,0211,'Q','Z',0244,0311,024,'i',023,';','9','5',0302,'R',0326,021,';',0212,0237,'e',035,'L',0227,047,0327,0203,035,'p',0277,0134,0243,0300,0257,0363,'u','r',0350,'c',0250,0302,0362,0341,'q','C',0177,'w',0252,0365,0215,'g','a',0344,0347,'j',0373,0362,0342,0276,'o',0317,0267,'=',0243,0302,'Q',032,',',0205,0231,0373,0353,0303,0365,0320,01,')','2',04,'+','E',0213,'j',0355,0317,0356,0375,0375,0216,0306,0265,'^',0354,'+',036,'J',0200,'6','e',036,05,0177,0233,0253,0,0322,0300,017,0331,0360,'u',0373,'>',016,0261,0214,014,'l',0134,0375,'_','~',0134,'W',0315,0371,0307,030,0321,'b','<',0325,'"','C',010,'Y',0244,'m','z',',','S',0212,0350,0227,'h','B',0365,0134,'(',0312,0365,0252,0256,'A','b',0334,0273,'2',0213,'v',0324,'U','K','#',0246,0223,'f',01,'F',0247,0330,0177,'[','r',0217,02,0277,0315,0313,0355,'f',0244,0307,'q',0274,0254,0333,'L','C',0367,'f',0353,'_',0273,'7','Z',0300,0363,0213,014,0226,0337,'W',0337,0227,025,0363,'~','l',0322,0244,',',0266,0260,'R',0245,0260,'/',0225,033,'"',0243,0304,'3',0253,0247,0261,036,0205,'W',0372,'i',0315,'V',0257,0320,'x',026,'g',0215,02,'F',0224,'u',0251,033,';','|','D',0266,'R',0254,0266,017,03,0212,0236,0202,0261,0265,'5',0233,'r',0217,02,0277,0315,'8',030,',',0205,016,0214,0,02,'v',037,'B',0315,'~',0223,0307,0365,'[','G','W','[','>',0257,0277,'.','+',0346,0374,0305,'^','T',0274,0264,0347,'S',010,0351,'2','Y',026,'G','"','z',0250,'p','$','q',0276,0303,0222,'X',0345,'l',0250,'H','m',0221,'$','o','#',0243,'b',0275,0301,0214,0221,'0',0353,'$',021,'j',0310,'i','@','v',0255,0213,'@','k',0211,0235,0304,0221,0263,0207,'T',0236,0350,0275,0331,'G',0201,'_',0346,0353,'$',0263,'u','5',022,'6',0313,'$','7',0364,'=',0356,0270,'i',0216,'Y','S',0336,0352,0373,0362,0342,0276,'o',0314,0272,0261,'H','#','"','}',026,'B',0314,0375,'3',0370,'t',013,0315,021,0201,'/','5','|','/','b',0232,'_','M','?',0373,0335,'^',047,0246,0214,'%',0243,0306,'a','J','L',0234,'5',0263,'Y',0204,0355,'q','*',0315,'b',027,'d','Q',0254,0322,0343,0325,0255,0253,0253,0335,0224,'x',025,0376,'n',0257,'D',0210,0372,'n',031,'Z',0205,'F','w',0352,0312,']',05,'w','_','e','.',0257,0277,'.','+',0346,0374,0263,0213,'A','a','8',0265,'"','K',02,0371,0227,'Q','B',0351,'W',0355,0256,0364,0202,'G',013,0246,0312,0327,0243,0345,'l','m','&','^',0254,0200,011,0316,0347,0271,' ',0216,0314,0345,'"','M','b','6','+',']','t',0213,0314,0235,0205,0376,023,'3',0260,0373,0205,0346,0314,06,0255,017,0270,0337,0224,'x',025,0376,'n',0256,0205,'y',0324,0377,0,0265,'w',0232,0375,0253,0274,0326,01,0205,'X',0343,0227,032,0276,0374,0270,0257,0233,0362,0244,'z','F',0333,0233,025,'"','S',0312,0351,0265,0313,0314,0255,'N','e',026,024,0206,'8',0346,'I',024,0307,'#',0265,',','2','@',0216,0231,0316,0320,0243,0254,0317,0212,'4',0211,0227,'G',0362,0267,0350,0307,'+',035,0215,0330,'%',0215,'?',0247,'b',0340,0244,016,0266,'i',026,'i','v','p',0376,0251,02,0250,0337,0224,'x',025,0376,'n',0216,'I','T',036,035,'e','6',0267,'W',0277,'[',0357,0313,0212,0371,0277,'*',0366,0313,0221,0244,0317,0323,'l',0362,0254,0257,0320,0337,0225,0354,0347,0217,0321,06,0210,'v',0272,'y',0254,'d','F',0307,034,'k','#',0204,033,0244,0333,022,0375,0254,'s',0314,0263,0311,0365,0341,0221,0334,0343,'v','8',0216,'g','B',0237,'e','h',0252,'i',0301,0300,0202,0213,0277,'(',0360,'+',0374,0335,0134,0226,0360,'*',04,0313,0213,02,0363,0367,'f',0353,'X',036,'q','a',0222,0333,0352,0373,0363,'b',0276,'o',0311,0261,'1',05,0204,0262,'V','W',0236,'W','Q',0332,0202,05,0231,'d',021,0303,0350,'R','R','F',0275,0210,0364,'{',0330,';',010,0225,'g',0222,0274,'N','T',0253,01,'J',0227,0210,'U',0252,034,0373,'0','3','=',0255,0367,'c',0211,'e',0365,',',0266,'p',0354,037,'s','s',0330,0312,'<',012,0377,0,'7','S','B',0302,'a',0375,031,'G',0257,0321,0224,'z',0257,0307,0353,0252,0246,0325,0357,0346,0305,'|',0337,0216,0211,0351,0251,036,0221,0266,0344,0365,'"','[',02,0271,'Q','W',0327,'L','o','3',0207,0211,' ',0212,'E','q','n','@','9',022,'B',0245,0205,'d',0235,0322,0350,01,'9',0324,'Q',0226,'g',0326,0202,0202,0303,0237,01,0356,0350,0366,'W',0317,0355,0216,026,'N',0260,0333,0227,0370,'L',0270,0257,'w','{',0263,0206,0301,'t','j',0373,031,'G',0201,'_',0346,0352,0324,0366,0325,0326,0231,0221,0335,'[','J',0331,0357,'$',033,0205,'s',0330,023,'s',0253,0357,0313,0212,0371,0277,'"',0366,0307,0221,0246,021,0323,'l',0262,'u',035,0240,0377,0,'3',0231,0316,0326,0265,0260,0266,'9','R','M','Y',0372,'u',05,035,'f','x',0360,'r',0245,'%','g','I',0232,':',017,'r',031,0220,0373,'r',0276,0277,0326,0261,'B',0220,0272,'=',0305,'I',0321,030,0371,'z',0346,0375,0177,0275,'b',0202,0240,0224,'}',0214,0243,0300,0257,0363,'u',0236,'#',0227,021,0304,0207,'l',0334,'7',0341,0365,0365,'{','1',036,020,033,'*','Y','j',0373,0362,0342,0276,'o',0307,'<',0244,032,023,'J',0352,0274,0322,':',0257,0323,'"','t',0232,0366,0362,'B',0261,0331,'"','7',0235,0345,0257,0360,'4','O','U','&','`',0306,0351,'2',0222,0263,0252,0346,0267,0225,'4',0277,0312,'e',0302,0373,'K',0335,0234,'7','+',0255,'M',0273,'#',0231,0320,'S','*',0363,'/',0324,'(',0226,'r',0303,0215,'b',027,0261,0224,'x',025,0376,'n',0255,0200,'K','J',0314,'C',015,0227,030,'m',0317,014,'m',0205,'7',0,0303,0244,0306,'`',0325,0367,0345,0305,'|',0337,0214,0347,'r',0245,0345,0207,'Z','K',022,0275,'5',0375,0352,'8',0372,0216,034,'v',0302,0317,'D','r',022,02,';','P',0220,0242,0350,0202,0226,'u',0257,023,0321,'+','A','R',0245,032,04,0202,'?',0257,022,0205,'t','v',0273,'8','_',';',0371,0267,'g','S',0276,014,0177,'f','.',';','I',0274,'D',0364,'N',0306,'Q',0340,'W',0371,0272,0256,0342,'}',0330,'Z',0256,0342,0350,'R',0352,0273,'-',0250,0265,0372,0337,'~',0134,'W',0315,0370,0327,'g',0364,'"','8',0256,'D',0225,0375,'G','j',0266,'$',0321,022,'+',0244,0222,'O','o',034,'R',0365,031,'d',0366,0350,01,'z',0216,030,'u',0221,0325,'`',' ',0260,0354,0342,'x',0315,0350,'l',0341,0264,0357,'e',0306,0356,'"','N',0310,0350,0266,'`','#','4',0213,0376,0316,'Q',0340,'W',0371,0272,';',010,0243,0261,0325,0337,014,'j',04,0216,0320,030,0253,0311,0341,')',0223,0276,0363,'W',0337,0227,025,0363,'{','O',0235,0221,0352,'K',0210,030,0277,'}',0203,'L',0273,0201,0313,024,0315,0225,'7',023,':','A',025,0241,0275,'y','M','#',0252,0375,015,07,'Y',0317,0215,0301,0350,027,0365,'e',0234,'~',0266,0246,0377,0,0340,0202,'6','8',0231,'F',0203,0221,0264,'U',0234,0211,0267,0210,0303,'6','Z','M',0234,'>',0235,0220,0337,'n',0342,'w',0374,0375,0234,'8',0215,0316,0272,0354,0345,036,05,0177,0233,0253,014,0366,0362,0307,'T',0230,0301,0331,'T',0265,0334,' ',032,'=','S',0343,025,0224,'+',0253,0357,0313,0212,0371,0275,0211,0312,'d',015,';','!',0324,0366,022,'J',0262,030,0324,0327,0334,'Y',0250,0213,'k',0365,'O','d',0350,0245,'c',0271,0233,0266,0376,0303,'V','%','z','k',0373,0323,031,0316,0340,0305,0350,0352,0306,'o','W','A','2',0302,0346,0331,'7',0224,0202,'T',0227,02,'/','M',0264,0325,0312,'D',0221,0261,'#','n',0334,0372,'7','I',0217,0354,0303,0277,0364,033,0270,0235,0377,0,'?','g',013,0374,0236,0316,'Q',0340,'W',0371,0272,0261,0341,'=','Q',':',0260,0341,'E',0250,0272,'[',0274,0227,024,0233,02,0316,'L',0311,'O',0325,0367,0345,0305,'|',0335,0366,'V',0354,031,013,'>','B',035,'9',0255,0213,'S',0236,0351,'4',0347,0253,0276,0221,'J',0261,0270,02,0271,0365,'R','G','X','m',0226,'E',0240,0320,'Y',031,0247,'*',0221,',',0225,0352,0330,0306,'z','E',',','S','6','D','$','4',0227,'S',016,0350,0227,'U',0342,'z',0350,021,024,0231,'B',025,06,0213,'v','S',0377,0,013,'f',035,0377,0,0240,0335,0304,0357,0371,0373,'8','_',0344,0366,'r',0217,02,0277,0315,0321,0274,']',0261,0233,'D','e',0227,0327,017,07,01,0276,0265,'v',021,0201,'K',0213,0233,0253,0357,0313,0212,0371,0273,0256,',',0275,0254,'d',020,0257,'S',',','4',0347,0253,0327,'e','|',0334,0222,'c','e',0354,'s',0271,'[','}','a',0325,0220,0342,':',0257,0257,027,'F',0317,0312,0324,01,'_',033,'e','p',0357,030,0326,0313,0243,0134,0316,0230,0203,0365,0244,036,015,'S','W',' ',0361,'o',0312,0177,0341,'l',0303,0277,0364,033,0270,0235,0377,0,'?','g',015,012,0351,0331,0366,'r',0217,02,0277,0315,0325,'w',014,'i',01,0320,'u',0343,'W',0307,0365,0276,0374,0270,0257,0233,0265,0353,0312,0313,'i',0326,'R','l','J',0364,0322,0257,0256,0350,0335,0312,0352,'B',0371,037,013,0372,0221,0375,'.',0317,0366,0360,0331,0231,0241,'!',0353,'H',0215,0345,'c','F','t',0223,0223,'*','A',033,'X',0244,0313,'0','k',02,'"',0276,'w',06,'?','I',0224,'U',0274,0312,0211,0350,0233,0363,'R',0275,0255,06,0314,';',0377,0,'A',0273,0211,'"',0272,'Z',0215,0234,':',0377,0,0273,0331,0312,'<',012,0377,0,'7','u',0367,0345,0305,'|',0335,0263,0177,'1','X',0247,',',0305,0257,0254,0273,0352,0247,0325,021,'}','h','4','D',0311,014,'w','v','=','G',0317,'/','U',0360,'N',0260,0270,'s',033,'*','h',0370,037,'"',0202,'7','I',0266,04,'j',0274,'_','M','U',0202,0245,'M',04,')',014,'}',0216,' ',0377,0,0347,0366,'`',0303,'8',0213,0375,0334,'A',0377,0,0317,0354,0303,0227,0227,' ',0334,0237,0134,0243,0300,0257,0363,'w','_','~',0134,'W',0315,0332,0344,0365,'K',0310,0271,011,'5',0274,0262,0357,012,'^',0234,0264,0207,'t','%','d',0210,0346,'_',0332,'j',0300,0256,0243,0376,0215,'r',0265,'E',0260,0323,'^',0217,'B',0247,'H','X',',','*','D',0242,0217,0324,'u','X','(',',','=',0236,047,';',0377,0,0247,0354,0341,0317,0375,0335,0331,'c',032,0372,035,0225,'r',0244,'6','0','=','$',0207,'j','}','r',0217,02,0277,0315,0335,'}',0371,'q','_','7','v','I',017,0242,0332,'G',0350,0375,0355,'_','E',0257,0237,0231,0214,0271,0225,0220,0331,0231,0247,'/','2',0354,0200,0267,'E',0245,'{',0214,0220,'Q',0372,'m',0242,0255,0345,'N',0327,023,0210,'k',0315,0331,0303,06,'5','K',0335,'e',037,'T',02,030,0261,0317,0365,'c',0271,'_','D','G',0272,0251,0354,'e',036,05,0177,0233,0272,0373,0362,0342,0276,'n',0353,0310,':',0203,'Z','E',0352,0336,0300,'D',0364,'_','!',0355,'F',021,'2',0314,0355,0250,0236,0253,'^','/','+','i',0253,0324,0211,'c','b','F',0336,0326,'x','W',0271,0277,0331,0303,'!',0371,'+',0367,'9','=','[',0220,0214,0242,0334,0354,0341,0361,'~',0342,0217,0261,0224,'x',01,';',0220,0275,0327,0256,0365,'#',025,0363,'w',023,037,'R','+','H','=',035,'#','y','_',0330,0365,0336,0,0335,'G',04,'*',0315,' ',02,' ',0260,0366,0246,'z','G',025,0271,036,0352,0313,'f',020,'+',0206,0240,0337,0304,'!',':',027,'{','8','g','c',0310,'O','b',0340,0177,'u','_',0375,'-','q',0310,'T','[',010,'!',0203,'F','D',0312,'D',0330,0260,0312,0310,'w','/',0362,0231,0,0334,0223,0237,037,'$',0275,0350,'"','Y','^',' ',0374,0215,0243,0255,0350,0263,0267,0225,0237,0366,0352,'U','^','e',0372,0301,037,'V','j',0250,020,'j',0375,0374,'M',07,0234,'m',0230,0311,0353,']','p',0307,'#',0331,0330,0275,0246,'X','^',0327,'+',035,035,0324,0354,0327,0337,'e',0327,0337,'e',0323,0257,'&','T',0230,0211,010,'u','e','d',0226,'2',0303,013,'`',0213,'~','@','7','R',033,'H',0277,0216,0352,047,0252,0327,0213,0310,0332,'J',0356,0264,0214,'o','#','{','|','L',0262,0364,0217,'f','(',027,0276,0274,'D',0364,'M',0371,'X',037,'q',0245,'T',0345,'_',0252,'/','*',0342,0226,037,'q',0245,0354,'*','z',0241,0230,0340,0344,0253,0261,'I',0275,0177,'J',0317,0257,0322,0263,0353,0364,0254,0372,033,026,0215,0213,024,',',0201,0235,0203,'"',0352,0301,'h','?',0242,0275,0274,0256,0356,0,'7',';',0253,0303,'R','%',014,'d',032,'.',0332,0257,'*','e',0266,037,'q',0273,0331,0303,':',0356,'r','{',022,0306,0222,0305,'|',017,0333,0355,0266,'p',0322,0315,'X','G','b','i',0330,';',013,0312,0177,0225,0310,0215,0365,0375,'D','n',0277,'Q',033,0257,0324,'F',0350,'l',0246,'D','Q',015,0210,0330,0373,012,0236,0251,0220,013,0311,'9',0361,'r','K',0333,0202,'.',0253,0304,037,0225,')','k',0320,'x',0273,0231,']',0217,0333,'i',0234,0345,'s',0266,'`',0265,0276,0302,0223,0263,0304,0312,0336,0231,';','*','O','u','m',0200,'d','!','C','n','{',0322,'6','[','Z','>',0302,'a',0306,0220,0227,'G','C',0374,'}',0205,0272,0373,013,'t',0352,037,0340,0240,'e',021,'A',':','@','f',024,0226,0227,07,'b',0374,'^',0254,026,0220,0377,0,035,0244,'O','U',0257,027,0225,'(',0253,'z',0216,'j','r',0247,'s',0211,026,0353,'1','{',')',0303,'S',0354,0207,0211,' ',0203,0263,0226,0326,'6',0316,0231,'S',0225,'v','p',0352,0357,0334,0211,0273,'$','#',0242,04,'l','Y','d',030,'v',0215,026,0311,'#','l',0254,'0',0177,'m','>','*','G',0252,'v',012,0217,0253,015,0250,0334,0257,0225,0234,0217,0354,0200,'7','Q',0365,0241,')',022,0212,':',017,027,'r',0332,0301,0225,0200,034,'[',0317,'/','g',015,'j',0222,'b',0273,'O','j','=',0271,'}','W',0332,0256,'v','Q','Y',0272,0246,0314,'R',032,'T',033,'r',0317,0305,'R',0324,'q',0333,0257,'[',0351,'>','+',0346,0366,'r',' ',0371,']','e',07,'+',0273,020,0307,0324,'x','B',0372,'%','5','z',015,027,'w',0211,027,'|',0362,'l','c','U',0356,0305,0252,0233,'S','S',0333,0342,05,047,0277,0256,0333,0303,0314,0203,0257,026,0334,0263,0361,'T','y',0333,0257,0277,'.','+',0346,0366,'l',0306,0367,03,0330,0213,0251,031,0310,0355,0311,0374,0352,0270,'_','D',0242,0255,0347,'r',047,0242,'w','/','-',031,'Q',0134,'q','o','<',0275,0230,'=','/',0335,'-','Q','=',023,0267,',','I','4','y','=','J',0324,'[','l',0254,'>','J',0303,'i',0255,'#',0266,07,'f','U',032,0270,'`',0345,0350,022,0213,0352,0233,'m',0346,0353,027,0212,'F',0252,'G','e','S',0325,'/',0353,0371,']','`',037,0256,0225,0252,0232,0364,0372,0372,'i',0261,0271,0332,022,0275,'U','j',0353,0226,'y',06,0201,' ',0217,0270,0253,0350,0231,0346,'E',0367,'"',0366,'5',0252,0347,'a',0324,0311,'Q','S',0335,0342,05,047,0277,0256,0333,0203,0344,'K','T','k',0134,0217,'o',0324,0361,'}',0340,0222,0304,0350,'$',0257,0265,0350,0243,012,0212,'T',0352,0263,']','V','i',0304,'F',0304,':',0341,'9',0177,0227,'-',' ','>',0304,'>',0321,'#',0241,021,0330,0323,'>',047,0311,'W',0352,0253,'S',0245,0251,'M','}',0241,'4',0312,0215,017,'L',0345,0320,'x',0353,0227,'B',0204,0301,'[',0335,0316,'r','$',0253,011,'U',0134,0273,'0','z','U',0263,0265,'D',0364,'N',0353,0330,0222,'7','0',0245,'u','E',0256,0317,0353,'X','.','S',0357,'a',0331,'o','L',0333,04,'$',031,0204,'v',0310,'F',0224,0207,'S',0320,0373,'e',0356,'9',0210,0355,'8','(',0235,0257,0267,'C',0257,0266,'A',0257,0265,0301,0246,0201,023,'t',0221,'5',0275,0373,0253,'h',0251,0302,0265,0263,0226,0330,0315,0220,0302,0342,'%',0305,0352,033,'Q','U',0337,0311,0350,0331,'w',0134,'@',0357,026,'}',0202,025,' ','D','b',0231,033,'o',0203,0330,0346,0243,0265,0366,0341,0227,'_','m',027,'_','m',027,'_','n',027,'L',0215,0261,0247,0370,'$',0220,0301,' ',0312,'r','Y','/',0211,0333,0303,0354,'o',0235,0337,07,0210,'8',0337,'2','m',0252,0265,0236,0240,0252,'+',0210,0356,'@',0377,0,'%',0357,'H',0333,0232,'e','R','X',0223,0267,032,0244,'}',0335,0200,0243,0260,'X','>',014,0360,'0',0230,0262,0274,'y',0364,'g','m',0240,0277,0236,0210,0252,0213,'x','.',05,0377,0,035,0357,'H',0333,0231,0346,'j','K',0266,0216,';',0312,0237,026,0307,0333,'F',02,'|',';',0332,'x',0356,'@',0265,0252,0232,0240,0275,0264,027,0363,0321,025,'I',0220,013,'y',017,0370,0263,0316,0301,0242,0313,0263,0177,'|',0233,'Q',025,0313,0203,'b',0212,023,'u',0351,0361,'2',0274,'e',0227,0303,026,',',0201,021,0266,0252,0326,'z',0202,0261,0234,0256,033,0330,0277,0303,'8',0370,'k',0307,0311,0363,')',0256,0227,'v',021,0210,0373,0267,'"','z',047,0306,0314,'1',06,0332,0307,'4','/',036,'M',0243,0221,' ',0262,'b',0371,0353,011,0323,036,0331,033,0376,05,0366,'N','-','$','7',0231,021,'7',0223,0356,0304,0361,027,0332,0276,0270,'_','j',0317,0221,0230,'a',0354,0264,0216,'h','^','<',0233,0261,0354,0320,0252,'w','T','^',0213,'s',017,0315,0236,'v',015,036,'I',0304,036,']',020,'D',0205,'I',0273,020,0304,037,'m',',',020,'0','x',0276,'V','[',0206,0266,0335,0246,07,'(',023,0356,020,0351,0300,0223,037,0342,'*','z',010,'|',07,'G',0362,0134,0364,'b',']',0347,'!','V','%',0276,'L','u',0303,0267,0342,0330,'D',0307,0276,010,030,'4','_','3','#',0305,07,0276,0216,0326,0246,'z',0202,0267,0201,'j','U','d',0224,0234,'H','k',0264,025,0240,0266,015,0370,0262,0312,0310,'[','q',0236,01,0134,0333,0214,0300,0373,'u',0376,0367,0265,0252,0367,'b',0230,'"','*','1',0211,033,'~','u',0265,'(',0367,03,0344,'X',0201,'4',0262,0366,04,':','p','d',0252,0342,')',0202,0272,0267,':',0255,'?','Q',021,034,0351,0337,'U','F',0350,0374,0226,0276,0271,0266,0334,'K','O','K',034,0220,0373,'N',0315,'}','a',026,'s','c','8','T',025,'-',0376,0277,0301,0222,'&','L',0314,0223,0207,0354,0237,'E',0207,'0','3','v','C',0270,'0',07,'W','q',024,0361,'P','N','%',0207,'"',0215,0231,'U',0222,0310,0354,0205,0233,0134,0355,0334,0256,'D',0324,0205,'C',016,0247,0310,0353,0207,'y',0134,'E',0255,0205,0247,'q','6','G','h',0334,0252,0310,0355,'9',0352,0365,0354,0177,'z',0307,'p','r','m','V',0256,0230,'j',0230,0177,0304,0271,0307,'D',0272,0212,0357,010,'6',0253,'_',0327,'q',0204,'I',032,0307,'v','t','O',0375,'c','m',0241,0263,0353,'A',0331,0373,0215,'g',0257,0334,'[','=','.','c','l',0252,'N','K','b','^',0245,'<',0211,0364,0252,0256,'^',0335,']','!','w',022,'c',0230,034,025,0272,'k','Q',0215,0377,0,031,0315,'G',0266,0353,06,012,0323,'W',030,'y',0365,013,0375,'|',0320,'*',0212,0263,0222,0223,0206,0355,'n',0204,02,0,'c',0377,0,')',0314,'G',0245,0326,014,025,0246,0256,'0','c',0353,'5','$','O',0205,0337,037,0373,0325,'v','>','u',0233,0352,'8','k',034,'n',020,010,01,0217,0374,0357,'O',']','X',0343,0340,0331,0262,0313,0206,'l',']','X','b','V','U',0353,'$','O',0205,0337,07,0373,0320,0224,0246,0232,0265,0274,'6','*','}','U',0341,025,0325,0253,034,'L',0211,'?',0323,'T','E',0321,'t',0201,033,0243,'8','q','_','>',0212,0341,0221,'Q',0264,0214,'&',0326,011,'%',0253,'.',024,'X',0336,0324,0336,0215,'W','j',' ',0247,0235,'G',0305,0354,0312,'`',0234,'9',0260,0231,'A',0341,0224,',',0320,'X',0215,'`',':',0216,026,'D',0237,0355,0276,010,0344,'l',0265,01,0314,0317,0322,0325,0232,0237,04,0252,0236,'O',0333,0352,0255,'~',0337,'U','k',0366,0372,0253,'_',0267,0325,'Z','f',047,'V',0306,017,0217,0327,0214,0350,0303,0202,'%','D','D',0377,0,0365,0317,0377,0304,0,'=',021,0,01,03,02,03,05,06,04,04,05,04,02,03,0,0,0,01,02,03,04,0,021,05,022,'!',06,023,' ','0','1',020,024,'"','2','A','Q','@','P','a','q','3','4',0221,0261,'#','B','R','S',0201,025,026,'5',0241,'$','C','`','p',0200,0377,0332,0,010,01,03,01,01,'?',01,0377,0,0362,'f','R','k','*',0275,0253,'*',0275,0253,'*',0275,0253,'*',0275,0277,0370,013,'l',':',0357,0221,'7',0246,'v','z','{',0247,0311,'o',0275,'5',0262,'O',021,'w',026,01,0246,0366,'V','*','H','+','Q','4',0215,0236,0303,0333,'V','l',0225,0376,0223,07,0373,'B',0233,0211,035,0241,0225,010,026,0373,'V',0341,0257,0350,037,0240,0255,0303,'_',0320,'?','A','[',0206,0277,0240,'~',0202,0267,015,0177,'@',0375,05,034,'.',012,0215,0313,'B',0235,0301,' ',':',',','[',0267,0332,0235,0331,0210,'+',026,'E',0323,'N',0354,0220,0277,0360,0234,0323,0353,'O','l',0314,0346,0301,')',027,0247,0360,0351,'Q',0315,0234,'l',0325,0210,0371,0267,'Z',0215,0205,0313,0227,0370,'h',0250,0333,'&',0243,0254,0205,0333,0355,'Q',0360,030,'1',0307,0223,'7',0336,0220,0332,033,0362,013,'|',01,0324,'X',0323,0370,'d','9',037,0210,0330,0251,033,'(',0302,0356,'Y',']',0252,'V',0317,'M',0215,0250,'N','a',0364,0245,0266,0266,0315,0224,'-',0363,026,0230,'q',0365,'e','l',0134,0324,035,0227,'}',0337,024,0237,010,0377,0,0272,0211,0202,'C',0207,0252,'S','s',0365,0240,'-',0240,0370,'y','0',0243,0313,'N','W',0221,'z',0231,0262,0255,0250,025,'F','U',0217,0261,0251,'X','d',0250,0177,0212,0217,0226,0264,0303,0217,0253,'+','b',0346,0240,'l',0262,0325,0343,0226,'m',0364,0250,0320,0330,0206,0234,0254,0246,0337,030,0244,0245,'c','*',0205,0305,'O',0331,0250,0362,'<','L','x','O',0375,'T',0314,'.','T',023,0374,'T',0351,0362,0224,0244,0254,0331,'5',017,02,0324,'*','j',0302,07,0267,0255,'F','V',035,015,'9','Y','P',025,0337,0342,0377,0,'p','W',0177,0213,0375,0301,']',0376,'/',0367,05,'&','d','u',0234,0251,'X',0346,'Z',0255,0317,'R','R',0261,0225,'B',0342,0261,'-',0232,'j','G',0216,'/',0204,0324,0270,'/',0302,'^','G',0223,'o',0223,'@',0303,'$','b',013,0263,'c','O','z',0220,0270,0330,032,'w','L','x',0235,0365,'>',0324,0363,0356,'>',0254,0356,033,0236,0315,'k','Z',0326,0202,0212,'M',0305,'`',0333,'@',0246,0324,030,0224,'t',0367,0240,'B',0205,0307,'j',0224,0224,'j',0243,'j','{',030,0202,0310,'9',0234,0247,'v',0246,032,015,0220,0222,'i',0315,0255,'p',0334,'6',0335,'+','i',0347,0250,'[','O',0322,0277,0327,'q',037,0356,0232,'w',022,0226,0362,0263,'-',0303,']',0362,'G',0365,0232,0357,0262,0177,0254,0320,0307,'q',01,0246,0364,0323,'[','G',0210,'5',0325,'W',0373,0323,'[','W','%','?',0210,0220,'i',0255,0255,'d',0217,0342,'7',0255,'3',0217,0300,'x',0333,'=',0276,0364,0324,0226,037,027,'m','`',0362,0344,'F','j','Z','7','o',013,0212,0305,'6','u',0330,0327,'r','?',0211,'?',0265,021,'n',0277,'"',011,'*','6',025,0204,0354,0331,'t',07,0245,'h','=',0252,'c',0255,0341,0220,0324,0246,0305,0255,'N','8',0247,'V','V',0276,0246,0233,'o','6',0246,0202,'@',0253,'U',0252,0302,0226,0327,0250,0354,0331,0374,'L','.',')','K',0352,0362,'T',0255,0244,0206,0306,0210,0361,032,0225,0264,0362,0336,0321,0257,015,'?','2','D',0223,'w','W','~','r',034,'Z',015,0322,'j','>','?',':','?',0363,0334,'}','j','.',0325,0264,0275,'$','"',0337,'j',0215,'>','4',0277,0301,']',0371,'X',0236,0,0304,0357,033,'~',025,0324,0250,0217,'C','Y','m',0321,'o',0220,'2',0303,0222,025,0221,0261,'s','X','N',04,0324,' ',035,'t',']',0177,0267,'f',0325,',',0246,'*','R','=','M',015,'h',013,016,047,05,0225,'A','D',013,'|','"',026,0246,0315,0320,'m','P',0366,0206,0134,'c','e',0234,0303,0353,'P',0266,0206,'$',0263,0225,'^',023,0365,0240,'A',0324,'r','&','B','f','r','7','o',012,0305,'0',0207,0260,0367,016,0227,'O',0277,'2',0365,0230,'V',0360,'V',0360,'P','P','<',0350,'P',036,0236,0346,0355,0221,'X','^',026,0326,032,0325,0207,0230,0365,'=',0273,'Y',0371,'d','}',0351,'=','x',0336,0363,'|','D',034,'j','T',035,022,0253,0217,'j',0201,0264,'1','e',0370,'W',0341,'W','!',0306,0320,0362,013,'n',013,0203,'X',0276,02,0344,'2','^','g','T','r',011,0265,')',0360,'(',0276,'M',025,0250,0325,0317,'h','Q',024,0321,'$','k',0314,0201,01,0334,'A',0320,0333,'b',0240,0301,'k',017,'k','t',0327,06,0326,'~','Y',037,'z','O','^','7',0274,0337,023,0322,0260,0374,'~','L','2',022,0263,0231,'5',07,021,'b','z','3','4','u',0366,0343,' ','(','X',0326,'9',0201,0230,0304,0310,0216,'<','?',0267,022,0334,011,0245,'8','U',0306,0204,0346,'4',0221,'a',0313,0201,01,0334,'A',0320,0333,'b',0240,0301,'k',017,'k','t',0327,016,0326,'~','Y',037,'z','O','^','7',0274,0337,026,0313,0356,'0',0254,0355,0233,032,0302,0266,0215,'2',010,'f','V',0212,0367,0240,'o',0250,0342,' ','(','X',0326,'9',0201,0230,0304,0310,0216,'<','?',0267,03,0256,'e',0242,'o',0306,05,0351,0246,0362,0216,0134,'X',0256,'K','p','4',0320,0326,0260,0350,'(',0303,0330,015,047,0257,0257,026,0326,'~','Y',037,'z','O','^','7',0274,0337,031,'z',0302,'q',0367,'!',0220,0323,0332,0242,0232,'u',017,047,';','f',0343,0210,0200,0241,'c','X',0356,020,0250,'n',0227,0233,036,03,0330,0265,0345,024,0245,'f','<',0206,'[',0365,'<',0266,0232,'S',0313,010,'@',0324,0326,015,0205,0214,'5',0237,027,0234,0361,022,022,'.','k','h',0261,'f','f',0,0303,'>',0236,0264,0236,0275,0212,'6',027,0255,0362,0253,'|',0252,0337,'*',0220,0254,0342,0364,0367,0233,0343,0260,0254,'U',0334,'9',0313,0215,'S',0352,'*',034,0326,'g','#','x',0311,0342,0306,0261,'$',0266,0202,0325,'-','A',':',0322,0327,0230,0362,031,'n',0372,0232,0351,0313,0331,0334,'#','r',0236,0364,0370,0361,'z','q',022,022,'.','k',034,0307,014,0222,'c',0307,'>',037,0337,0261,'=','{',026,'l',0223,'L',0244,021,0255,'d','O',0265,'6',02,0256,015,'1',0326,0236,0363,'|','|',011,0356,0341,0356,0207,033,'5',06,'s','X',0203,'[',0326,0270,'1',011,0211,0214,0331,0251,0262,'K',0356,025,032,'u',0314,0307,0220,0332,'3',032,02,0334,0274,07,014,0357,0317,0347,'_',0221,'4',05,0264,034,'X',0376,'4',0247,'V','b',0260,'|','#',0257,0327,0265,'=','{',024,'.','-','^','$',032,'.','(',0372,0323,'I',' ','^',0231,'I',035,'i',0357,'7',0310,' ','O','w',017,'t','8',0331,0250,'r',0221,'1',0220,0362,'=','{','%',0311,'L','V',0312,0215,'b','X',0212,0345,',',0353,0245,'<',0345,0364,034,0204,047,'1',0244,047,'(',0345,0306,0216,0271,'N',0206,0233,0352,'j',014,'4','A','`','2',0216,'-',0241,0306,013,'C',0272,0307,':',0372,0327,'^',0324,0365,0355,'R',0321,0320,0326,'v',0305,'%','i','W','N',0307,0274,0337,'!',0302,'1','G','0',0367,0206,0276,023,0326,0214,0246,0267,'[',0340,'t',0254,'_',024,'2','T','R',0236,0224,0363,0226,0344,01,'z','m',031,'G','3','f',0360,0320,0303,']',0351,'}','U',0323,0213,035,0305,04,06,'w','i',0363,0252,0224,0242,0263,0230,0360,047,0257,'b',0364,'I',0244,' ',0257,0245,'n',017,0275,'!',0274,0206,0375,0217,'y',0276,'D',0334,0347,'[','d',0261,'}',')',0327,'-','D',0337,0220,0313,'v',0324,0363,'0','x',035,0376,'H','A',0362,0216,0264,0224,0204,'$','%','=',07,014,0311,'H',0206,0312,0236,'_',0245,'K',0224,0271,0217,027,0134,'=','x','S',0327,0261,']','5',0246,0326,020,'k','~',')','.',05,0233,'v','=',0346,0371,022,0225,0224,'R',0327,0230,0362,031,'n',0372,0236,'n',0317,'A',0356,0221,'s',0253,0314,0256,'-',0241,0305,';',0343,0333,0226,0374,0211,0342,'O','^',0302,'.','-','[',0201,'[',0201,'H','o','!',0277,'c',0336,'o',0221,'I','z',0302,0227,0213,024,0275,'j',0217,'-',017,0215,'8',0232,'F','c','@','[',0231,0202,0301,0357,0322,0222,0223,0320,'u',0240,',',',','8','v',0206,0177,'t',0215,0273,'I',0361,'*',0272,0361,047,0255,',',0345,'M',0305,'%','d',0244,0232,0337,'*',0267,0312,0246,0334,'*','6','=',0217,'y',0276,'B',0363,0226,0322,0226,0234,0342,0306,0261,034,'4','#',0306,')',0231,013,'a','Z','T',',','Q','.','h',0252,'J',0202,0265,035,0250,'N','c','H','E',0207,'7','f',0341,0367,'x',0233,0322,'5','W',012,0224,020,0222,0245,'t',025,0212,'L','3',0245,')',0337,'N','4',0365,0242,'/',0241,0240,0220,05,0253,'"','}',0253,'"','(','%','#',0247,'c',0336,'o',0220,'8',0274,0242,0211,0275,023,'j',0304,'e',')',0307,'7','b',0233,0302,0203,0215,'_',0326,0237,0212,0344,'U','^',0240,'b','K','I',0312,'i',012,0316,0233,0320,027,0246,0233,0312,'+',06,0303,'{',0323,0227,'W','J',0230,0301,0214,0372,0232,'>',0234,0274,'>','9',0225,'%',015,017,'S','I','H','B','B','S',0320,'p',0355,',',0376,0357,037,'p',0236,0252,0375,0271,011,0353,0330,0243,0224,'^',0265,'U','n',0325,0355,'M','$',0203,0257,'c',0336,'o',0217,'Q',0312,')',0305,0346,'=',0213,0325,'5','4',026,0237,0315,'P','1',04,')',031,'U','X',0244,0206,0324,0233,012,0303,'`',05,0177,020,0320,026,0322,0231,'o',0324,0324,010,'J',0224,0340,02,0241,'D','L','V',0302,'E','m',0134,'K',')',022,'S',0353,0247,'/','e','"',0346,'q','r','O',0246,0234,'$',0201,0251,0254,'Z','Y',0231,')','N',036,'B','z',0366,'(',0134,'S','D','$',0233,0326,'t',0373,0320,'P','=',';',036,0363,'|','{',0316,'_','A',0330,0353,0311,'h',']','T','q','f',0257,'j',0224,0303,'s','S',0231,024,0270,0257,'2','t',0246,'c',':',0372,0365,0250,0254,0356,'[',0313,'M','7',0233,'Z',0214,0301,'y','a',011,0254,'+',017,'L','V',0301,'#','^',0314,'V','(',0227,021,'m',0372,0321,026,'6',0344,0365,0254,032,'/','t',0204,0204,0372,0235,'x','v',0202,'_','u',0204,'r',0365,'V',0234,0224,0365,0354,'P',0270,0265,'n','U','[',0225,'S','m',0224,0233,0236,0307,0274,0337,034,0363,0226,0323,0261,'G','(',0275,'N',0220,0271,016,0356,0323,'R','!',0226,'S','s','X','b',026,0204,0357,015,'3','!',0231,047,')',024,0226,'P',0216,0202,0220,0214,0306,0220,0217,'A','X',06,033,'o',0342,0257,0203,031,0213,0335,'f','-',036,0234,0234,'9',0203,'&','R',033,036,0365,'`','4',034,';','O',',',0273,'+','r',016,0211,0344,0247,0257,'a',0351,'M','-','J','6','<',017,'y',0276,'5','j',0312,')','J',0314,'{','$',0337,'v','m','L',0272,033,'|',0225,'U',0314,0347,0276,0225,'-',0304,'E','c',' ',0254,'!',0222,0245,'g','4',05,0351,0264,'e',025,0204,'a',0306,'B',0302,0215,'2',0320,'e',031,'G',06,0326,'G',0374,'7',0307,0333,0223,0262,0214,'g',0222,0247,'}',0207,013,0256,06,'[','S',0207,0322,0244,0272,'_','u','N',037,'^','J','z',0366,'(',0330,'^',0202,0310,'9',0253,'|',0252,'m',0302,0243,'c',0330,0357,'_',0214,'&',0324,0352,0363,036,0307,0344,'%',0201,'s','L',0314,'D',0257,015,'b','0',024,0205,'f','M','2',0363,0221,0316,0224,0323,'o','M','_',0212,0242,0307,014,'#','(',0246,'[',0266,0247,0263,'e',0335,'K',0221,0312,'=','S',0303,0216,0261,0277,0200,0277,0246,0274,0235,0227,'g','w',014,0271,0375,'G',0207,'h',0344,'n',' ',0224,0203,0252,0271,'I',0353,0333,0273,'O',0265,'n',0323,0355,'A',' ','t',0354,'{',0257,0306,'<',0347,0240,0354,'Z',0262,0213,0324,0307,0327,')',0354,0211,0246,0222,0334,04,'f','W','Z',0377,0,'V','K',0212,0312,0252,'j',033,017,0214,0342,0232,'a',015,'y','E','2',0335,0365,0355,0331,0211,033,0251,0233,0262,'t','W',013,0210,0336,' ',0243,0336,0237,'F',0355,0325,'#',0333,0217,0255,'a','L',0356,'!','6',0213,'[','N',035,0254,0177,'3',0310,'g',0330,'r',0223,0327,0260,0233,013,0321,'R',0216,0265,0342,0246,'o','~',0307,0274,0337,026,0342,0362,0212,'&',0347,0262,'e',0367,'F',0324,0333,0373,0227,'J',0215,'-',0307,'&',0256,0324,0374,'M',0305,0253,011,0276,0353,'Z','B','s',032,'J','r',0216,0330,0256,0356,'_','K',0236,0306,0222,0254,0351,012,0367,0341,0307,'Y',0334,0317,'X',0265,0201,0343,'a',033,0307,'R',0217,'z','B','r','$',047,0333,0207,035,'{','}','=','f',0367,03,0224,0236,0275,0216,'y','M','#',0360,0315,'6',0241,0226,0306,0230,':',0333,0261,0357,'7',0305,023,'j','u','y',0217,'b',0335,'K','z',0252,0273,0313,'/','x','o','O','`',0341,0305,'f','M',06,0232,0200,0233,0236,0264,'3',0316,'{',0351,'Q',0231,0335,0240,'$','S','h',0312,'8',':','V',024,0366,0376,023,'k',0275,0364,0341,0332,0266,0262,0311,'K',0236,0343,0217,06,'m','.',0316,'m',012,0367,0341,'R',0262,'$',0253,0332,0244,0254,'8',0362,0226,'=','O',')','=','{',010,0270,0265,'!',031,')','M','(',035,')',0264,'d',0353,0330,0367,0233,0342,0236,'s',0323,0261,0307,03,'i',0314,'j','d',0267,'$','/','*','+',';',0254,'+','Z',0203,0213,0177,'*',0352,'D','T','M',031,0222,'j','$','$',0307,024,0313,'~',0274,'[','0',0350,0134,034,0203,0371,'O',016,0326,0266,0235,0323,'n','z',0361,0354,0313,'i','r','x',0277,0247,016,'"',0341,'f','#',0253,'O',0265,035,'O',')','=','{',03,0252,024,036,036,0264,026,0223,0332,0367,0233,0342,0134,'^','Q','D',0337,0263,027,'y','I','N','Q','P',0331,015,'4',']',']','4',0307,'}','t',0324,0250,0245,0207,',',0232,0302,'[','p','&',0352,0246,0233,0314,'h',013,'q','l',0223,0244,0207,032,0364,0353,0303,0264,0315,0245,'p','3',037,'C',0307,0262,0250,'Q',0230,'V',':',01,0303,0217,0272,'Z',0303,0326,'G',0256,0234,0264,0365,0354,'-',0244,0372,'R',0232,'H',0365,0242,'-','L',0235,'{',036,0363,'|','A','6',0247,027,0230,0366,'I','|','0',0214,0324,0323,0255,0317,0320,0326,'$',0215,0313,'9','S','P',0246,0367,'z',0212,'L',0271,031,0215,'2',0325,0274,'"',0220,0234,0243,0217,'e',035,')',0226,0246,0375,010,0341,0332,024,')',0314,'=','y','x',0366,'G',0316,0357,0333,0207,'i','T',04,02,017,0251,0345,0247,0257,'a','q','F',0222,0202,0272,014,017,'Z','J',02,'z','v','=',0346,0346,0227,022,'+','|',0232,'K',0201,0134,0227,0234,0364,0354,'Z',0302,05,0315,'b',023,0203,0376,01,'X','T','p',0332,'3','S',0354,07,0323,0224,0322,0360,'S',0233,'J',0205,04,'G',024,0323,'y','G','#','f',024,023,'?','_','c',0303,0213,'~','E',0337,0267,036,0310,0371,0335,0373,'p',0355,'g',0345,0233,0373,0362,0323,0327,0260,0262,0237,'J',',',0250,'t',0254,0313,'E','6',0341,'Q',0261,0354,'{',0315,0313,'[',0241,'4',0247,'I',0253,0366,03,'j','i','y',0207,033,0212,0312,')',0327,'2',0214,0306,0232,0304,0220,0267,'2','T',0226,0313,0315,0331,'5','&','#',0214,'*',0365,013,023,'-','x','U','L','I','C',0302,0343,0261,0226,0357,0257,047,02,0377,0,0221,'k',0357,0303,0213,'~','E',0337,0267,036,0310,0371,0335,0373,'p',0355,'g',0345,0233,0373,0362,0323,0327,0260,0274,'}','+',':',0215,06,0324,'i',0266,0362,033,0366,'=',0346,0344,0223,'j','q',0357,'A','W',0277,013,'*',0261,0342,'&',0324,0352,0363,032,0305,'f',0345,031,023,'X',0134,'B',0243,0275,'U','+',022,'B',034,0335,0322,0332,'n','J','5',0251,0270,'Q','G',0211,025,0205,0266,0360,']','4',0214,0324,05,0271,'8',027,0374,0213,'_','~',034,'[',0362,'.',0375,0270,0366,'G',0316,0357,0333,0207,'j',032,0317,010,'/',0372,'O','-','=','{',03,'I',024,0,035,'8',036,0363,'r','_','s',0323,0214,'i','M',0233,0216,027,0227,'m','*','l',0215,0313,'w',0242,0356,0365,0353,0256,0234,0230,0333,'1',0354,0212,0204,0302,0245,';',0234,0322,0326,0230,0315,0324,'y',0350,0222,'r',0232,'m',0224,0244,0370,'E','6',0214,0243,0225,0263,0215,'o','q',04,0237,'m','x','q','o',0310,0273,0366,0343,0331,'7','B','d','-',0277,'q',0303,0264,0177,0361,0312,0373,0216,'Z','z',0361,0275,0346,0344,032,'s',0315,0310,0216,0257,'N',05,0253,'(',0245,034,0306,0237,'a','/',0246,0306,0246,0341,'j','h',0335,'4','s',015,025,'X',0134,0226,0220,0233,'V',047,'7','z','r','"',0260,0250,'y','F','u','S','-',0372,0362,0366,'[',0363,0337,0340,0360,0343,'n',0206,0240,'8','O',0256,0234,'{','-',0371,0357,0360,'x','q','a','x','.',0375,0271,'i',0353,0306,0367,0233,0220,'i',0301,'e','r',033,'V','U','P',0327,0265,0345,0334,0333,0265,'I',012,026,'5','7',012,'J',0374,'H',0247,031,'v','9',0254,':','*',0244,'/','2',0252,';','6',0322,0200,0267,'/','d','G',0361,035,'?','N',035,0244,0377,0,0216,'W',0334,'q',0340,'*','#',020,'n',0334,'/',047,';','j','O',0320,0323,0251,'(','Y','I',0345,047,0257,033,0336,'n','K',0343,'^','K','*',0270,0354,'y','v',034,'R','!',0266,0377,0,'Z',0213,025,',',0370,'S','H','N','Q',0314,0331,'V',0312,'b',0251,'d','u','<',';','V',0242,'"',0240,017,'~','8','K',0335,0310,'B',0257,'m','j',0340,0352,'8','q','F','w',023,034,'G',0327,0224,0236,0274,'o','y',0271,'/',0246,0343,0222,0332,0362,0232,'/',013,'R',0225,0230,0361,0262,0335,0265,0346,0340,'M','n','p',0366,0307,0276,0274,';','Z',0345,0334,'m',0260,'x',0306,0206,0241,'8',036,0214,0333,0203,0324,'p',0355,'C','9','&','g',0266,0204,'r',0223,0327,0215,0323,0342,0344,0254,0134,'Q',0323,0340,032,'F','c','C','N','c','i','+','X','H',0246,033,0335,'4',0224,'{',016,035,0244,'t','9','=','@','z','i',0310,0331,0327,0367,0320,0,047,'Q',0303,0265,'Q',0267,0221,0322,0370,0376,'^','[','k',0270,0261,0341,'R',0202,'E',023,'s','~','S',0251,0262,0271,0351,031,0215,'!','9','G','7',02,0215,0336,0246,0241,047,0240,0327,0206,0340,'j','j','{',0245,0351,'+','Y','7',0327,0221,0262,'O',0352,0343,07,0357,0303,0210,'G',022,0242,0255,0257,0245,')','%','$',0244,0362,0303,0252,025,0276,'U','o',0225,'E',0325,'Q','7',0353,0313,0220,0237,'^','{','-',0333,'^','v',0311,0305,0260,0134,0203,0366,0341,0304,0337,0356,0360,0334,'s',0351,'G','S',0310,0300,0244,0367,'Y',0250,'Q',0350,'t',0342,0307,'b',0367,'Y',0253,03,0241,0327,0342,0234,027,024,'y',0254,0243,'1',0277,'8',013,0233,'V',027,033,0272,0303,'C','|',';','U',047,'w',035,',',017,0346,0344,0266,0262,0332,0302,0207,0245,'C','|','I',0216,0207,'G',0250,0341,0332,0230,0233,0310,0351,0220,':',0217,0213,'t','Y',0134,0304,0247,'1',0244,047,'(',0347,'`','q','{',0324,0324,0244,0364,032,0361,'m',',',0255,0374,0302,0201,0321,':','r',0266,'Z','V',0362,':',0230,'?',0313,0303,'!',0204,0311,'i','M','+',0326,0244,'2','X','u','M',0237,'N','H',04,0364,0240,0311,0255,0305,'n','(',0262,'i','I',')',0353,0314,0220,0237,'^','c','-',0333,'^','~',0314,'B',014,0307,0357,07,0252,0270,'d','<','#',0262,0247,'O',0240,0247,0234,'.',0270,'V','}','y','X',024,0276,0353,'1',':',0350,'t','<','[','S',03,'*',0304,0264,'z',0365,0344,0241,'9','G',011,031,0205,0251,'B',0306,0334,0265,0213,0212,'"',0307,0224,0322,'3',032,032,'s',0240,'E','T',0311,011,'e','4',0323,'i','e',01,0264,0364,034,';','Q',',',0263,035,',','$',0352,0256,'Z','T','R','s',012,0302,'e',0367,0330,0211,'p',0365,0341,0231,031,'3',030,'S','*',0365,0247,0332,'S',016,026,0325,0324,'q',0243,0315,0306,0367,0233,0230,0372,'l','o',0311,'H',0314,'i',0264,0345,034,0375,0227,0201,0272,'h',0312,'_','S',0323,0213,033,0232,'f','K','Q',0364,032,'s','6','b','~',0345,0356,0354,0276,0212,0375,0370,0266,0237,015,0267,0376,'b','?',0317,033,'~','n','7',0274,0334,0307,023,0230,'Q',026,0344,'2',0337,0257,'?',014,0204,0251,0362,'R',0320,0246,0233,'K','(',015,0243,0240,0341,0307,047,'w','(',0206,0336,'e','i','D',0337,'^','c','k','-',0250,'-','>',0225,0207,'K',023,'c','%',0341,0376,'x','_','e',022,'[','-','9',0320,0326,'#',011,'p',037,'-','+',0210,033,032,032,0361,'8','n',0256,'k',0315,0372,0216,' ','/','M',0263,0352,'h',013,'s',0200,0276,0225,0200,'a',0235,0311,0215,0342,0374,0352,0342,0307,0347,0367,0311,'D',047,0312,0235,'9',0333,'1','?','r',0367,'w','_','E','~',0374,'X',0346,032,047,0307,0314,0237,'2','i','@',0244,0330,0361,'!',0314,0272,032,013,'I',0254,0311,0254,0311,0254,0351,0245,0273,'}',07,'<',0264,0223,'[',0204,0326,0340,'W','w',024,030,024,020,07,0300,'l',0356,027,0336,']',0357,016,017,012,0177,0357,0213,034,0235,0334,0242,033,'y',0225,0240,0242,'o',0257,'9','*','(','9',0205,'a',023,0204,0350,0251,'_',0250,0353,0305,0264,'X','F',0354,0367,0246,06,0236,0277,'.',0303,0240,'9','=',0360,0332,07,0336,0243,'G','n','+','A',0246,0206,0203,0204,0220,0221,'s','X',0324,0343,':','R',0224,'<',0243,0247,0300,'`',0330,0211,0303,0344,02,'|',0247,0255,'%','A','i',012,'O','C',0302,0343,'i','u','%',013,032,032,0306,0360,0243,0207,';','t','y','O',0313,030,'e','R',034,015,0243,0251,0254,'/',014,'o',015,'k','(',0363,036,0247,0213,'i','q','M',0312,';',0243,'g','S',0327,0340,0266,'k',024,0314,';',0233,0247,0355,0305,'&','3','r',0333,'-',':','4',0254,'O',017,'^',036,0371,'l',0364,0364,0371,'R','R','V','r',0212,0300,0360,0204,'A','h',':',0261,0343,'?',0365,0305,0210,0316,'D',06,013,0252,0353,0351,'O',0274,0247,0334,'.','/',0251,0370,'&',0235,'S','+',016,' ',0352,'+',012,0304,'Q',0210,0261,0234,'u',035,'x',0247,'A','k',020,'k','t',0355,'O',0200,0356,036,0351,'m',0301,0362,0204,0244,0254,0345,'M','`','x',030,0212,04,0211,03,0307,0373,'q',')','A',011,'*','W','A','X',0326,'(','q',07,0374,'>','A',0323,0341,'0',0314,'A','x','{',0341,0301,0323,0326,0243,'I','j','[','a',0326,0216,0207,0212,'t',026,0261,06,0267,'N',0326,'#',0205,0277,0207,'*',0316,015,'=',0376,'L',0323,'K','y','a',010,027,'&',0260,'l',04,'B',0376,'4',0215,'W',0373,'q',0355,016,'0',034,0377,0,0305,0216,'~',0377,0,015,0202,0343,07,016,'^','E',0371,015,'6',0342,']','H','Z',016,0207,0212,'L','f',0345,0264,'Z','t',0134,'V','/',0202,'/',016,'V','t','j',0217,0222,'E',0212,0354,0267,03,'M',015,'M','a','x','3','8','h',0315,0325,'|','x',0356,'4','"',0244,0306,'g',0314,'z',0375,'(',0233,0353,0360,0370,026,'8','c',021,036,'G',0223,0366,0240,'B',0205,0307,022,0222,0225,0214,0252,027,025,0213,'l',0335,0256,0364,'?',0322,0224,0222,0203,'e','|',0207,014,0301,0237,0304,024,015,0254,0217,'z',0205,01,0230,015,0344,'h',0177,0236,'<','c',030,'F',036,0235,0332,'5','Y',0377,0,0252,0222,0361,'}','Y',0325,0327,0342,'p','<','p',0306,'"','<',0203,0341,0375,0250,020,0241,'q',0307,0211,'`',0261,0361,01,'~',0212,0367,0251,0370,'d',0214,'=','v','p','i',0357,0361,0315,'4',0267,0224,020,0330,0271,0254,'/','f',0202,'l',0354,0317,0322,0222,0224,0240,'e','H',0260,0343,0306,'q',0224,'a',0310,0310,0215,0134,'?',0365,'N',0272,0267,0226,'V',0263,'r','~','/',04,0307,0214,'O',0340,'H',0362,'~',0324,0333,0210,'y',01,0304,033,0203,0306,0343,'H','y','9',034,027,025,0211,'l',0302,'W',0374,'H','z','}','*','D','G',0242,0253,'+',0251,0267,0305,'%','%','F',0311,0250,033,'9','&','M',0226,0357,0205,'5',023,016,0215,04,'Y',0224,0377,0,0236,'F','-',0216,0265,010,026,0232,'7','_',0355,'N',0272,0267,0226,'V',0263,'r','~','7',012,0306,0335,0303,0216,'C',0252,'j','4',0226,0345,0266,035,'h',0351,0310,'~',';','R','S',0221,0324,0334,'T',0375,0226,07,0307,020,0377,0,0212,0223,06,'D','C','g',0221,'o',0206,'C','j','p',0345,'@',0275,'B',0331,0251,'O',0233,0275,0341,025,013,010,0213,04,'x',023,'s',0357,0311,0306,'6',0204,'4','L','x',0275,'}',0351,'J','+','9',0225,0361,0360,'1',027,0340,'8',026,0331,0377,0,025,0206,0342,0354,'b',')',026,'6','_',0267,'%',0306,0220,0362,'r',0270,'.','*','^',0315,0304,0220,011,'k',0302,'j','V',0315,'L','c','T',014,0303,0351,'N','2',0343,'F',0313,026,0370,0,011,0351,'Q','p','i',0222,0274,0210,0322,0241,0354,0252,'S',0342,0224,0253,0375,05,'F',0201,032,047,0340,0242,0334,0227,0237,'j',':','7',0216,0233,012,0305,0266,0201,0311,0177,0302,'c','D',0376,0365,0327,0344,'(','Z',0233,'9',0220,'l','k',013,0332,'^',0215,'L',0375,'i',0267,020,0352,'B',0320,'n','9','O','G','f','@',0263,0251,06,0244,0354,0334,047,0315,0323,0341,0247,0266,'M',0320,011,'i','`',0323,0273,'=',0210,'6','l',021,0177,0265,'.',024,0206,0357,0231,07,'J',0312,'}',0270,0200,047,0245,'!',0207,0134,0362,'&',0364,0326,015,'9',0344,0346,'C','f',0231,0331,'Y','k','?',0304,' ',012,0217,0262,0214,'"',0305,0345,0336,0230,0303,'b','G',0374,'6',0307,'/',022,0307,'#',0300,031,'S',0342,'U','M',0304,'_',0236,0274,0316,0237,0222,0341,0370,0264,0214,'=','^',03,0247,0265,'@',0306,0342,0316,0360,0203,'e','{','s','N',0242,0306,0225,031,0205,0214,0252,'@',0375,'+',0375,'&',017,0366,0205,';',0200,'a',0356,0233,0224,'[',0355,'_',0355,0274,';',0372,'O',0353,'_',0355,0314,';',0372,'O',0353,'C',011,0202,'?',0365,012,'j',04,'V',0177,015,0260,')','(','J','<',0242,0334,0331,'2',0331,0206,0234,0357,'*',0325,0212,'m','"',0337,0273,'Q','t','M',025,025,033,0237,0223,0205,024,0233,0212,0201,0264,'r','b',0370,035,0361,'&',0241,'b',0361,'g',017,02,0254,'}',0276,'9',0371,015,'F','N','w','U','a','S',0366,0244,017,04,'A',0376,'j','D',0247,0245,'+',';',0312,0277,0312,0322,0242,0223,'t',0324,015,0243,0223,027,0302,0357,0211,'5',013,034,0211,'7','@','r',0237,0255,03,'}','G',0304,0311,0233,036,'"','s','<',0273,'T',0335,0252,0323,',','T',0377,0,0223,'R','%',0275,')','Y',0235,'U',0376,'_',0322,0242,'b',0322,0341,0233,0266,0252,0213,0265,0200,0351,'!',037,0245,'F',0305,'!',0312,0374,'5',0320,'7',0324,'|',033,0262,'X','`',']',0305,0201,'R',0266,0236,'+',':','4','3',032,0231,0264,'r',0344,0202,0224,0370,'G',0322,0226,0342,0334,'7','Q',0277,0315,01,0267,'J',0217,0211,0313,0215,0370,'N',032,'c','j',0344,0243,0361,'R',015,'3',0265,'1',026,'l',0264,0221,'M',0343,'0',035,031,0203,0226,0373,0322,'^','m','~','U',017,0327,0224,0245,'%',036,'c','j','s',021,0210,0311,0312,0267,05,'=',0264,0260,'Z',07,')','$',0323,0373,'Z','z','0',0337,0353,'R','1',0371,0322,'?',0236,0303,0351,'K','q','k','7','Q',0371,0342,']','Z',015,0322,'i',0274,'B','S','j',0314,0227,015,0177,0256,0342,'?',0335,'4',0336,0323,'O','m','6',0275,0353,0375,0323,';',0351,0372,'W',0373,0246,'w',0323,0364,0257,0367,'L',0357,0247,0351,'_',0356,0231,0337,'O',0322,0225,0217,0342,04,0337,'y','N',0342,0363,'_',026,'[',0206,0227,'%',0347,05,0226,0242,'j',0344,0377,0,0365,0317,0377,0304,0,'D',021,0,01,03,02,02,06,06,07,06,06,01,02,07,0,0,0,01,02,03,04,0,021,05,022,06,023,' ','!','0','1',020,'4','@','A','Q','q',024,'"','2','P','a',0221,0241,026,'3','B','R','S',0321,025,'#',0201,0261,0301,0341,'b','5',0360,'C','T','`','p','r',0200,0361,0377,0332,0,010,01,02,01,01,'?',01,0377,0,0352,'m',0352,0365,'z',0277,0376,0201,'*','H',0346,'i','R',0332,'O','}',031,0351,0356,024,'g',',',0362,024,'e',0272,'{',0353,'^',0357,0346,0242,0342,0216,0362,'k','2',0274,'k','2',0274,'k','2',0274,'k','2',0274,'k','^',0347,0346,0244,0311,'u','=',0364,0231,0256,016,'t',0231,0376,'"',0223,'5',0263,0316,0222,0362,027,0310,0373,0341,'o',0266,0216,'f',0227,'?',0362,012,0134,0247,'W',0337,'D',0223,0317,0260,0245,0347,021,0310,0322,047,'(','{','B',0221,'-',0265,0320,' ',0362,0367,0212,0224,023,0274,0323,0223,'R',0237,'c','}','9','%',0307,';',0373,'B',034,'Z','=',0223,'M',0316,'?',0216,0220,0362,034,0366,'O',0273,'T',0240,0235,0346,0235,0234,06,0344,'R',0334,'S',0236,0321,0355,0200,0333,0225,'5','1','H',0334,0255,0364,0333,0350,'w',0221,0367,'I','6',0247,'%','w','6','/','K',017,'9',0355,'V',0251,'~',025,0252,'_',0205,'j',0227,0341,'E',0265,0216,0356,0330,015,0271,'S','3',024,0235,0313,0246,0334,'K',0202,0351,0367,'3',0257,'%',0241,0276,0220,027,'$',0335,'^',0315,'%','!','"',0302,0212,0222,0236,'f',0265,0315,0376,'a','Z',0346,0377,0,'0',0240,0342,025,0310,0364,'H',0210,017,0254,0215,0200,'/',0312,0223,035,0325,'w','R','`',0270,'y',0320,0200,';',0315,010,'M',012,0364,'V',0274,')',',',0266,0236,'B',0265,'h',0360,0255,'Z','<','+',0321,0232,0360,0245,'C','h',0367,'R',0240,' ',0362,'4','`','+',0270,0322,0242,0272,0236,0352,'R',024,0236,'c',0206,0205,0251,06,0351,0246,'&',05,0356,'_','?','q',0362,0247,0346,'e',0365,'Q','M',0202,0363,0226,'4',0,'H',0260,0254,0177,'H',0275,0,0372,'<',0177,'o',0373,'S',0370,0204,0251,'&',0356,0270,'M','k',0134,0374,0306,0265,0256,'~','c','M',0312,'}',0243,'t',',',0212,0301,'4',0241,0304,',','1','0',0334,036,0372,04,'(',0134,'T',0266,'l',0273,0247,0276,0221,015,0305,'s',0335,'H',0204,0204,0373,'[',0351,'-',0245,034,0207,030,0200,'y',0322,0342,0264,0256,0352,0134,025,017,'d',0322,0332,'[','~',0320,0341,'3',')','M',0356,'<',0251,016,'%',0301,'t',0373,0201,'J',011,027,'4',0374,0242,0346,0344,0362,0350,0202,'=','s','R',']',014,'2',0247,017,'p',0251,016,0251,0367,'T',0342,0273,0366,0264,'f','Q',0223,0207,0246,0347,'x',0335,0331,'H',07,0235,'9',021,0265,0362,0335,'N','D','q',0275,0374,0370,'-',0270,0246,0215,0323,'L','>',0227,'G',0307,0211,'q','Z',0304,0326,0271,025,0256,'E',07,022,'x',0316,':',0226,0205,0325,'O',0276,'^','?',016,0230,036,0331,0254,'W',0250,0273,0345,0267,0241,0275,'I','^','}',0241,0330,0310,'r',0235,0210,0266,0367,0215,0374,0,'J','M',0305,'G',0224,034,0365,'U',0317,0200,'T',05,';','1',010,0247,'1','/',012,'T',0327,017,'*','2',0134,'=',0365,0256,'_',0215,'k','W',0343,'H',0222,0340,'5',035,'E','I',0271,0342,':',0352,'Z','M',0315,':',0352,0235,'U',0316,0304,017,'l',0326,'+',0324,']',0362,0333,0320,0336,0244,0257,'>',0324,0354,'T','9',0313,0235,'8',0312,0232,'>',0267,02,'4',0234,0376,0242,0371,0355,'<',0372,'[',024,0374,0325,'/','p',0242,'I',0347,0265,021,0202,0342,0257,'H','N','Q','n',033,0256,0245,0244,0334,0323,0256,0251,0325,0134,0354,0300,0366,0315,'b',0275,'E',0337,'-',0275,015,0352,'J',0363,0355,'j','H','P',0261,0247,0341,0345,0365,0221,0300,0215,047,'?',0250,0276,'{',022,'$',06,0205,'<',0372,0235,';','m','6',0134,'U',0205,'F','`','4',0236,032,0326,033,027,'4',0363,0245,0325,'_','j',07,0266,'k',025,0352,'.',0371,'m',0350,'o','R','W',0237,'m','~','(','s',0326,'O',':','R','J','M',0216,0334,'Y',01,0301,0224,0363,0350,'y',0320,0332,'j','C',0345,0325,'m',0245,'%','f',0302,0241,0306,015,0213,0236,031,'!','"',0346,0244,'?',0256,'V',0356,'[','q',030,'S','~',0262,0253,025,0352,'.',0371,'t','A','e','2','%',0264,0312,0371,')','@','|',0315,'}',0217,0303,'?',0345,0363,0257,0261,0370,'g',0374,0276,'t',0346,0206,0341,0352,036,0241,'P','>',0177,0352,0261,'l','-',0334,'&','F',0245,0315,0343,0270,0370,0212,0320,0336,0244,0257,'>',0334,0373,01,0341,0361,0247,033,'S','F',0312,0332,0214,0311,047,'5','-','y',05,0315,'K',0222,0134,'6',033,'`','^',0240,0305,0267,0254,0252,02,0334,'9','r','3','z',0211,0333,0215,033,047,0256,0276,'}',030,0257,'Q','w',0313,0243,06,'c',0322,'1',026,'[',0370,0377,0,'m',0365,0245,0263,0246,'D',0226,0204,0260,0341,'J','J','{',0217,'}',0315,'5',0215,0342,'H','Z','U',0257,'Q',0376,0265,0244,0222,0245,'a',0216,0263,'1',0205,0234,0267,0261,035,0307,0376,0367,0326,0233,0267,'x',0314,0271,0340,'m',0363,037,0352,0264,'7',0251,'+',0317,0267,0272,0322,']','M',0215,':',0322,0232,'U',0216,0303,'M',0225,0232,'H',015,0246,0246,0312,0277,0252,0236,04,'(',0271,0216,'c','I','N','Q','n',034,0247,0265,'i',0260,0347,0267,026,'8','H',0316,0256,0234,'W',0250,0273,0345,0321,06,'Q',0205,'%',0271,03,0360,0233,0325,0260,0374,'z','8','Q',01,'i',0372,0217,0362,')',0215,036,0303,'#',',','8',0333,';',0307,0304,0237,0356,'k','J',0261,026,'&','>',0324,'6',0225,0271,047,'y',0356,0377,0,0261,0337,'Z',']',0210,0306,0230,0323,'H',0216,0340,'V',0363,0312,0264,'7',0251,'+',0317,0334,016,0264,0227,'S','c','N',' ',0266,0254,0247,0241,0264,025,0233,'S','M',06,0305,'M',0225,0224,'e',024,'M',0315,0366,0342,0307,'.',0252,0346,0233,'@','@',0267,015,'k',010,'N','c','N',0270,']','V','c',0265,022,'>','o',']','[',030,0257,'Q','w',0313,0246,016,011,0214,'(',07,0243,' ',0247,0343,'|',0277,0344,032,'w',05,0322,047,0306,'W','I','#',0342,0277,0367,'S',0260,'Y',0330,'k','a',0331,'(',0260,'&',0334,0307,'F',0206,0365,'%','y',0373,0205,0366,03,0251,0370,0326,'C',0233,'-','G','c',' ',0271,0251,'R',03,'I',0245,0254,0254,0334,0355,0260,0321,'u','V',0246,031,015,0247,0211,'1',0354,0312,0310,'6',0242,0261,0255,'U',0317,'*',033,0266,'1','^',0242,0357,0227,'F',06,0322,036,0304,0231,'C',0234,0257,'X',0266,'2',0306,020,0204,0251,0340,'I','W','+','W',0333,'v','?','D',0374,0305,'c',0272,'D',0336,'/',031,',','!',0262,0233,033,0375,017,0357,0321,0241,0275,'I','^','~',0342,'-',02,0254,0324,0363,0241,0244,0323,0357,027,'U',0266,0204,025,0233,012,0211,030,'6',0236,'$',0207,'u','H',0275,023,'}',0373,'-',0240,0270,0254,0242,0233,'@','m','9','F',0316,'+',0324,']',0362,0350,0202,034,'T',0246,0222,0311,0262,0212,0205,0274,0357,'X',0366,012,0376,'0',0313,'V','P',013,'O','>','v',0337,0317,0373,'W',0330,0251,0277,0250,0237,0257,0355,'X',0256,0217,'H',0302,'Y',017,0272,0260,'A','6',0335,0177,0217,0303,0341,0321,0241,0275,'I','^','~',0342,'Z',0202,05,0352,'d',0235,'b',0254,'6',0300,0275,'B',0213,'o','X',0327,'.','$',0267,'u',0213,0267,0206,0324,'F','u','i',0314,'y',0355,'b',0275,'E',0337,'.',0210,0317,0230,0317,0241,0361,0370,'H','?','*',0373,'m','+',0364,0223,0365,0257,0266,0322,0277,'I','?','Z',0305,0264,0211,0354,']',0200,0303,0210,02,0306,0373,0277,0257,0357,0321,0241,0275,'I','^','~',0341,'&',0325,0210,'K',0312,',','(',0311,'9',0251,0267,'B',0366,0241,'E',0314,'s',032,'H',0312,'-',0304,0222,0356,0255,033,'Q',032,0326,'.',0347,0220,0333,0305,'z',0213,0276,'U',0202,0303,'n','|',0366,0343,'=',0354,0233,0377,0,'b','k',025,0301,0343,'C',0305,'X',0204,0335,0362,0257,'-',0374,'w',0250,0212,0373,033,0207,'x',0253,0346,'?','j',0373,033,0207,'x',0253,0346,'?','j',0322,',',02,'&',025,025,'/','0','M',0312,0255,0277,0310,0374,'>',035,032,033,0324,0225,0347,0356,031,0222,'u','b',0324,0341,0326,'s',0247,0231,0311,0276,0202,0212,'i',0251,035,0306,0201,0277,'L','X',0372,0325,'S','h',010,026,0342,0314,'s',';',0226,0360,0331,02,0373,0251,0206,0365,'H',03,'o',025,0352,'.',0371,'T','y',016,0305,'t','<',0312,0254,0241,'O',0342,022,0244,0274,0231,016,0256,0353,'O','#',0345,0276,0206,'7',0212,036,'O',0252,0277,0214,0342,0337,0254,0252,0225,0210,'N',0224,0214,0222,'V','H',0370,0364,'h','o','R','W',0237,0270,037,'t','6',0232,'}',0322,0352,0257,0320,0363,0205,'J',0265,'&','>','d',0336,0224,0202,0212,'i',0342,0232,'I',0270,0275,'4',0321,'u','V',025,035,0200,0322,'j','C',0331,06,0352,'m','Y',0322,025,0303,'u','y',020,'U','D',0337,'~',0314,'6',0263,0253,'1',0356,0340,'b',0275,'E',0337,'.',0214,'.',' ',0235,'5',0250,0352,0344,0243,0277,0313,0276,0257,017,013,'d',03,0225,0264,0374,0277,0375,0257,0264,030,'_',0353,0212,0322,0254,'R',034,0330,'I','n',';',0201,'G','0','?','C',0321,0241,0275,'I','^','}',0275,'j',0312,'/','S','$',027,025,'a',0320,'y','R',0367,'*',0231,'|','Z',0306,0244,'-',047,0225,'0',0316,'m',0364,0204,0337,'p',0250,'q',0262,013,0232,'u',0300,0330,0247,034,'+','5',01,'|',0321,0303,0236,0275,0301,033,'L','7',0253,'@',034,014,'W',0250,0273,0345,0321,0207,0274,0344,'y','m',':',0320,0272,0201,033,0274,'~',037,0326,0264,0262,034,0234,'A',0226,035,0216,0331,'6',0276,0353,'o',0337,'n',0357,0351,'_',0301,0261,037,0374,0272,0276,'F',0244,'a',0362,0342,0247,';',0355,024,0217,0210,0350,0320,0336,0244,0257,'>',0337,':','U',0275,'Q',0320,0245,0204,'s',0257,'J',024,0264,0207,'w',0246,0212,'J','i',')','*','4',0322,'2',0213,'T',030,0277,0211,'T','H','B','i',0367,'J',0317,'C',013,0310,0340,'<','9',013,0326,'8','N',0314,'F',0363,0271,0301,0305,'z',0213,0276,']',020,'^','L','y','m','<',0276,'I','P','?','#','_','l','0',0317,0371,'|',0253,0355,0206,031,0377,0,'/',0225,'i',036,'=',017,024,0210,0226,'c',0336,0341,'W',0336,'>',07,0367,0350,0320,0336,0244,0257,'>',0335,'.','@','m','4',0265,0225,0233,0232,'&',0324,0352,0312,0325,'J','F','Z','d',021,0353,'R',026,0227,015,0215,04,01,0312,0241,0307,'.','*',0346,0220,0220,0201,'R',0236,0356,033,021,0327,0235,0260,'x','/','+','"',011,0332,0204,0336,'T','f',0361,0340,0342,0275,'E',0337,'.',0210,0372,0275,'r','5',0276,0315,0305,0374,0273,0353,'I',0360,0210,'0','!','!',0350,0255,0330,0225,01,0314,0362,0261,0370,0354,'h','o','R','W',0237,'m','u',0300,0201,'z',0224,0361,'u',']',016,0373,'4',015,0225,'[',0334,'U','8','C','i',0312,'*',':','n',0253,0323,014,0227,'U','j','a',0240,0332,'i',0367,0262,0213,'R',0225,0230,0337,'b',02,0271,0247,0203,'9','V','@','N',0312,'F','c','j','B','r',0244,016,016,'+',0324,']',0362,0350,0202,0312,'d',0312,'i',0225,0362,'R',0200,0371,0232,'{',05,0217,'"',022,'`',0272,0245,024,0247,0226,0375,0377,0,0332,0276,0306,0341,0336,'*',0371,0217,0332,0264,0213,0,0211,0205,'E','K',0314,023,'r',0253,'o',0362,'?',017,0207,'F',0206,0365,'%','y',0366,0302,'m','S',0244,0334,0345,035,013,'p','"',0222,0350,'s','u',':',0321,'I',0240,'J','h',05,'8','i',0206,'{',0205,'C',0215,0253,'M',0372,047,'$',0205,0337,'f','*',0262,0272,'8','3',0225,'w','-',0263,015,031,0235,0341,'b',0275,'E',0337,'.',0206,0326,0246,0226,034,'A',0261,025,0374,'w',023,0375,'u','W',0361,0334,'O',0365,0325,'R','q',')',0223,021,0253,0220,0341,'P',0370,0364,'h','o','R','W',0237,'l',0233,'#','V',0233,'R',0216,'c','s','D',0330,'^',0234,'Y','q','T',0233,'4','.','k',0322,'3','s',0244,0264,0205,0357,0244,'6',023,0312,0240,0305,0374,'F',0200,0267,'D',0324,'f','n',0373,' ',0330,0336,0222,'n',0220,'x',017,0253,'3',0204,0354,0300,'O',0252,'U',0302,0305,'z',0213,0276,']',020,0343,0231,'r',021,035,'?',0210,0201,'L','a','x','l','$',0245,0220,0332,0177,0255,0256,'~','|',0350,0267,0206,'%',0315,'Q',010,0315,0341,0352,0337,0345,'Z','`',0334,'F',0242,'!',015,04,0205,0346,034,0255,'{','Y','_','N',0215,015,0352,'J',0363,0355,'o','8',033,'M',0351,0367,'K',0252,0350,'{',0331,0240,'l','o','D',0225,0232,'R','r',0324,'o','f',0241,0307,0326,'*',0346,0220,0234,0202,0335,'+',031,0222,'E',021,'m',0333,'1','U',0231,0241,0266,0243,'d',0223,'D',0334,0337,'f','*','r',0264,'8','X',0257,'Q','w',0313,0243,'G','m',0374,'U',0214,0336,'?',0340,0326,'2',0341,'F',0220,'C',0360,0335,0365,'Q',025,0244,0270,'t',0265,'b',0272,0346,'P','N','k','X',0217,021,0273,0374,'V',0233,'0',0203,035,0251,037,0212,0366,0376,0226,047,0374,'t','h','o','R','W',0237,'j','Q',0260,0251,0322,'s',034,0243,0241,'J',011,0347,'Z',0304,'/','u','*','1',047,'u','e','K',0134,0353,'{',0212,0250,0254,025,'Y','"',0230,'d','6',0235,0227,0323,0225,0302,'6','`','*',0350,'#','n','A',0312,0321,'#','d',013,0356,0244,013,'$',016,026,'+',0324,']',0362,0350,0207,'#',0321,'$',0267,' ',013,0345,' ',0326,'7',0216,'7',0213,026,0326,0206,0362,')',035,0367,0377,0,'U',07,'K',' ','<',0310,'2','U',0221,'}',0373,0217,0322,0325,0244,'x',0342,'1','U',0245,0266,07,0250,0237,0251,0350,0320,0336,0244,0257,'>',0325,'6','F','A','a','D',0346,'7','4',0245,'e',027,0247,034,'+','5',0274,'S','R','-',0270,0322,0333,016,0357,024,0304,'{',033,'T','(',0331,05,0366,0246,0246,0316,'_','f',01,0365,0210,0333,0232,'l',0326,0313,'C','3',0200,'p',0361,'^',0242,0357,0227,'D',0235,022,0303,'_',0336,0200,'P','~',07,0367,0275,'J',0320,0251,'(',0337,031,0300,0257,'=',0337,0275,'J',0301,0261,010,0177,'|',0311,0267,0217,'1',0363,035,':',033,0324,0225,0347,0332,'_','t','6',0233,0323,0356,0227,'U','~',0211,'*',0356,0246,0323,'a',0230,0322,'S',0254,'U','-','9','M',0252,'0','5',06,'5',0375,'c','@','[','j','z','y',035,0230,'F',0316,0333,'n','q',0376,']',0266,'b',0247,'3',0243,0207,0212,0365,027,'|',0272,'#',0343,0370,0234,'o','a',0342,'|',0367,0377,0,'z',0201,0245,0223,0336,'P','A',0217,0254,0377,0,0343,'{',0377,0,0232,0211,'!',0311,'-',0347,'q',0242,0203,0340,'m',0376,'?',0315,0253,'L',0330,'i','0',0322,0350,'H',0315,0234,'o',0266,0376,'J',0350,0320,0336,0244,0257,'>',0320,0243,'a','S',0244,'g','9','G','C',0213,0310,'/','I','P','{',0235,'>',0234,0211,0260,0246,0334,0311,'H',0376,'b',0352,034,'l',0346,0233,'@','@',0266,0334,0344,0372,0227,0331,0210,'l',0350,0333,0237,0311,';','0',0307,0363,'x','x',0257,'Q','w',0313,0242,'6',0216,'a',0221,'w',0206,0256,'~',';',0377,0,0327,0322,0247,0342,0321,'p','t',0204,0251,07,0372,047,'w',0317,'p',0251,':','l',0362,0267,'F','h',017,'=',0377,0,0265,'N',0305,0246,0342,';',0244,0271,'q',0341,0335,0321,0241,0275,'I','^','|','K',0322,0236,'J','k',0322,0321,'H','u','+',0345,0301,0233,'#','"','m','D',0334,0336,0224,'r',0213,0323,0316,0347,0335,'Q',0221,'a','z','q',031,0305,030,0306,0365,026,'6',0373,'T','V',03,'i',0340,'M',027,'k','e',0217,0275,'N',0334,0376,'I',0331,0201,0355,0236,036,'+',0324,']',0362,0350,0215,0246,'S',0232,0334,0360,013,0372,037,0246,0357,0245,'F',0323,030,'/','n','}','%',037,'Q',0377,0,0177,0322,0204,014,033,030,'F',0261,0264,'%','_',021,0270,0375,'-',0365,0255,'"',0321,0370,0370,'S',011,0220,0302,0216,0363,'k',037,'"',0177,0307,'F',0206,0365,'%','y',0360,0335,0222,0226,0351,0354,'@',0235,0311,0245,0274,0265,0363,'5','s','L',0276,0246,0315,'G','t','8',0235,0267,0234,015,0246,0244,0277,0235,'W','4',0231,0,0233,'S',0211,0316,0235,0324,0244,024,0232,'m',0342,0212,'C',0201,'t',05,0352,014,'l',0243,'1',0340,0312,0373,0243,0262,0307,0336,0247,'n',0177,'$',0354,0300,0366,0317,017,025,0352,'.',0371,'t','G',0320,0270,'h',0373,0347,012,0276,0237,0277,0367,0246,0360,'l','*',010,0317,0252,'H',0370,0235,0377,0,0336,0244,'i',036,027,014,'e',016,'^',0335,0311,0337,0376,0276,0265,0217,0351,023,'x',0263,'"',';','M',0330,03,'{',0237,0352,'9',0177,'_',036,0215,015,0352,'J',0363,0340,0223,'j',0225,'4','#','p',0245,0272,0247,016,0375,0234,'=',0353,034,0273,'D',0332,0247,'I',0314,'r',0212,0220,0357,'p',0246,033,0271,0271,0243,' ',03,'j',')','K',0202,0234,'`',0246,0230,012,0315,'P','c',0347,'9',0215,'%','9','E',0270,'2',0276,0350,0354,0261,0367,0251,0333,0237,0311,';','0','U','g','-',0303,0305,'z',0213,0276,']',022,0264,0263,022,0221,0271,04,' ','|',07,0371,'7',0247,0344,0275,'%','Y',0236,'Y','Q',0370,0235,0215,015,0352,'J',0363,0340,0316,0221,0220,'X','Q','%','F',0347,'i',0225,0344,']',0351,0245,'f','N',0314,0311,032,0264,0324,0207,'H',0337,'W',0271,0337,'E',0320,0224,'X','S','h','+','U',022,033,'M','!',0340,0275,0306,0243,0307,0316,0255,0324,0303,'A',0264,0360,0246,'*',0315,035,0226,'>',0365,';','s',0323,'t',0203,0263,017,0357,'G',017,025,0352,'.',0371,'m',0350,'o','R','W',0237,0,0324,0345,']','|',010,016,0346,'E',0266,035,'^','D',0336,0244,0275,0255,']','8',0330,'X',0247,031,'(',0350,0216,0342,'S',0316,0237,'s','1',0260,0250,0254,0225,032,0205,033,' ',0277,016,'w',0335,'l',0306,'N','g','F',0334,0357,0272,0331,'c',0357,'S',0303,0305,'z',0213,0276,'[','z',033,0324,0225,0347,0300,'5','=','6','_',02,03,0271,027,'j',06,0343,0240,0356,0251,0362,0177,010,0351,'"',0364,0354,'~',0361,'D',024,0323,'H',0316,'k',017,0213,0336,'h',013,016,034,0376,'C','f',037,0336,0215,0271,'_','t','v','R','l','A',0240,'n','8','X',0257,'Q','w',0313,'o','C','z',0222,0274,0370,'8',0223,'}',0374,04,'+','*',0257,'Q',0234,0316,0216,0211,'O',0352,0323,'K','Y','Y',0271,0331,'[','A','u',012,'%',0325,'M','6',033,'M',0270,0223,0215,0326,06,0314,017,'l',0355,0270,'.',0202,'6',0230,'V','f',0301,0341,'b',0275,'E',0337,'-',0275,015,0352,'J',0363,0340,0315,'F','t','Q',0335,0300,0205,047,'V','l','i','r',0220,0224,0336,0244,0310,'/','+','i',')','*','6',025,016,'>',0255,'<','Y','J',0314,0351,0331,0200,'7',023,0300,'p','e','Y',033,'0',0225,'v',0355,0302,0304,033,'.',0304,'q',03,0274,'R',0206,'S','m',0255,020,'h',0267,03,'1',0357,'<',027,'F','d',0323,0350,0310,0262,'8','%','j',';','p','#','_',0326,'4',05,0270,0204,0330,'^',0224,'n',0242,'v','a',0246,0315,'p','&',047,'+',0273,'0','W','e',0345,0341,'s',0255,'"',0301,034,0206,0361,'}',0241,0352,035,0234,'3',014,'{',022,'x','6',0330,0335,0343,'Q','#','"','#',')','e',034,0207,04,0326,' ',0336,'U','_',0217,031,0222,0352,0251,0246,0302,023,'n',',',0245,0344,'l',0355,'4',0234,0250,03,0201,'=','<',0225,0262,0322,0362,',',032,033,0370,'K','B',0134,031,'T','.','*','N',0213,0341,0322,'7',0345,0313,0345,'_','c',0240,'x',0232,0373,035,03,0304,0323,'Z','%',0207,0266,'n','n','j','<','V','b',0247,'#',')',0260,0341,0317,'o','2','/',0306,'J','s',033,012,0207,034,'6',0236,'4',0365,0362,'F',0313,')',0316,0340,034,031,'H',0316,0331,0332,0212,0274,0355,0216,0324,0362,'s','&',0236,'N','U',0236,',',010,0337,0210,0320,026,0343,'>',0274,0356,023,0263,05,027,'^','n',011,027,026,0247,023,0221,'E',';','0','W','e','e',0355,'F',0261,06,0262,0253,'7',022,'3','%',0325,'S','H',0310,0233,'q',0245,'/','#','g','j',032,'2',0267,0177,036,024,0344,'Y','y',0266,'P',0242,0205,'f',024,0205,'f','M',0370,'2',0346,0261,011,0275,'c',0352,0260,0247,0364,0322,':',015,0231,'A','5',0366,0330,'~',0217,0326,0276,0333,017,0321,0372,0323,'Z','j',0321,'?',0314,'n',0302,0240,'b',0221,0261,024,0346,'a',0134,'I',0315,'f','E',0370,'i','N','c','a','P',0330,0325,0247,0217,'5',0314,0313,0313,0262,0204,0346,'P','M','$','e',026,0341,'J','o',';','g','j',013,0267,031,017,01,0327,03,'H','.','+',0272,0261,'|','M',0334,'J','A','Z',0216,0356,0355,0230,'s',035,0202,0360,'y',0243,'c','X','|',0264,0316,0214,0227,0323,0337,0303,'q','9',0223,'j',0220,0214,0213,0341,'@',0217,'s',0230,0320,026,0343,':',0275,'Z',012,0250,0234,0306,0347,'f',023,'y',0225,0233,0207,0316,0237,'o','V',0341,033,'-',0257,'V',0240,0252,'J',0263,013,0215,0274,'}',0305,'7',0206,0272,0244,0370,'m',0350,'{',0212,0134,02,017,'q',0342,'b',014,0376,'!',0301,0216,0311,'u','T',0313,'a',0264,0333,0217,'5',0333,0234,0203,'j','3','z',0266,0370,0223,'Z',0314,0234,0343,'j',023,0337,0370,'g','o','H',0377,0,0351,0216,0355,0350,'o','R','W',0237,021,0366,0363,0246,0236,'o','V',0253,'m',0244,'f','6',0250,'Q',0365,'i',0277,035,0347,'5','H',0315,'D',0346,'7',';','1',0232,0326,'/',0212,'E',0305,0251,0346,0365,'k',')',0331,'J',0212,016,'a','M','8',035,'N','a',0265,'>','?',0245,'E','[','^','"',0235,'m','L',0254,0266,0276,'c','d',013,0356,025,0243,0321,014,'8',010,'J',0206,0363,0277,0213,'6','.',0260,0134,'R',0233,'R','M',0255,'Y','M','[',0243,')',0244,'0',0265,0362,025,026,016,'_','Y','T',05,0270,0362,0236,0326,'*',0303,0226,0324,'V',0265,'h',0343,'M','k','2','s',0215,0250,0317,'j',0225,0277,0225,'s',0332,0307,'t','m','3',0316,0276,'>',0345,0377,0,'z',0177,04,0237,034,0331,'m',032,0376,033,'3',0364,0217,0312,0277,0206,0314,0375,'#',0362,0246,0260,0211,0317,034,0251,'h',0326,013,0242,0245,0225,0207,0346,0363,0360,0256,0134,'[','^',0224,0302,025,'^',0212,0212,0364,'&',0315,'z',03,'t','"',' ','R','Z','J','{',04,0307,0362,014,0203,0236,0324,'f',0265,0213,0343,0221,'z',0220,0336,0251,'v',0332,0207,'"',0376,0242,0275,0334,0363,0241,0244,0334,0322,0326,'V','s',035,0236,'u',031,0255,'R',';',04,0206,'u',0251,0370,0321,026,0335,0262,011,'I',0270,0250,0317,0353,0223,0277,0237,0273,024,0240,0221,'s','O',0274,'^','V',0324,'6','3',034,0347,0261,'L','b',0337,0314,033,'H','Y','l',0346,'M','2',0350,'u','7',0367,'Q',0335,'R','_','.',034,0243,0226,0323,'-',0227,'U',0226,0222,0220,0221,'a',0330,0224,02,0205,0215,'>',0311,'e','V',0332,'i',0325,'4',0253,0212,'i',0324,0272,0233,0217,'t','r',0251,'2','s',0372,0251,0345,0264,05,0367,'T','f','5','I',0337,0317,0262,'<',0320,'u','6',0245,0240,0266,'r',0253,'i',0247,'T',0322,0256,')',0227,0322,0360,0335,0356,'e','(','$',0134,0324,0211,'Z',0317,'U',034,0266,0342,'G',0267,0256,0256,0315,'&','>',0264,0134,'s',0242,012,'M',0216,0322,026,'[','9',0223,'Q',0344,0207,'w',036,'~',0344,'Z',0303,'b',0346,0237,0220,0247,0267,'w','m',0305,0215,0237,0327,'W','.',0321,'*','6',0177,']','<',0366,0301,0267,'*','b','g',0341,'r',0201,0277,0270,'^',0220,0226,0207,0306,0234,'u','N',0233,0253,'n','<','r',0351,0271,0345,'H','N','Q','n',0323,'&','6',0177,']',034,0370,014,0311,'S','^','T',0323,0311,'t','n',0355,0305,'A','"',0346,0237,0231,'}',0315,0321,'7',0347,0267,036,'9','t',0334,0362,0244,0244,'$','X','v',0271,'1','s',0372,0310,0347,'D',024,0233,035,0260,'J','w',0212,'f','m',0267,'9','H','Z','V','.',0223,0332,0271,'S',0263,020,0215,0311,0337,'N','<',0267,'=',0243,0300,'b',')','s','z',0271,'R','R',022,',',';','k',0361,0203,0333,0373,0351,'h','-',0234,0252,0340,'%','j','A',0272,'i',0251,0335,0316,'R',035,'C',0236,0311,0354,0304,0201,0316,0234,0230,0204,0373,';',0351,0311,013,'w',0237,06,'<','L',0336,0262,0353,0227,'o','u',0224,0272,',','i',0350,0352,'h',0374,'8',' ',0224,0357,024,0334,0307,023,0317,'}','"','c','j',0347,0272,0202,0202,0271,'v',025,0310,'m',034,0315,'9','8',0237,'`','R',0335,'[',0236,0321,0340,0245,'%','f',0311,0246,'"',04,'z',0312,0347,0356,'"',01,0334,'i',0370,0177,0211,0272,' ',0244,0330,0360,0222,0265,047,0331,'4',0211,0216,047,0236,0372,'L',0364,0376,'!','I',0226,0321,0357,0240,0342,017,'#','W',0333,'*','H',0346,'h',0310,'i',';',0211,0245,'N','@',0345,'K',0234,0243,0354,0212,'S',0316,'/',0231,0341,0263,031,'N',0357,0356,0246,0332,'K','B',0311,0367,'+',0254,'!',0336,'t',0354,'e',0265,0306,013,'P',0357,0255,'{',0277,0232,0223,')',0324,0367,0327,0246,';',0343,'^',0230,0357,0215,'k',0335,0374,0324,']','Z',0271,0232,'$',0236,'|','T','6',0247,015,0223,'L',0303,011,0336,0272,0345,0356,'~','t',0354,'4','/','z','w','S',0221,0326,0327,'>',0334,0224,')','f',0311,0246,0240,0367,0271,'H','B','P',',',0237,'u',0363,0247,'a',0241,'{',0323,0272,0234,0214,0343,'}',0251,015,0255,'~',0310,0246,0340,0367,0254,0322,020,0224,013,'$','{',0301,0306,020,0347,'1','K',0201,0371,015,'-',0207,021,0314,'v','D',0241,'J',0344,')',020,0226,0257,'k','u','7',015,0264,'o',';',0350,0,'9','{',0325,'L',0266,0276,'b',0225,05,07,0331,'4',0250,'.',016,'T','c',0272,';',0250,0244,0216,'c',0204,05,0371,'P','i',0305,'r',024,0230,'n',0232,'L',017,0314,'i','1','Z','O','u',0,07,'/','~',020,015,026,0220,'w','Z',0275,025,0257,012,'0',0232,'5',0350,'-','W',0240,0265,'^',0202,0325,'z',013,'U',0350,0255,'x','R','c',0266,0236,'B',0202,022,'9',017,0375,0272,0377,0304,0,'F',020,0,01,03,01,04,06,07,05,06,04,05,02,07,0,0,0,01,0,02,03,021,04,022,' ','!',020,'0','1','A','Q','q',023,'"','2','@','a','r',0221,024,'#','3','B','R',05,'4','P',0201,0241,0301,'5','b',0223,0321,'$','D',0222,0261,0341,'S',0202,'C','`','c','d','p',0200,0361,0377,0332,0,010,01,01,0,06,'?',02,0377,0,0352,'f',0320,0273,'A','v',0202,0355,05,0332,037,0371,07,0257,'#','[',0314,0252,0233,'@','v','t',0240,'E',0261,0306,0351,07,024,0341,024,01,0247,'q','(',0266,0363,'[',']',0341,'}',0351,0310,0275,0366,0227,0327,0232,0373,0314,0236,0253,0357,'2','z',0257,0274,0311,0352,0276,0363,047,0252,015,026,0247,'P','"','L',0335,047,0231,036,0226,'6',0310,027,0276,0263,0220,0357,04,0326,0364,0235,031,'?','R',0254,'V',0206,';','v',0337,0306,011,0232,'v',0217,012,0252,'Y','b','2',0370,0225,0324,0177,'B',0336,01,'{',0311,0336,0377,0,0317,0270,'U',0217,'-','>',05,013,0226,0202,0341,'Z',0321,0311,0242,0323,05,0356,'%',0250,01,'5',0307,'p','r',0253,034,034,'<','?',021,'/',0225,0341,0215,0361,'W','l',0377,0,0342,'$',0360,0330,0213,'C',0372,026,'p','j',0274,0367,027,0237,036,0356,035,024,0356,0240,0371,'J','k','-',0261,'e',0365,0265,'{',0211,0232,0343,0303,0360,0322,0371,'^',030,0337,024,0350,0354,'c',0246,0177,0325,0271,023,'<',0244,0217,0244,'l',0357,0227,0342,'y',0215,0334,'B',021,0333,033,0322,0263,0352,033,'P','t',022,0202,'x','~',022,0134,0343,'@',0236,0313,023,035,'h',0227,0213,'v',04,'L',0375,'!',037,'H',0330,0276,013,0275,027,0301,'w',0242,0370,'.',0364,'U','1','8',016,'Z',0274,0232,'O','%',0330,'w',0242,0354,';',0323,'_','~',047,0230,0335,0304,'!',025,0277,0256,0337,0254,'.',0222,0317,' ','x',0374,030,0276,'i',05,'w','7',0212,'$',0326,033,037,0312,0321,0264,0252,'4','P',',',0205,'W','`',0372,'.',0301,0364,'Y',0264,0215,06,'H','E',037,0303,0212,0241,0310,0351,0367,'Q','9',0374,0202,'o',0270,0270,035,0275,0312,0262,0314,0326,';',0202,'a',0222,'g',':',0233,'B',016,0350,0211,0247,025,0367,'F','+',0254,0263,0260,016,'K',0340,'G',0376,0225,0360,'#',0377,0,'J',0257,0262,0261,012,0300,031,'O',0245,016,0214,0272,'$','z',033,'O','S',0305,'T','0','I',0236,0344,'D',0266,'w',0212,'x','j',0304,0220,'H','G',0362,0356,'M',0212,'s',0320,0317,0343,0275,'e',0370,025,0134,'h',023,0254,0366,'O','y','7',0325,0270,'&',0231,0336,'_','S','R',0203,'F','@','!',',',0275,0235,0301,'u','Z',07,'-','9',0212,0242,0350,0205,0327,0360,0342,0250,'S','}',0232,'2',0363,'&',0340,0203,0247,'"',06,0240,'d','o','L',0357,0346,'T',0206,026,0263,0362,0327,'Q',0355,016,036,'(',0336,0200,'4',0223,'Z',0204,']','d',0232,0277,0312,0344,'z','h',015,0337,0250,'j','j',015,012,'l','V',0257,'{',017,035,0351,0262,'B',0360,0340,'F',0263,'2',0273,'A','v',0302,0355,0205,0333,013,0266,027,'h','k',0213,0345,'x','c','G',025,'%',0236,0312,'n','Y',0366,'W',0216,0211,016,0360,023,033,0304,0252,014,'U',0334,0341,'U',' ',0247,0313,0335,'(',0366,0207,017,024,'}',0337,'E',047,0324,0325,'~',037,0361,014,0360,0332,0213,'^',0322,0327,015,0307,'Q','~',07,'u','w',0264,0246,0271,0256,015,0227,'{','5','9',0234,0325,030,0263,'r',0370,0213,0342,'/',0210,0276,'!','_',021,03,'|',0241,']',0272,0303,',',0357,0272,021,015,'%',0266,'q',0261,0272,'f',0344,0242,0347,0216,'>','J','O',047,'w','=','$','@','?',0352,011,0317,0263,0373,0370,0277,'T','C',0205,010,0335,0215,0263,'B',0342,0327,04,0310,0244,'7','-',';',0301,0305,'R',0213,'#','U','{',0226,'K','%',0265,'m','[','V',0325,0265,'g',0254,'t',0323,':',0234,07,024,'^',0363,'H',0376,'V',0340,0233,0222,0213,0236,'8',0371,')','<',0235,0345,0307,0243,021,0315,0271,0301,036,0221,0245,0321,'n',0220,'c','l',0221,0272,0353,0206,0302,020,0263,0332,015,0333,'@',0375,'p','T',0243,033,012,0333,0232,0333,0250,'k',02,'h',0325,':','i',0235,'N',03,0212,'/','y',0244,0177,'+','p',0315,0311,'E',0317,034,'|',0224,0236,'N',0364,'Y','+',03,0332,'x',0247,0332,',','=',0221,0231,0215,026,0275,0245,0256,033,0216,'&',0311,033,0256,0270,'l','!',013,'=',0240,0335,0264,017,0327,'I',0215,0205,034,0363,'U','8',0350,0207,025,0322,'8','j',0235,'4',0316,0272,0320,0236,0373,0307,0241,07,0250,0334,'S','r','Q','s',0307,037,'%',047,0223,0276,'>','X',0305,0313,'N',0342,021,0216,'f',026,021,0211,0262,'F',0353,0256,033,010,'M',0215,0357,0377,0,022,0301,0230,';',0321,'k','N','h',0270,0234,0325,'u',027,0212,016,'p',0352,0240,06,0245,0322,'H','n',0265,0273,'J',0350,0341,'$','Y',0331,0372,0342,'l','q',0266,0363,0216,0300,021,0264,'Z','>','$',0204,013,0252,'.','z','-',0326,0230,0251,0322,'C',03,0344,'m','x',0206,0325,0177,0227,0376,0232,0377,0,'/',0375,'4',014,0221,0331,0245,'n',0361,'p',0217,0335,'{','L','-','1',0275,0246,0354,0221,037,0224,0250,0371,')','<',0235,0364,0261,0302,0222,'|',0256,'W',047,'n','G','c',0261,'6','p','K','J','.','y',0317,'S','x',0240,0,0311,06,0215,'Q',0260,0331,'_',0325,0377,0,0304,'#',023,'c',0215,0267,0234,'v',0,0205,0242,0320,'/','Z',017,0350,0233,0346,'Q','s',0321,0366,0214,0327,'C',0275,0311,'m',034,'*','3',0313,0367,'V',0227,0332,0254,0220,'Z','f','m',0242,0236,0361,0200,0220,'.',0217,0371,'R','0',0375,0233,'f',0214,'9',0244,'^','l','`',020,0276,0320,0373,'6',0327,'g','a',0224,'7',0244,0212,'p',')','#','w','m',0364,'V',0370,'w','>',020,0377,0,'C',0377,0,'*','>','J','O',047,'~','t','3','6',0274,017,04,'X',0361,'X',0376,'W','`',034,'4','P','l',0324,'W','r',014,'h','C',0216,0250,0206,0237,'~',0374,0232,0234,0367,032,0271,0306,0244,0341,0,012,0222,0231,'k',0235,0265,0235,0333,0216,0355,015,0363,0250,0271,0350,0265,'X',0334,'n',0211,0230,'[','^',012,'F','5',0362,'X',0247,0330,'i',0331,'x',0377,0,'b',0237,04,0337,'h','8',0306,0341,'B',032,0306,0266,0276,0201,'[',0276,0322,0236,027,0265,0362,0307,'H',0242,0247,'X',0201,0237,0352,0255,0322,0333,',',0262,'Y',0252,0306,0265,0275,' ',0245,'s','Q',0362,'R','y',';',0373,0241,0231,0265,0340,'x',047,0300,0360,'n',0216,0313,0270,0350,0,'h',0272,'5','!',0240,'f',0203,0334,'3',0325,'>','i',015,032,0320,0237,'3',0217,'W','c','F','/','m',0265,0307,0237,0310,0323,0245,0276,'u',027,'=','.',0262,0333,'m',020,0332,')',0223,0231,0321,0364,0240,'~',0212,0374,014,0202,027,0375,'L',0261,0220,0177,0331,':',0317,'b',0234,0313,'+','Y','|',0202,0302,'2',0374,0371,0350,0217,0222,0223,0311,0370,03,0232,0346,0373,0320,':',0256,'N',0263,0310,0302,0327,0202,0252,'v',0253,0241,'W',035,020,0342,0272,'G',0215,'_',0260,'D','z',0255,0355,0221,0210,'Z','e',036,0342,'3',0260,0357,'A',0255,024,03,'K','|',0352,'.','z','>',0321,0222,032,0211,04,'T',04,'m',033,0224,0254,0263,':','8',0333,025,'/',0276,'C',0262,0277,0376,'/',0342,'0',0377,0,0240,0251,'m','R','Z',0231,'8','|','&','+',0255,'m','7',0203,0373,'h',0217,0222,0223,0311,0370,013,'^',0320,'/',0267,'i',0321,']','E','J',04,0216,0252,0,'j',0244,0233,0347,0330,0320,0237,'+',0363,'s',0315,'N',030,0340,'`',0313,0346,'<',023,'!',0215,0240,06,0215,0330,033,0347,'Q','s',0321,'m','}',0245,0206,'[',';','a','{',0244,'`',0336,0332,'f',0255,0367,0242,0232,'k',',',0364,0273,'J','_',0310,0232,'W',0325,'}',0322,0327,0350,0337,0356,0237,'e',0263,0301,'<','O','d','f','J',0311,'J','R',0240,'q',0361,0321,037,'%',047,0223,0360,02,'+',0232,'.','+',0303,'Q','x',0240,0320,'2','@',015,'_',0263,0261,0336,0352,'/',0367,0302,032,05,'I','B','G',0217,0177,'&','d',0341,'o',0235,'E',0317,'E',0246,0312,0342,'Z',0331,0343,'t','d',0215,0325,024,'_','~',0264,'z',05,0367,0353,'G',0240,'O',0265,'C','i',0226,'g','>','3',035,036,07,020,0177,'m',021,0362,'R','y',';',0371,'%',027,023,0222,0270,0325,0343,0216,0273,0220,'c','B',025,035,'m',0134,0262,'W',0256,'E',032,0234,0367,032,0271,0306,0247,017,0264,0310,0337,'s',036,0316,'x',0233,0347,'Q','s','V',0273,'m',0236,0357,'M',025,0332,'_',025,031,0270,017,0335,'}',0251,0366,0234,0342,'/','h',0263,'t',0267,'.',0267,0253,0325,0214,'8','/',0207,'d',0376,0231,0376,0353,0341,0331,'?',0246,0177,0272,0226,0315,'k','l',02,'6',0300,'d',035,033,'H','5',0274,0321,0307,0307,'D','|',0224,0236,'N',0374,0134,'Q',0317,0252,0256,0205,'y','Q','f',0252,0325,0236,0,025,0367,014,0365,0202,0314,0327,'V','8',0377,0,0337,013,'"','g','i',0346,0212,'(',0,0314,014,0361,'7',0316,0242,0346,0237,'f',0264,0306,'&',0201,0375,0246,035,0373,0324,0266,'8',',',0314,0216,0315,'-','o',0307,0271,0325,024,'+','?',0263,'l',0303,0233,'W',0360,0373,047,0242,'2','X',0254,0260,0303,')','m',0322,0350,0366,0323,'D','|',0224,0236,'N',0373,'U',0321,0260,0243,0305,'W','E','U','7',',',0225,'U',025,'4',03,0300,0250,'d','f','`',0267,'v',0256,'y',0217,0312,0325,'$',0256,'5','.','5',0302,0353,'d',0203,0251,037,'g',033,'|',0352,'.','z','-',0266,0306,'R',0374,'Q',0365,'k',0307,'`','N',' ','O','o',0264,034,0315,'*',0352,0177,'e',0374,'2','o',0321,'O','5',0262,0310,0373,'<','F',0314,'Z',034,0356,'7',0233,0242,'>','J','O',047,'}','-',07,'4',0134,0345,0341,0240,' ',0257,05,'R',0256,0350,0274,'t',023,0271,'I','e','q',0251,'f',0315,0134,'v','V',0222,'/',0355,0302,0326,'7','k',0215,024,'1','4','S',',',0361,0267,0316,0242,0347,0242,0333,04,0357,021,'B',0370,0235,'z','C',0261,0276,'+',0355,'H','-',0226,0250,'b','.',0273,'v','B',0376,0243,0256,0223,'Z',037,0315,0177,025,0262,0177,'X','#',035,0222,0333,05,0242,'@','/',026,0306,0360,'M','4','G',0311,'I',0344,0357,0204,0242,0342,0256,0215,031,'h',0272,0375,0213,'n',0232,0235,04,03,0226,0210,']','Z','5',0346,0351,'@',0352,0245,' ',0325,0254,0352,0214,'=','#',0333,'V','E',0236,0241,0276,'u',027,'=',026,0353,'4','T',0351,'&',0201,0361,0266,0274,'K','h',0266,'Y',0377,0,0250,0266,'Y',0377,0,0250,0246,0264,0332,0372,'.',0215,0320,030,0305,0307,0327,';',0315,'?',0266,0210,0371,')','<',0235,0354,0222,0213,'A',0352,0252,015,024,'U','Y','+',0233,0325,'A',0311,'f','t',0334,'n',0335,'!',0303,'h',0315,'A','(','5','4',0241,0324,0317,')','4',0243,'w',047,0274,0346,0134,'k',0236,021,'1','m','$',0227,':',0352,033,0347,'Q','s',0321,'h',0366,'s','v','~',0215,0335,031,0340,0352,'d',0247,0263,0333,0355,'F','h',0333,'g','s',0256,026,'5',0264,'u',0346,0360,036,047,04,'|',0224,0236,'N',0367,0321,0264,0346,0211,'*',0272,02,0240,0321,'|',0354,'T','T','^','(',0327,'j','.','8','&',0263,022,'j',0323,'Q',0251,021,0177,0324,'8','a',0204,012,0336,'r',0216,'!',0261,0242,0232,0206,0371,0324,0134,0364,'[',0255,'1',0323,0244,0206,07,0310,0333,0333,'*',033,'U','7',0332,0260,'E',04,'v',0211,'A',016,'`','i',0271,0236,0334,0252,0276,035,0223,0372,'g',0373,0251,'l',0326,0266,0300,'#','l',06,'A',0321,0264,0203,'[',0315,034,'|','t','G',0311,'I',0344,0357,'D',0357,'N','{',0212,0240,0331,0243,'%','y','x',0254,0364,0336,'(','e',0325,'P',0310,0337,0206,0341,'M',0230,'c',033,0237,0226,0246,'(',')',0330,025,0303,0322,0226,0325,0261,0215,0272,0226,0371,0324,0134,0364,'>',')','Z',037,033,0332,'Z',0346,0235,0341,0177,014,0263,0377,0,0245,0177,014,0263,0377,0,0245,031,'l',0226,'8',0254,0362,026,0335,'.','`',0335,0242,'>','J','O',047,'y','$',0242,01,0352,0205,'t','h',0242,0252,0240,0354,0256,0251,0315,']','+','2',0257,024,030,0320,0207,024,0367,06,0336,'t','y',0341,0202,'O',0245,0301,'F',0375,0227,0233,']','E',0241,0301,0367,0332,015,06,027,0316,'i','Y',016,0245,0276,'u',027,'=',026,0233,'[',0205,0341,014,'e',0364,0342,0246,0264,0272,0325,'i',0272,0334,0335,0321,'8',0206,'0','~','[',027,0264,'6','O',0264,035,'g',0245,'z','P','_','w',0325,'O','$',0362,'Z','e',0263,'{',';',0200,'t',0205,0305,0227,0257,'7',0365,0321,037,'%',047,0223,0274,0364,'m','9',0242,'w',0252,0350,012,0232,'2',0322,032,025,0367,014,0364,'K',036,'F',0363,'w',0251,'c',0372,0134,'F','X','l',0356,0275,'|',0322,0204,0343,0221,0373,'n',0266,0252,'i',')','K',0316,'8','l',0355,0273,'p',0322,0244,'j','[',0347,'Q','s',0321,0366,0225,0315,0267,07,0245,'E','W',0333,0371,'u',0357,'<',0237,0311,0215,'+',0331,0355,'V',0230,0242,'0','_',017,'d',0216,02,0255,'&',0277,0272,0266,0331,'*','z',07,'E',0322,0323,'p','p',' ','~',0377,0,0246,0210,0371,')','<',0235,0340,0224,0347,0225,0341,0243,' ',0257,'Q','Q',0333,'V','Y','7','O',0212,0351,034,'2','T',032,'m',015,014,0270,0322,'j','0',0230,0351,'K',0216,0307,'j','{','6',0335,'U',';','p','B',0301,0265,0316,012,'&',035,0241,0240,'j','[',0347,'Q','s',0321,'j',0262,027,0134,0351,0243,'s','/','p',0250,'V',0270,0244,0266,'6',0327,'g',0264,014,0343,0350,0356,0320,0372,0247,0213,014,'"',0327,'f',047,0250,0340,0360,010,034,015,'T',0323,'Z',0234,015,0256,'z',02,0326,0354,'`',0321,037,'%',047,0223,0273,0325,026,03,0220,'W','F',0212,'i',0253,'U',0327,05,'@',0257,024,'8',' ',0321,0202,'9','k',0223,0333,0206,0323,025,'z',0233,'q',0315,'p',0322,0271,'a',0262,0261,0333,'/','j',0233,0347,'Q','s',0320,04,0262,'G','l','o',0376,0263,'3',0365,010,013,'m',0222,'[','9',0372,0243,'7',0302,036,0317,'o',0210,0270,0374,0217,'7',']',0350,'t',0307,0311,'I',0344,0356,0345,0240,0346,'Q','$',0346,0253,0242,0362,014,032,'*',0250,'6',0252,0224,030,0324,'8',0341,0263,0315,0363,'V',0230,']',030,'=','W','7','<','e',0204,0365,0234,'r',0302,0313,0337,' ',0250,0325,'7',0316,0242,0347,0243,0336,'}',0237,023,016,0333,0320,0365,017,0350,0235,'#','~',0325,'6',01,0377,0,0271,'-','-',0375,0221,0216,033,'l','6',0346,0375,'p',0203,0373,0205,'<',016,0236,'G','@',0333,'+',0210,0210,0270,0335,06,0363,'w','h',0217,0222,0223,0311,0253,0314,0256,0322,0332,0273,'J',0255,'5',0306,0134,'S',0234,'N','Z','h',0252,'6','"','N',0214,0264,0,027,'H',0341,0236,'.',0220,0355,'a',0313,013,'o',032,'^',024,030,0354,0376,'l','%',0300,'u','C','s',':',0246,0371,0324,0134,0364,'8',':',0334,0350,'X','~','X',':',0237,0362,0234,0370,0355,020,'^',0336,0351,0347,0353,'z','m','@',0333,'m',0262,'L','~',0230,'E',0321,0373,0242,'l','V','V',0304,0362,'.',0231,'+','W',021,0314,0350,0217,0222,0223,0311,0251,0253,0212,0244,'k',0254,0345,0233,0226,0325,0221,'A',0244,0344,'U','q','t','m','*',0350,0321,'E','U','u','W','E',02,0256,0364,034,'F','H',01,0212,'[',0242,0264,0317,015,0227,0236,';','?',0233,015,0253,0226,0251,0276,'u',027,'=',04,0331,'d',0232,0306,0356,0,0337,'o',0353,0375,0321,'u',0226,'X','m',0215,034,015,0307,'~',0277,0335,010,'e',0236,0323,01,0333,'r','~',0273,'O','*',0376,0312,'[',035,0256,030,0201,'d','F','Q','$','u',033,0300,0331,0371,0350,0217,0222,0223,0311,0250,0240,0332,0252,0347,'e',0243,'%',0231,0321,0222,07,'z','n',022,'w',0247,'8',0235,025,'Y',0254,0227,0216,0233,0305,06,0215,0210,01,0216,0327,0345,0303,'e',0347,0216,0317,0346,0303,'j',0345,0252,'o',0235,'E',0317,'G',0370,'k',',',026,'a',0374,0325,'y',0375,0220,0217,0333,0255,022,'8',0354,0216,016,0255,0177,'&',0253,0346,0312,0350,'C',0263,0351,'-','.',0273,0377,0,')',0366,0271,0355,'L',0226,'G',0305,0321,0364,'q',0267,'!',0230,';',0177,'-',021,0362,'R','y','1',0320,'v',0221,'s',0212,0243,'V','x','h',0256,'`',0252,'"',0271,05,'@',0257,025,'t','m','W',0264,'P',0355,0321,0340,0203,'Z',0203,0210,0317,'Q','k',0362,0341,0262,0363,0307,'g',0363,'a',0226,032,'v',0333,0267,'T',0337,':',0213,0236,0200,'d',0216,'K','c',0306,0371,0235,0227,0240,'W',',',0326,'x',0254,0354,0341,033,03,'p','G',0311,'I',0344,0304,'J','w',05,'t','c',05,'0',0240,'t',0226,0203,0231,'G','<',0326,'j',0201,'U',0333,'4',0336,010,'5',016,'+',0244,'p',0324,0316,'i','[',0331,'a',0262,0363,0306,0311,01,0311,0216,0303,0377,0,'n',0251,0276,'u',027,'<','q',0362,'R','y','1','9','=',035,'E',025,0335,0343,'A','q','N','5',0311,'U','d',0274,'t','e',0261,'T',0355,'W',02,0274,'P',0313,'$',032,'5','/',0347,0206,032,036,0306,'x',0344,0347,0206,0315,0235,'3',0325,'7',0316,0242,0347,0216,'>','J','O','&','7','#',0251,'o',02,0257,'"',0306,0225,'M','9','*','9','e',0242,0361,'M','c','P',0343,0252,0200,'W',0346,0303,0377,0,'n',';','U',0341,'^',0256,033,';',0311,0240,017,031,0246,'8','f',010,0324,0267,0316,0242,0347,0216,'>','J','O','&','0',0345,']','H',0342,0256,'#',0236,'x',0302,0,'m',']','#',0206,0256,010,0203,0263,'h',0314,'a',0264,0270,0214,0300,0333,0216,'v',0335,0275,'V',0234,0224,0215,'"',0355,035,0263,0,'<',012,0263,'I','J','U',0272,0226,0371,0324,0134,0361,0307,0311,'I',0344,0306,'N',0253,0303,'E','q',0324,0240,0342,':',0250,01,0253,0224,'R',0227,'2',0303,'4',0205,0224,0274,0354,0235,0214,0253,'S',035,0231,0275,0205,0255,0277,'y',0314,'4',0324,0267,0316,0242,047,0216,'6',0216,01,'I',0344,0306,0340,0236,0324,'G','p',0251,'M','`',010,015,'[',0334,'r',0,'+','D',0227,0257,0325,0373,'p',0301,'x',0326,0366,'z',0202,0360,0313,0241,0343,'o',034,'3','Y',016,0307,'f','5','2',0264,'m',0332,'4',0,'O',0274,033,'F',022,0367,0224,0347,0235,0352,'I',0210,0355,'d','5',04,0356,'=',0302,0210,'4','m','W',0334,'3',0326,'O','&',0362,'(',025,'N',0334,014,'`',025,0251,0245,024,021,0206,0335,0243,'v','j','!',0264,0,'I','i',0241,0303,'g',0222,0271,'V',0207,'4',034,'6',035,'I',0236,'!','X',0316,0320,'7','*',0264,0320,0254,0350,0376,'k',0341,0265,'|','6',0254,0232,0326,0252,0275,0327,0225,06,'Q',0215,0256,'M','c',05,032,'5',027,0270,'*',0353,0352,'U',0367,014,0225,06,0262,033,'#','N',0334,0316,'x','l',0354,0241,' ',032,0232,'*','j',047,0217,'x',025,012,0207,'n',0,'F',0325,03,0367,0201,'C',0251,0315,027,'3',0335,';',0303,'b',0312,'V',0321,'|','V','/',0212,0305,0361,'X',0201,0232,'B',0377,0,0,0203,030,0320,0326,0216,032,0227,04,0366,0243,0255,0251,'A',0240,'d',0203,'F',0260,0225,';',0253,0325,'i',0272,'0',0315,'k',';',033,0220,0324,0271,0207,'a',024,'V',0210,'x',':',0243,014,0266,'G',036,0251,0314,015,'I','|',0216,015,'o',0212,0244,021,0345,0365,'9','v',0307,0242,0370,0203,0321,'|','A',0350,0276,' ',0364,'@','M',030,'p',0342,0325,'~',047,'W',0303,'T','N',0343,0255,0242,015,033,'P','q',031,0353,'g',0222,0264,'q',024,010,0223,0231,'8','c','$','u',0344,0353,035,'T','V',0260,'2','v','G',014,'3',0260,0322,0351,0315,'G','(',0371,0205,'q',0227,';',' ',021,0317,0335,016,0310,'W','X','*',0272,0362,'z','/',0212,'}',027,0305,'>',0213,0253,'.','~','!','u',0306,0134,'B',017,'a',0346,'8',0246,0312,0315,0207,'S','{',0202,0256,0262,0245,'t',0216,031,'*','k','Y','c','i',0352,'3','3',0206,010,'F','w',0234,0231,030,0330,0321,'M','T',0315,0273,'W','4','T','"',016,0334,'&',0307,'#',0272,0361,0354,0345,0216,0350,'9',0274,0321,'5',0243,'i','A',0215,0374,0360,0226,0270,'T',024,0346,')','a',047,0304,'j',0134,0324,0366,0242,'5','U','M','h',031,' ',0321,0255,0226,'w',0232,']',012,'I',0336,'s','y',0256,031,'m','o','m','C','2','n',0254,0264,0354,'*','V','7',0260,0376,0260,0303,024,0340,0345,'^',0267,'$',0311,'X','j',0327,012,0342,0203,0232,'e','q',0260,0361,012,'O','&',0252,0370,'U',0324,0321,06,0215,0250,022,'3',0327,'6',0303,033,0262,031,0277,010,'h',0332,'r','Q','0','v',0210,0251,':',0317,'h','`',0367,0261,'g',0213,0330,'%','=','f','v','N','(','9',0246,'~','x',0343,0344,0244,0362,'j',0210,'N','i',0332,0251,0250,0274,'W','H',0341,0256,0222,0320,0355,0303,' ',0244,0235,0375,0247,0232,0341,017,'p',0367,'Q','f','U','5',0216,'c',0263,016,024,'R',0305,'N',0241,'7',0233,0206,';','D','}',0246,0225,034,0361,0232,0324,'g',0206,047,0356,016,'Q',0277,0305,'W',021,0241,0250,'n','J','W',0356,02,0232,0276,0221,0243,'%','x','b',0310,'*',0271,01,'N',0252,015,032,0332,0257,'e',0210,0373,0230,0377,0,0337,010,03,'2','T','`',0217,'x',0374,0335,0256,0366,0210,0307,0275,0213,'<','B',011,017,0270,0223,0216,0344,034,'3',07,03,0342,0343,0261,'9',0216,024,'p','B','9','s','n',0343,0301,'u','d','i',0374,0327,'h','z',0256,0320,0365,'U','/','h',0374,0321,'d',031,0237,0251,'q','%',013,0335,0267,'f','u','e',0245,032,'6',0255,']',0205,0331,'[',026,0305,0331,'Y','F',0205,0374,0202,0243,'F',0270,0301,023,0275,0374,0231,'r','D',0234,0311,0302,0331,034,'=',0324,'Y',0252,'k',0213,0134,'*',012,0222,0215,0367,'2',032,0264,0342,0366,'K','K',0375,0363,'{','>','8','o','7',0253,'(',0337,0305,'R','H',0310,0303,'v','6',027,037,04,'%',0237,'9','7','7',0206,0267,'0',0273,'+',0262,0273,'+',0262,0273,'+','!',0257,'|',0322,':',0231,'d',0237,'h',0230,0324,0235,0230,'[',033,05,0347,';',' ',024,'Q',0323,0256,'E',']',0334,037,035,'=',0340,0315,0245,'>',047,0212,'9',0246,0230,'Y','4','F',0353,0332,'j',025,'N','S','3',047,014,'9',0212,0257,0200,0317,'E',0360,031,0350,0276,03,'=',027,0300,'g',0242,0352,0264,'7',0227,0340,'O',0225,0346,0215,'h',0252,0246,0310,030,'z',0243,027,0267,0316,0334,0276,'N',0345,0355,0360,'7','1',0333,03,023,'f',0205,0324,0246,0321,0305,'G','3',010,0274,'F','c',0207,0341,'E',0316,'4',01,'>',0313,03,0251,'g','n','D',0215,0370,0233,035,'=',0323,'s','y','L',0211,0202,0215,'h',0247,'r','t','o',027,0232,0355,0310,0357,0205,0371,0264,0342,017,'a',0254,0177,'3','S','f',0205,0325,0342,'8','~',020,0134,0343,'@',023,0254,'v','7','R','?',0231,0343,'~','&','D',0301,'W','8',0321,06,0220,014,0316,0315,0316,0356,0217,0205,0340,'^','#','#',0301,':',011,0233,'C',0270,0361,0304,036,0303,'X',0376,'f',0253,0320,0273,0255,0275,0277,0203,':','I',035,'u',0243,'z','6','k',023,0210,0217,0346,'v',' ',06,'d',0257,'l',0265,'4','t',0216,0354,0264,0356,0356,0325,031,'N',0316,0311,'O',0206,'Q','u',0355,'4','8',0233,'4',016,0241,033,'G',025,'C','H',0347,033,'[',0370,'#',0245,0231,0301,0255,'j','0',0307,0356,0354,0343,0206,0374,'m',0266,0332,'G','P','f',0326,0252,'w','s','i',0263,0213,0266,0201,0372,0247,'G','#','n',0270,'m',07,020,'|','O',',','p',0336,023,'l',0366,0342,'#','}','2',0177,024,034,0323,'Q',0370,013,0257,'<',':','m',0314,'E',0322,'8',0266,'=',0314,07,',','b',0321,'8',0273,'g',037,0252,0270,0321,'F',015,0203,0274,0233,'E',0234,']',0264,017,0325,':','9',033,'u',0303,'h','8',0303,'$','&','h','8',035,0250,'>',031,05,'w',0267,0207,'~','/',0221,0301,0255,033,0312,'t',026,014,0316,0316,0221,027,0312,0362,0367,035,0347,030,0264,'Z',05,0333,'0',0375,'S','c',0215,0267,'Z','7','w',0276,0236,0314,03,'-',037,0356,0235,014,0315,0270,0361,0216,0374,022,030,0335,0340,0204,'_','h','m',0377,0,0250,020,'|','2',07,0217,016,0365,'W',032,017,024,0346,'F',0356,0232,'n',015,'G',0244,0224,0210,0376,0206,0352,'#',0264,'Z',0205,0313,'>',0332,'q','M',0216,'6',0335,'h',0335,0337,'j','z',0223,015,0216,011,0320,0314,0332,'S','a',0343,0250,0275,'g',0224,0263,0303,'r',021,0333,0233,'t',0375,'a','V',011,0232,0376,0355,'y',0356,015,036,'(',0210,0235,0323,0311,0301,0250,0202,0376,0212,'/',0245,0272,0200,032,'*','N',0345,035,0256,0333,0267,'h',0215,06,0264,'P',016,0376,0350,0346,'`',0317,0346,'N','s',032,'e',0263,0375,'Z',0233,0360,'J',0350,0317,0202,'k','m','#',0246,'g',035,0350,03,047,'D',0376,016,'U',0215,0341,0343,0300,0367,014,0315,021,'2',0316,0332,0360,010,0266,0305,036,0177,'S',0221,0351,0247,'7','~',0221,0251,021,0331,0343,'/','(','K','7',0275,0234,0215,0373,0277,02,'-','{','C',0233,0300,0247,'O','a',0352,'?','i','g',024,'b',0231,0205,0217,033,0216,0252,0260,0316,0366,0376,'j',0354,0300,'N',023,'D',0321,0272,'>','%','^',026,0200,0336,'i',0267,'g','a',0256,0314,0326,0321,0213,'2',0272,0362,'5',0274,0312,'-','}',0245,0225,013,0335,0336,0224,0327,'`','N',026,'h','.',0360,'.','F',0375,0240,0206,0223,'Z','5','U',0304,0270,0370,0352,0204,0223,0216,0206,017,035,0350,'G',04,'`','S',0177,0340,0245,0262,0263,0255,0365,04,0347,0260,'t',0320,0215,0343,'Z',013,'d','s','i',0262,0205,07,013,'L',0225,036,'+',0357,'N','W','o',0211,'<','J',0371,027,0310,0276,0362,'P',0277,'j','~',0134,020,0351,'&','{',0251,0342,0252,'s',':',0313,0266,'x',0313,0206,0367,'n','M',0232,0325,0357,'f',0375,025,032,'(','?',07,0243,0205,'B','/','c','z',031,'x',0265,022,'Y',0322,0305,0365,'7',0277,']',0263,0304,'_',0343,0271,011,'-',0316,0274,'~',0200,0256,'A',030,'`',0360,0374,'.',0216,025,036,'(',0271,0215,0350,'e',0342,0325,'y',0215,0351,0343,0342,0325,'u',0355,',','>','=',0344,'6','(',035,'C',0363,024,037,'m',0223,0244,0376,'@',0203,'!',0214,'0','x','~',' ','[','4','-',0346,021,'u',0222,'k',0277,0312,0345,0326,0200,0275,0274,'Z',0256,0275,0245,0207,0307,0271,0201,025,0235,0346,0276,010,':',0323,' ',0211,0274,02,'k',0256,'t',0262,015,0356,'T','c','C','G',0207,0342,0231,0257,'{','g','c',0277,'%',0356,0213,0242,0344,0253,014,0315,'y',0256,0302,0213,'z',013,0364,0336,021,'/',0263,0310,0,0360,'U','-',' ','r',0324,'d','+',0311,'Q',0220,0275,0307,0300,'+',0314,0262,0272,0236,')',0275,'!','l','m','(',033,'D',0305,0346,0273,02,027,'l',0340,0220,'k','R',0250,0306,0206,0217,017,0307,'(',0346,02,'9','"',0307,'Y',0331,'C',0340,0276,0350,0304,'_',0320,0335,0360,013,0341,0237,'U',0360,0317,0252,0370,'g',0325,'|','3',0352,0203,'}',0225,0271,'*',0307,'f','`','<',0225,'Y',023,032,'|',07,0377,0,035,0177,0377,0304,0,',',020,01,0,02,01,02,05,03,05,01,01,01,01,01,01,0,0,01,0,021,'!','1','A',020,' ','0','Q','a','q',0241,0360,'@',0201,0221,0261,0361,'P',0301,0321,'`',0200,0341,0377,0332,0,010,01,01,0,01,'?','!',0377,0,0362,'b',0352,'I',0365,0237,0330,0237,0330,0237,0330,0237,0330,0202,'?',0374,0,03,0177,0340,0237,'y',0350,'a','i',0272,'J','Q',0372,0255,' ',035,0273,',',0234,02,0330,'?','j','r',0336,0367,0255,016,05,023,'2','A','T','"','E','W',01,0210,0347,0236,0372,'j',';',0230,0355,0245,04,047,'`','i',032,'*','>',0237,0353,' ','Z',0321,0346,'.',034,0276,0344,'H',0300,'{','D',0305,0313,'Z',0354,0304,06,0253,'9',0372,011,0321,'f',0314,'Y',0224,'Q',0273,0205,0312,'~',023,020,023,0326,0326,'X','-',0273,'E','_',0372,' ','F','n',0240,014,0302,0324,0233,0345,0250,0341,'w','6',0357,0351,0205,'B','4',0233,0316,0353,0240,0331,035,'@',0320,0300,0272,0250,0274,0263,0376,'h',021,0233,0251,0217,'w',035,0210,0375,0356,0365,'}','`',0310,0356,0355,'N',0305,'^',0322,'5',031,0275,0317,0371,'"',04,0362,0254,' ',0213,025,'Z','B',0355,0273,'U',0310,0326,0264,0264,0363,'W',0246,036,0313,0356,'.',0177,'K','?',0245,0353,0231,035,0335,0250,0345,0235,'3','c',0326,030,'M',0354,0351,0376,'0',0302,'V',0354,0314,'-','w',0262,0253,0325,0361,0,024,0266,'&',0265,0372,016,'"',021,0226,07,0222,' ','R','Y',04,'9',0345,':','C',0220,0243,010,0361,'^',0267,'=','h',032,'3',0134,0230,0333,'Z',';','D',0232,0351,0332,'f','o',0225,0322,0304,0376,'d',0315,'=',0272,'o','?',0204,0213,0225,0355,'"',0245,'s',0235,'!','_',0212,020,0254,'{','Z','u',0227,'Z','6',07,'3','h',0355,'O','3','~',0333,'K',021,024,0211,'I',0267,'J',0277,'K','j','r',0373,'B',0245,'@','e',0207,0342,05,0312,0316,0347,0370,'O',010,'y','V','V',0250,'m',0202,0243,0362,032,04,'4','h','P',020,0214,0345,0367,0345,'0',037,016,' ',0320,017,'$','4',0207,0263,'H','t',012,'L','$','c',0327,'!',0321,0357,05,'D',032,'o',024,'P',0367,0321,05,022,012,0304,05,'i',0325,'J',0331,0250,'.','v','c',0243,'n',03,0241,'1',026,0225,033,'T',0331,021,'H',0224,0233,'t',015,0250,'2','#','I',026,047,'L',0330,0227,0227,'E',016,'N',0235,0324,0323,0222,0177,'Z',0177,'R',0177,'R',0177,'R',0177,'R','+','C','>',0262,0354,0307,'W','~',0240,')',0276,0334,035,'a','T',0253,'k',0273,034,'f',0306,'x',',','!',0206,0,0301,0314,'4','J',0374,0244,'b',0300,0353,0264,0363,0364,0210,0232,0366,027,')',0262,0231,'0','f','4','j','2',0220,0326,014,0203,'O','C',']',0227,0204,0315,'7',0241,0234,0337,'A',02,0330,0302,0227,0262,'&',0215,'y',0227,0266,0220,'z',0257,0314,0334,0237,0230,0263,'w',0346,'Y',0377,0,0322,'h','K',0363,016,0251,'^','b','X','X',0352,034,'a',0320,0335,0215,0205,0373,'W',0353,0307,0333,'z',027,0356,0377,0,0271,0360,'<',0375,'2','Y',0230,010,0313,'C',0244,0232,'3',0263,'F',0202,'>','L','e','m',0316,0236,'^',0360,0353,'0',027,0273,07,0231,'Z',0320,'K',0211,0373,0306,'W','&',031,'_',017,'o',0330,0276,0371,'~',0351,0345,'C',0364,0241,0346,0134,'.',0217,'L',0330,'P',0362,0250,0207,0301,0360,0207,047,0266,0364,'/',0335,0377,0,'s',0340,'y',0372,0204,05,'%',0220,0271,'E',0263,0314,027,0265,'`','c',0235,010,'>',0340,07,0343,0241,'y','.','R',0202,'>',02,0335,0201,'+','h','I',0240,0212,'u',0346,'6','V','"',0215,0203,'C',0232,0351,033,012,036,'U',020,0370,'>',020,0345,0366,0336,0205,0373,0277,0356,'|',017,'?','U',0260,0320,04,0324,'X','n',037,0264,0303,0221,020,0247,0231,010,'>',0340,07,0343,0241,'x','@','[',013,'0','o','R',0256,0243,0211,0223,0234,0220,'&',0220,0312,'U','3',0266,0201,'E','t','O',0311,0357,';',0315,04,021,';','s','{','o','B',0375,0337,0367,'>',07,0237,0252,'c','|','2',0266,0361,0330,'1',0337,0325,'Z','a',0346,'B',017,0270,')',0365,'A',0221,0220,0246,'j','i','D','i',0347,'j',0211,'T',034,0314,'m',020,'Z',0240,0350,0203,'Q','Z','D',0322,0203,0256,0276,'d',' ',0372,0201,0276,02,03,'c',0215,0350,0370,0267,'e',0241,0177,'r','y','>','~',0263,0311,0363,0365,0226,0330,0272,0241,'<','&',020,0375,0204,'m',0276,0276,0347,'f','{',0277,0356,'|',017,'?','Z','n',0314,0302,'d','g',0203,033,0321,0345,013,'`',02,'9',0262,'f',0326,034,'g',034,0341,'r',0250,'q','0',0334,0353,011,0232,0256,0212,0321,'s','(',0264,0257,0320,0346,'B',017,0250,01,0370,0354,031,0366,036,'6',011,'S',025,0341,0307,'f',0344,'1',0242,'_',022,']','v',0270,'q',020,'1',0227,'Q','4','|',0317,'?',0332,0330,'<',0201,0265,'=',0331,0224,0366,'/','Z',0377,0,0356,'{',0277,0356,'|',017,'?',0134,'l',',','y','T','C',0350,0370,'S',0221,':',0261,0205,0315,'(',0214,0233,0240,06,0216,05,0326,'.',0317,0245,0212,0333,'@',0351,031,025,0300,0357,0312,0201,0225,'@','o','(',05,0354,016,037,'l',0343,'~',0271,'c','m',0237,0263,'Q',01,'.','a','{',04,0262,0231,'r','+','+',035,0254,0231,'a','F','g',0236,0265,'y','U',036,047,0220,'U',0265,'-','~',011,0356,0377,0,0271,0360,'<',0364,'/',0351,0315,0205,0217,'*',0227,030,031,015,034,03,',','o',014,0342,0232,0226,'e',0213,'o','8',0202,0261,'+','f',0223,'9',017,'K',',',0356,'Y',0217,'E',0364,034,0241,'m',020,0303,'2',0262,0373,0300,0,024,034,'=',0263,0222,0334,0226,0233,'5','n','4',0213,0237,0336,0364,0221,',',0256,030,0257,'B',0354,033,0216,036,0357,0373,0237,03,0317,0370,03,0357,'(',0265,0271,'W','!','d',0203,0312,011,027,'1',025,'s',0213,04,',',014,0245,0263,0322,'C',' ',0323,0245,0201,0375,'a',0257,0216,'c',0251,0262,'5',0300,0240,'j',03,0217,0266,'q',0265,035,'"','4',012,'$','|',012,0301,'r',0351,0252,0311,'T',03,'n','_',0210,'U',0233,'>','[',0302,0217,'A','H','[',0331,0341,0367,0177,0334,0370,036,'~',0213,'c',0254,'h',0272,'B','Z',0300,06,0261,'H','k',035,0247,0235,'@','!',0211,'f','b',',',0207,035,07,'J',0332,027,',','n',0307,0236,0321,'9','P',0245,0334,'&',0210,'w',0220,'4',0325,0344,0366,0316,'7',0253,'$',' ','&',0203,0315,'M','p','I',0302,0322,'W','Z',';',0247,'^',026,0323,0300,'S','4','P',0302,0316,'<','=',0337,0367,'>',07,0237,0242,0256,0261,047,',',0316,0374,0261,07,'8','.','Y',06,'y',0255,' ',0205,'O','7',0375,'r','-',027,'5',0275,0253,'N',036,'S',0342,'U',01,0274,034,0365,'z',016,'_','l',0343,'z',0335,0332,0260,0311,'?','3',0347,0377,0,0362,'|',0377,0,0376,'F','8','T',0300,033,030,0341,0367,0177,0334,0370,036,'~',0275,022,0317,017,'R',0304,'b','d',0232,0243,0254,'Y',0314,0202,0210,0275,0324,'l',0310,0347,0331,0310,0215,0245,03,0273,'-',014,011,0347,0224,'M',0334,0251,'0',0300,0,014,07,'/',0266,'p',0273,'s',0371,'0','{','=',024,0323,0340,0204,'5',0,0276,0353,0306,0335,0266,'z',0255,'X','n',026,')','p',0367,0177,0334,0370,036,'~',0271,0351,0240,0203,06,011,'`',0271,0235,0304,0225,06,'f','S',0205,0304,0264,0351,'B',0270,0220,'+',020,036,'e',0204,'s',0335,0340,'W',';',0311,'R',0363,'h','r',0216,0353,'(',0224,0312,013,0353,0346,0366,0316,027,'_',0260,0330,0321,07,0270,'L','.',0337,0333,'A','e',0367,0,0236,0311,'a','?',0230,0211,0273,0,0226,0270,0327,0245,0207,017,'w',0375,0317,0201,0347,0353,'M',026,0221,027,023,'x','9',031,'D',')',0225,04,'<',0314,0315,'/',031,0332,0343,'Q',0206,'Z',0366,'A','B',032,'S','0',0224,0344,030,0321,01,'=','3',0241,'V','U','w',0216,0231,'t',0274,0271,025,0305,'m',0336,0177,'l',0343,'b',022,'c',']',0227,0324,0373,0244,0313,027,0300,0242,0375,0236,0320,'s',0340,0367,0224,0303,0226,'i','o','Z',0366,037,0307,017,'w',0375,0317,0201,0347,0353,'r',0266,0312,07,'f','1',0317,02,0265,02,0267,'h',0227,0226,'(',0264,'%',0300,0325,0212,0367,026,'S',06,'+','V',0232,0211,'G',0302,'1',0364,0335,0373,'p',0276,0213,'o',035,0223,'D',0345,'9',0224,0202,0213,0226,'^','U',0266,0267,0317,0355,0234,'l',0343,0240,0232,032,0273,0372,'U',0375,0241,012,0322,'v',03,0261,'n',0251,0336,'|',0227,0376,0312,0332,'$',0352,0301,'t','m','i',0371,0341,0356,0377,0,0271,0360,'<',0312,0225,0365,'I','7','5',020,0374,'K',05,0307,012,01,0206,'v',0361,'*','=','R',0314,06,'2','l','%',0333,020,0213,021,'+',0240,023,035,'O',013,'}',0244,'M',0341,0211,0242,0134,'Z',0350,'+',027,'B','R','B',0354,'9','L','P',0277,0224,012,'+',0237,0333,'8',0336,0257,0213,'t','Z',027,0367,'g',0311,0377,0,0344,0371,'?',0374,0201,0310,0317,0226,0335,0207,'e',0303,0335,0377,0,'s',0340,'y',0372,0265,'*',0202,'b','D',0204,0215,0230,0250,0262,0264,'A',0353,'X',0200,0331,'*',0206,0251,'{',0361,0213,'F',020,0306,'!',0240,0304,047,'l',0242,0333,0303,'U',0304,020,04,'Q',0243,0274,',',0364,033,0325,0274,0352,0216,'R',0215,0265,'r',0352,':',037,016,0207,0266,'q',0262,0213,'|',015,0344,'Z',0275,'j',034,0351,'4',0300,'6',035,'9',017,'w',0375,0317,0201,0347,0352,0226,0245,0326,'S','X','j',0263,034,047,0205,'s',0367,0215,0341,'%',0237,'x',0347,'E',0244,0356,0214,'&','!',036,' ',0201,0205,'#','A','|',0200,0227,0240,':',07,'F',0204,'-',0246,0307,'N','U',0374,0210,'h',0274,'C',0224,03,0201,']',017,'l',0343,'`',0333,026,027,'d','/',0305,0222,0352,'Z',',',0301,']',0305,'/',']','x','[','g',0252,0325,0206,0341,'b',0227,017,'s',0375,0317,0201,0347,0351,0334,'A',0276,015,'g','G',010,0202,';','a',0302,0232,'#',047,'d','>',',','Q',0262,'"',012,0242,'x','T',0243,034,0315,0216,'!','B',0345,'+',013,0345,0301,026,';',0353,0242,0367,0,0312,0275,'y','m',0262,0357,'-',036,0217,0266,'q',0275,'9',0256,'{',024,0217,0333,0215,0356,0233,0315,'W','[',015,'~','C',0361,0300,'~','o',0356,'|',017,'?','O',0254,0265,034,0252,016,013,'B',0361,'3',',','[',020,0206,0362,0374,0326,0242,0223,0256,0351,0226,'B',035,0244,'z',014,'a',0216,021,0202,0312,0234,0221,0252,0267,0247,'+',02,'-',0252,032,0230,0317,02,0234,0352,0305,0320,0226,0261,0222,0266,0345,0254,032,'J','k',0321,0366,0316,'6',0213,0251,0277,'a','u',0367,0216,0235,0200,'o','8',0306,03,'l',0307,02,012,0317,'S','W','f',')',0235,0246,0316,'*','b',0343,013,0367,0341,0356,0377,0,0271,0360,'<',0375,'C',0211,0177,0224,0202,0243,0224,'e',0134,010,0333,013,0266,0235,0227,',','v','E','M','B',030,0304,0240,'9',0204,'Y',0330,025,011,'2',0300,0354,0210,0375,'_','h','k',0310,'*',021,0244,0336,032,0330,0134,'w',0347,0306,'y',024,0373,'M',0332,025,'}',0371,01,'@',026,0273,'C','[','K',0216,0375,037,'l',0343,'~','k','/',0211,0245,0312,0200,0253,0272,'Q','?',0366,'>','`',0265,010,0134,035,'F',0304,0275,047,0303,04,'N',07,0273,0376,0347,0300,0363,0365,017,0366,0232,0214,0256,':',03,0300,0305,']',03,'6','%',010,0302,'5',020,'2','`',0231,0314,02,0304,'1',0341,'4',0204,'a','A',0300,'X',':','2',0326,'2','V',0374,0275,0223,0253,0275,'y',0327,0212,'.',':',0344,'M',0274,0212,'X',05,'o',0254,'W','-','E','z','t','}',0263,0215,0320,0361,0215,']',0350,032,0361,016,0221,'r','6',027,0253,'Q',0257,0261,035,0343,0335,0253,0202,0214,0371,' ',0270,0344,'6',035,0257,'u',0274,0372,034,'=',0337,0367,'>',07,0237,0247,047,'Z',021,'&','U','+','b',0332,0343,010,0204,0254,'.','y','b','^','b','b',0320,'m',0362,'Q',016,'a','}','c',0254,036,'j',0216,'D','(','j',06,0374,0252,0323,0232,'|',0363,0272,'X',0317,0351,0313,'j','&','L','J',0243,0261,0321,0366,0316,'7',0220,013,0245,024,0354,'S',0357,'r',0367,'[','H',0217,0313,0243,0354,0312,0276,0227,0335,0277,013,06,0313,'2','p',0367,0177,0334,0370,036,'~',0234,'f',0326,0243,0210,0252,0270,'1','V',0263,0356,0247,04,0356,021,'i',0211,0320,0204,'2',0304,'#','&',',',0317,0225,0366,0332,0372,'5',0313,'J',0313,0303,0236,0201,'c',0247,'~','W',0224,0344,0253,0277,'K',0333,'8',0335,0342,0345,0300,'n',0374,'o',0357,'-',012,0254,0255,'x','5','~',0341,'T',';','I',0367,0240,0374,',','|',0220,'e','S',0263,'E',0345,0374,0360,0367,0177,0334,0370,036,'z','Z','C',0254,0311,'F','L','g',0257,'E',034,016,'v','R',0250,0213,0201,032,'G','P','q',0301,'&',0315,0261,0277,0270,'D',0266,'V',0265,'U','3',014,0346,01,',',0312,034,0347,'x',024,'W','-',0271,'k',0264,0345,02,0274,0276,'G',0251,0257,'u',0360,0203,0234,0343,0355,0234,'o',0266,0224,0341,'>',0347,0375,'K',',',0216,'!','{','i',0275,0273,0223,'$',0352,0352,0372,'J',0331,0366,0227,'&','8','W',03,'V','-','X','c',0307,017,'w',0375,0317,0201,0347,0242,0370,'$',0310,0376,'x',0361,'S',0357,'7','Q',0365,0211,'1',0336,'Y','o',0371,01,015,0371,'V',0213,0227,'/',0250,0225,0224,0314,'[',0134,'b',033,0305,'6',0217,'S','H','d','E',0345,0254,031,0247,0,0321,030,0313,'`',0225,'A',0315,'n','w',012,0273,'}',012,0357,0266,0363,'0',0343,0355,0234,'l','*',035,0214,0223,0323,'(','|',' ',0260,0261,'}','0',0215,':','a',0210,036,0241,'P','6','"',';','*',0262,0227,0357,0341,0356,0377,0,0271,0360,'<',0363,0255,026,0305,'o','r',0351,036,020,0347,'6',0305,0221,'Q',026,0310,0313,'`',0345,'J',0327,'a',017,'2',0320,0345,0275,'Z','"',0256,'Q',0235,0311,'l',0240,'`',0244,0300,'j',0203,0251,012,0254,0304,';','K',0201,0303,0222,03,0252,'k',0352,'5','w',0333,'y',0236,'O','l',0343,'m','W','z',0373,0336,036,0321,':',0247,0377,0,0,027,015,'f',0233,0335,07,0376,'b','M','{','f','u','7',0327,0355,'8','{',0277,0356,'|',017,'<',0340,0217,0224,0261,0267,0254,'K','^',0134,025,0362,0251,'[',014,0315,'w','^','B','e',0241,')',030,0225,0323,022,0202,0270,'{',0322,'w',0347,'Y','V',0275,' ',0202,'T',031,0335,',','K','+','T',0322,0331,0231,021,'~',0247,'W','u',0343,0223,'-','9',0236,'O','l',0343,'w',0236,027,0377,0,0214,037,0233,0201,016,'6',0307,0267,047,0273,0376,0347,0300,0363,0315,0343,02,'^',0316,021,0363,'b','+','y',0314,0311,0376,0260,0317,0315,0234,'B',01,'i',014,0223,047,0242,'z',023,026,0351,0242,0223,'y',0353,'I','m','b',0201,'X','8',021,'O',0215,0265,0302,' ',0323,0241,0262,'[',0177,'Q','A','!','i',035,0371,'X','g',0337,0314,0301,0343,0355,0235,013,0367,0177,0334,0370,036,'y',0215,017,021,0343,'{',0335,012,0202,0331,'!',02,'x',010,0345,'Q',',',0374,032,'D','D',0313,'t',012,026,0240,0247,'2',0331,0224,'a','h',0267,0273,'+','W','6',0301,0205,0215,'Q',0321,'e','>','<',0252,0304,'j',0337,'?',0262,0362,0256,0354,0243,0314,0315,0134,'}',0263,0241,'~',0357,0373,0237,03,0317,'5',0211,023,017,017,'D','T','^','f','D',0310,'x','q','P','6','C','X',0310,0134,'q',0275,'*',0224,'W',0347,0227,'d','1',0217,'y',0256,0222,0343,0210,0230,'3','O','J',0242,'j',0314,0345,0375,0276,'q','A',0255,0213,'9','s',';',0207,'d','@',0351,'Q',0345,'f',0256,'>',0331,0320,0277,'w',0375,0317,0201,0347,0236,0264,':','!',0243,'f',0252,0302,'W',0256,';',0305,0253,'Y',0305,'E',0344,0322,'/',0255,0220,'k','h','B','"',0237,'9',0322,0340,'Q',0322,0262,'E',0336,0317,')',0261,'K','T',0311,0316,',',0350,0252,'k',0211,'j','S',036,031,0344,0301,'w','C','P','@',0244,'q',0314,'q',0366,0316,0205,0373,0277,0356,'|',017,'<',0370,0273,'$',0265,0356,'G',0241,'A','l','[',0207,'1','J','q',0314,0225,022,0250,0263,'0',0240,'A','*',0203,0247,0262,033,'~',0274,0251,'b',0262,06,0274,0364,'N',0344,'l',0213,'-',0234,0242,0372,0276,016,0335,037,'l',0207,0244,0203,0316,047,0353,0236,'|',017,'<',0346,0356,'q','/',0343,'~',0225,013,'w',0347,'Q',',',023,012,'(','S','3',']','7','n',0311,'X',0326,0320,0224,0271,'I',0203,'C',']',02,'r',0267,0354,0134,0254,0341,0242,0252,0350,0250,'+',047,0340,0231,0355,'$',014,0,0327,'s',0317,'-',0,03,'C',0274,0327,0315,'J',0200,'_',0354,034,0342,0302,'T','$','/',0336,0375,'q',0,0224,023,'(',03,0231,0352,'V',0326,'b','G','x',0353,0221,'6',0362,'#',0303,':','7',0314,0246,0324,0375,035,014,0316,'H','4',016,'[','Z',036,0335,0206,':',0226,026,047,'C','R',']',0374,0331,0244,0363,017,'r',027,'U',0274,047,0311,'g',0311,'e','Y',0216,0372,0313,0206,'^','a',0220,'d',0211,' ','h',016,0206,'$','f','6',0334,0365,0230,0202,'P',026,'X',0345,0201,0202,030,03,0251,0257,'+',0254,0331,0351,0313,'a','x',0336,0312,0256,0303,0241,'[','[',0211,'=',0243,0256,0,0323,0310,0352,'(','6','0',0331,'W','6',0350,0203,02,0307,'f','1','+','|','*',01,0337,0330,0243,'>','k','>','k','>','c','<',021,032,0211,0244,0310,016,0210,0274,'L',0301,0332,'2',0245,0325,'s',',','p',07,02,0312,0307,'P',0324,0320,'.','=',0211,0310,016,'V','0',0321,'u',0364,'I','[','R','#','0',0,0224,'v','y','Y',0255,'=',0267,'D',0270,'-',0341,'F','d','|','j',')','!','x',0254,0376,'&',0177,023,'?',0211,0233,0250,0206,06,04,01,0337,'q',0321,0270,'%',020,'B',0311,0357,0324,'a',022,0262,0345,'2',0202,0365,'h','E',0200,0273,0304,'N',0325,0257,'w',0224,01,014,0201,0322,0261,0252,'o',0276,'[','"',07,0354,0336,'#',0242,036,017,';',0355,'N',0326,'h',021,0177,0376,0263,0325,'l',0354,'D','t','/','c',0307,'Z','8',0206,0240,036,0232,'S',0364,'6',04,'o',',',0177,035,033,020,'f','/','t',0311,0323,0252,011,'V','Y','b',036,03,'H',' ','4',':',0245,0336,0214,'n',0257,')',0337,0203,'t',0355,'4',0325,'=','"',0217,',',0373,'1',0304,'P','i','9','s',0335,0277,'u',0347,'>',011,0370,'I',0256,023,'P',0360,0323,'W','w',0224,023,'k',0206,'#',0271,014,0217,0210,0372,'!',0213,0367,0321,036,0360,'K','l',0214,0247,'I',011,030,0230,0300,'u',0205,'%','c',0252,'G',02,0325,0367,0216,')','n','[',034,0272,0210,04,0367,0351,0213,0266,024,0220,'u',0205,0312,0327,0270,0320,'E',026,010,047,'7',0272,0376,0245,02,0272,0267,0234,0206,0327,',',0370,036,'z',')','d',0300,0330,'u',0230,0231,0321,'R',022,0252,0345,'2',024,0365,0274,'7',023,0355,0313,0252,0342,010,'w',0224,0273,0345,0352,'k','_','e',0271,0315,0266,0212,0321,0324,0346,0367,'_',0324,0366,0237,0247,'?',0273,0376,0347,0300,0363,0322,032,0254,0324,'|','L','"',':',0347,026,0251,'L',031,0225,030,06,0220,0310,'4',0352,0326,0255,0372,0303,024,'U','N','[','r',0265,0277,0367,0346,01,014,07,'P',0276,0312,011,0203,05,'/',0216,'U','_',0262,0356,'O','a',0250,'<',0246,'M',0223,0367,0227,0243,'A',0227,0244,02,015,0216,'G',0230,'A','R',0351,0221,0225,0200,0305,'|',0206,0261,'l','9',0212,0322,'K','v',0225,0302,0335,0242,0264,0220,0211,'@',0326,'-','`','q','T','u','A',0226,02,'j',0315,0362,0367,0345,02,'v',0250,';',0263,0,016,0356,0266,0265,'v','[',0221,')',0247,0227,'#','v',0262,0303,0216,015,'+',023,0220,0332,0324,0345,0346,0134,'X',0322,'L',0351,030,0256,0220,037,0303,'O',0341,0245,'Q',0221,'t',',',0327,0267,0322,05,'<',0242,'8',0272,'o',010,'n',0346,'m',0251,0252,'3',0355,03,0273,0361,';',0247,0342,'y',0337,0211,0331,'o',0332,'.',0134,'z',0221,0225,'!','P','_','~',0260,0204,0247,'C',0223,0336,';','V','-',']',0371,'o','G',0232,0272,',',02,030,016,0261,'X',025,'#','-',0,0300,0230,0276,0334,0242,0241,032,'M',0310,'D',']',033,0354,0345,0303,0177,0230,'b','Z',0336,0365,0211,0244,0267,0274,0267,0274,0270,01,';',0262,015,'k',0355,035,'^',0206,'3','P',021,'}',0261,'m',0260,'-',0263,'G','3','N','H',025,0326,030,'l','U','w','c',0361,'^',035,0216,'T',0226,0252,022,0224,0313,0205,'f',0376,0201,021,0207,0341,'2',0340,'L',0216,0134,0357,'X',0230,'c',0254,032,0362,0217,'D','|',0221,'R',0252,0276,'3',0370,'y',0374,'<',0376,'^','S',010,0360,0257,0360,0214,025,0202,0343,0320,0375,0361,0363,0315,0265,'F',0227,0367,0364,'Y',0356,0350,'M',0271,0235,0262,'^',021,'4','2',0206,0352,0377,0,'(','(',032,0325,0227,0205,'6','<',0321,'s',0260,07,'h','(',0200,025,0364,'D','|','T',0251,'Q',0226,'P','m',0343,0231,017,0243,0341,'H','l',',','y','W',0371,01,'@',0326,0254,0240,'I',0211,013,'m',0274,0265,02,'`','L','^',0,031,0213,0350,0365,'6',0206,'j',0215,0210,037,0,0346,'C',0350,0370,'R','h',036,0326,0324,0377,0,030,0340,016,0325,023,'M',037,'v','-',0266,0362,0233,'V','(',015,0346,'4','N',07,011,'G',0351,'4','o',0243,0215,0353,034,0313,0221,032,0270,0213,0373,0250,0257,0370,0204,0264,'/',',',0263,026,'n',0317,'?',011,0315,0345,'y',0200,'C',01,0364,0347,'$','v',0204,0241,07,0327,'0',0335,0251,0315,'J',0,024,'G',022,' ','_','"',0177,0202,0315,'@',0306,0345,0211,'x','s',0241,0371,0256,0301,047,06,'1',0203,'o',0251,07,0343,0264,'%',010,'>',0271,0200,0323,'d',0260,0371,0312,'X',0213,'I','[',0263,'?',0134,031,0357,'j','C','u',0302,0326,0311,0273,'S',0233,0347,'M',')',0260,'d','z',016,0201,0365,'m',0200,'u',0355,'/','M','t',0217,'9',022,0316,0355,'`',015,0354,'4','#',0343,0375,0337,'T',0334,0245,0252,0247,'c',05,0232,0245,0247,'-',022,0216,'p',0266,0211,0266,0334,'=','`',0340,016,0201,0365,0272,'B',0270,'Y','c','#',0263,'G',03,0240,'a',0271,0335,0227,0332,'v','{',0266,0247,0242,02,'9',0372,'e','c','z',0252,0246,02,016,'$',0306,'[','G',0250,0252,'U',0265,0335,0347,'|',0230,0300,0336,031,'.','V',0364,0373,0300,0240,'j',03,0353,0332,0341,024,'S','$',0333,01,'I',0247,'D',0361,013,'y','a',0205,014,0360,0210,02,0312,047,0347,0366,']',0364,06,'X',017,'2',0244,'!','v',0333,'-','}',0275,'m','F',0205,0233,'v',0321,0321,0334,0350,0320,0301,07,'3','1',0134,'@',02,0202,0217,0360,'X','2',0324,'.','w',0314,'l','=',021,05,0245,'=',' ',05,'w','l',0210,',','0',0325,0303,'/','{',036,021,0215,0363,'z',0255,'p',0305,0265,0325,0266,011,0377,0,0267,'6',0202,036,0254,0254,0317,0351,0202,012,'V',0325,0313,0232,0301,'Q','+',0370,'M','M',0331,0302,0251,0346,0304,'+','z',' ',0240,013,']',0210,0217,0260,'=',0306,'x','=','.','_',0361,'H',0231,0267,023,'s','{','Y',0272,021,024,0211,'I',0263,0324,'m','V',0363,0211,'l',0363,'e',0360,03,0325,0235,'t',0346,'|','D',0134,0257,0322,'(','k',0275,0210,'Q',0355,'6',0251,0342,0316,0267,'/',03,0334,'z',0235,0343,0301,0242,'a',01,0344,'6','C',0204,'<',01,0376,';',0302,'>',021,0207,']','r','c','%',0241,0334,'E','"','R','l',0375,'i',0206,0357,'f',037,'y',0335,0356,0332,0204,0203,0373,'?',0313,'n','V',0324,020,0353,0356,'W','?',0221,021,0300,0356,'(',0327,0324,02,0200,'-','v',0235,0227,'A',0242,'h',',',016,0304,'<',0177,0263,0374,0364,012,'K','<',0307,'b',0274,0325,'L',0275,0245,0227,'P',0361,025,0324,032,0327,0216,07,'q','F',0276,0210,024,01,'k',0264,0331,0366,0326,0204,0322,0250,'.',0267,0231,0367,0323,034,026,']',0240,'+',0375,'M',024,'>',0261,'{','c',0274,'P','(',0227,'}',0323,0332,'%',010,012,0243,0321,0315,'_',0252,0355,0236,'p','c',0320,'7','L',0373,013,0215,'L',0213,0245,0232,0302,'u',0205,'E',0363,0313,']','R','S',030,0263,0204,'H','&',026,031,'X',024,0263,'@','W',0373,0210,035,0365,030,'f','}','b',0263,0371,0221,0231,'c',0273,'G','*',0224,0245,0134,0246,0225,'i',021,'6',024,0352,0214,0222,0267,022,'h',0240,'z',0177,0362,'u',0377,0,0323,0177,0377,0332,0,014,03,01,0,02,0,03,0,0,0,020,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H','$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,014,'I','$','I','$',0222,'I','$',0222,'A','$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'I','$',0222,'I','$',037,0316,'?','m',0270,'C',0325,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0272,'/','m',0266,0333,'m',0266,0332,0245,0322,'I','$',0222,'I','$',0222,'I','$',0222,'A','$',0222,'I','$',0222,'I','$',0212,0247,'m',0266,0333,'m',0266,0333,'m',0264,0277,'D',0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',0222,'I','$',0221,07,'m',0266,0333,'m',0266,0333,'m',0266,0333,'m',0,011,'$',0222,'I','$',0222,'I','$',0220,'I','$',0222,'I','$',0222,025,0311,'2',0333,'m',0266,0321,'%',0266,0333,'m',0266,0332,030,0222,'I','$',0222,'I','$',0222,'H','$',0222,'I','$',0222,'I',017,0322,015,025,0241,'>',0266,0352,0265,'t','6',0333,'m',0267,05,'$',0222,'I','$',0222,'I','$',022,'I','$',0222,'I',027,0335,0257,0303,'t',024,'d',0222,'I','$',0223,0301,0315,0266,0333,'B',0322,'I','$',0222,010,0,0,'I','$',0222,'I','$','T',0254,'-',0266,0345,'$',0222,'I','$',0222,'I','$','!',0273,'m',0266,0325,'$',0222,'H','&',0212,'5',0204,0222,'I','$',0222,0233,'_',0266,0333,0134,0222,'I','$',0222,'I','$',0222,'H','X',026,0333,'j','B','I',' ',0243,'8','^',0362,'I','$',0222,'O','-',0257,0333,'m',0256,'I','$',0222,'I','$',0222,'I','$',0222,0345,'m',0266,0252,'$',0203,'Q',0377,0,0377,0,0221,'$',0222,'I','<',0266,0327,0355,0266,0327,'$',0222,'I','$',0222,'I','$',0222,'I',047,'N',0333,'j',0240,'J',0177,0377,0,0371,'d',0222,'I','$','6',0333,'k',0366,0333,'k',0222,'I','$',0222,'I','$',0222,'I','$',0222,',','-',0266,0257,035,0377,0,0377,0,0323,0320,'I','$',0220,'k','m',0252,0373,'d','9',0311,'$',0222,'I','$',0222,'I','$',0222,'I','$',0206,0333,'g','O',0377,0,0377,0,'2',0210,'$',0222,'C',0355,0266,0252,'=',0331,0320,0344,0222,'I','$',0222,'I','$',0222,'I','$',0222,'O','-',0277,'/',0377,0,0377,0,0305,'$',022,'I','%','v',0333,'x',0236,0232,'M','r','I','$',0200,'I','$',0222,'I','$',0222,'I','$',0356,0324,037,0377,0,0377,0,'D',022,011,'$',0237,0333,'m',026,'O','l','.',0271,'$',0222,'@','$',0222,'I','$',0222,'I','$',0222,'E','0',0177,0377,0,0377,0,0322,'I',04,0222,017,'m',0265,011,047,0256,'y',0134,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','%',037,0377,0,0377,0,0361,01,'$',0202,'I',0,0266,0327,0244,0223,0332,'`',0256,'I',' ',0222,'I','$',0222,'A','$',0222,'I','$',0222,0237,0377,0,0377,0,0225,'D',0222,'A','$','2',0333,'@',0222,'I',0350,0331,0327,'$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'@','7',0367,0377,0,0323,022,'I',' ',0222,'7','m',0276,0311,'$',0361,0223,'k',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$','U','d',0177,0354,011,'$',0222,'H',035,0266,0201,'$',0222,0177,0210,'u',0311,' ',0222,'I','$',0222,'I','$',0222,'I','$',0203,0376,':',0221,'E',0244,0222,'H','$',0302,0333,'@',0222,'I','=','e',':',0340,0200,'I','$',0222,'A','$',0222,'I','$',0220,016,'?',031,'Z',0234,'0','I','$',022,'K','m','n','I','$',0236,0354,'=','p','@',04,0222,'I','$',0222,'I','$',0222,'I',036,0256,'t',0250,02,0255,'D',0222,011,']',0266,0363,'$',0222,'O','j','V',0271,' ',0222,'I','$',0222,'I','$',0222,'I','$',0206,033,0312,0205,0221,'C',0302,'I',04,026,0333,'T',0222,'I',047,0265,'[','T',0222,'I','$',0222,'I','$',0222,'I','$',0202,'s',0365,0370,0377,0,0265,0266,0211,'$',0202,'k','m',022,'I','$',0223,0336,015,0242,'I','$',0222,'I','$',0222,'I','$',0203,'A',0267,'"','I','l','v',0332,'D',0222,'A','-',0266,0211,'$',0222,'I',0352,'o','[','$',0222,'I','$',0222,'I','$',0222,'A',0340,'y',0232,0214,0206,'K','m',0356,'I',' ',0262,0333,'l',0222,'I','$',0365,'=','/',0222,'I','$',0222,'I','$',0222,'I','$',020,'>','2','&',0300,'<',0266,0223,'$',0220,'9','m','&','I','$',0222,'{',037,0365,0311,'$',0222,'I',04,0222,'I','$',0222,'C','{',0256,035,0244,0226,'[','j',0222,'H','!',0266,0303,'$',0222,'I','=','e','z',0344,0222,'I','$',0201,'I','$',0222,'I',07,015,0315,'g',02,'H','-',0264,0311,'$',02,0333,'z',0222,'I','$',0236,0271,035,'r','I','$',0222,'H',0244,0222,'I','$',04,'}',027,035,'I','$','v',0332,'$',0222,01,'m',0252,'I','$',0222,'O','R','*',0271,'$',0222,'I',0,0222,011,'$',0220,025,0350,'Q',01,'$',0222,'+','m',022,'I',03,0266,0325,'$',0220,011,047,0266,'C',0134,0222,'I',' ',0222,0320,'@',0222,'H',0,0321,'&','X',022,'I',025,0266,0361,'$',0201,0333,'n',0222,'H','$',0223,0327,'0',0256,'I','$',0222,'4',013,0240,'I','$',0340,0353,0231,036,'I','$',0232,0333,'x',0222,'@',0355,0267,'I','$',0202,'I',0351,'Y','W','$',0222,'H',0201,0377,0,0377,0,'D',021,'#',0327,0323,0300,'$',0222,'M','m',0274,'I',' ','v',0332,0344,0222,01,'$',0365,013,'k',0222,'I','$',0263,0377,0,0371,'"','@',0314,'D',0360,0340,0222,'I','#',0266,0336,'$',0220,033,'m','r','I',04,0222,'{','m',0265,0311,'$',0201,'O',0377,0,0377,0,0301,03,0201,'E',0340,0202,'I','$',0221,0333,'i',022,'H','5',0266,0341,'$',0202,'I','=',0266,0332,0344,0222,'A',07,0377,0,0377,0,0366,06,0377,0,';',0377,0,011,'$',0222,'H',0255,0267,'I','$',02,0333,'N',0222,'I','$',0236,0333,'m','r','I',' ',0227,0377,0,0377,0,0360,0305,'?',0365,025,04,0222,'I','$',0366,0332,'$',0222,04,'-',0261,0311,' ',0222,'O','m',0266,0271,'$',0222,'A',0177,0377,0,0376,'8',0377,0,0377,0,'0',0222,'I','$',0222,'+','m','r','I',03,0366,0333,'$',0222,011,'#',0226,0333,'|',0222,'I',02,0337,0377,0,0377,0,0253,0377,0,0377,0,'p','I','$',0222,'H',0325,0266,0311,'$',0202,'{','m',0262,'I','$',0223,'K','m',0330,'I','$',0202,0277,0377,0,0377,0,0377,0,0377,0,0376,0270,'$',0222,'I','$','&',0333,',',0222,'A','%',0266,0363,'$',0222,'@','/','o',0251,'$',0222,'H','=',0377,0,0377,0,0377,0,0377,0,0364,0300,0222,'I','$',0222,013,'m','J','H',' ',0204,0333,'M',0222,'I',' ',022,'I',010,0222,'I','$',033,0377,0,0377,0,0377,0,0377,0,0370,'"','I','$',0222,'I',0225,0266,0331,'$',0220,'M','m',0264,'I','$',0222,011,'$',0220,'I','$',0222,013,0277,0377,0,0377,0,0377,0,0366,01,'$',0222,'I','$','2',0333,'D',0222,'H','$',026,0333,04,0222,'I','!',0251,'+',04,0222,'I',' ','W',0377,0,0377,0,0377,0,0215,'$',0222,'I','$',0222,'[','m',0202,'I','$',022,'c','m',0242,'I','$',05,0333,'i',0202,'I','$',0222,'c',0377,0,0377,0,0377,0,0362,0222,'I','$',0222,'H',0275,0266,0271,'$',0222,011,'5',0266,0326,0244,0222,05,'m',0266,0311,'$',0222,'H','4',0377,0,0377,0,0377,0,012,'I','$',0222,'I','$','6',0332,'<',0222,'I',04,0220,'[','m',0362,'I',03,0266,0333,0134,0222,'I','$',0200,'O',0377,0,0376,'A','$',0222,'I','$',0221,0273,'m','J','I','$',0202,'I',0275,0266,0345,'$',0202,0373,'m',0204,'I','$',0222,'@',0372,0352,'4','p',0222,'I','$',0222,'E',0255,0266,'Y','$',0222,'A','$',0202,0333,'n','R','I',047,'$','4','$',0222,'I','$',027,06,0232,0342,'I','$',0222,'I',' ',026,0333,0224,0222,'I',' ',0222,'C','-',0264,0231,'$',0201,'$',0244,0222,'I','$',0222,'@',0,0222,'I','$',0222,'I','$',0206,'[','n',0362,'I','$',0220,'I','$','2',0333,'x',0222,'A','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,')','m',0264,0211,'$',0222,'H','$',0222,01,'m',0265,0311,'$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H','-',0266,0334,0244,0222,'I','$',022,'I','%','V',0333,'g',0222,'@','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','"',0226,0333,'e','2','I','$',0222,011,'$',0222,'O','m',0266,'y','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0226,'[','m',034,'y','$',0222,'I',04,0222,'I','&',0366,0333,0177,022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,']','m',0266,0225,'$',0222,'I','$',0202,'I','$',0222,05,'m',0266,'s','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'A',0205,0266,0333,'d',0222,'I','$',0222,011,'$',0222,'I',05,'V',0333,'l',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','(',0226,0333,'i','"','I','$',0222,'I',' ',0222,'I','$',0220,'u','m',0266,0276,'d',0222,'I','$',0222,'I','$',0222,'I','&',0272,0333,'m',0266,0311,'$',0222,'I','$',0222,'I','$',0222,'I',' ',0366,0333,'m',06,0311,'$',0222,'I','$',0222,'I','$',0331,0233,'m',0264,05,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,031,'m',0266,0332,0320,022,'I','$',0222,'I','$',0314,0373,'m',0266,0324,0254,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','#','.',0333,'m',0266,0307,0332,0302,'H',';',';',0261,'m',0266,0332,'r',0222,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I',015,0266,0333,'m',0264,036,0263,'&',033,'m',0266,0333,'m',0312,'I','$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'I','$','A',0233,'m',0266,0333,'m',0266,0333,'m',0266,0333,'m',06,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I',0201,'v',0333,'m',0266,0333,'m',0266,0333,'m','.',031,'$',0222,'I','$',0222,'I','$',0222,'A','$',0222,'I','$',0222,'I','$',0222,0300,0235,0266,0333,'m',0266,0333,'m',' ','m','$',0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$','W','x','E',0266,0333,'l',0372,'?','$',0222,'I','$',0222,'I','$',0222,'I','$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0333,015,0266,0,0251,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0200,011,'$',0220,'H','$',0222,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'O',0377,0304,0,'-',021,01,0,02,01,02,05,01,011,01,01,0,03,0,0,0,0,01,0,021,'!','1','A',' ','0','Q','a','q',020,'@','P',0201,0221,0241,0261,0301,0321,0360,0341,0361,'`','p',0200,0377,0332,0,010,01,03,01,01,'?',020,0377,0,0344,0300,'V',014,0357,047,'y',';',0311,0336,'D','L','?',0370,02,0324,0236,03,'(',0315,'5',0256,04,017,0271,06,'_',0251,017,0250,'j','`',0277,0214,'(',023,'[','-',0237,'i',0374,0357,0356,01,'+',0242,0217,0336,0347,0362,0237,0211,0374,0247,0342,0177,')',0370,0237,0310,'~','#',0207,0327,0263,0373,0207,0211,'N',0252,0375,0303,'H',0235,'n',0377,0,'Q','W',0247,0260,0337,0322,012,'b','i','N','_',0204,'L','%',027,0244,'p',022,0275,0354,012,0242,'=','N',0235,'k',036,'a',07,0206,0311,0371,0351,'+',0215,0235,0177,'M',0240,'4','~',0,'}',0275,0200,025,026,'t',0332,'X',0344,'%','X','S',0360,0254,'}','%',0221,'7','A',0310,'|','u',0372,'K',0252,0206,0371,'c',0274,'@',0344,'u','=',0342,'Y',0351,0322,'P',0247,'k',0364,0215,025,'}',0362,0372,'i',0367,0200,'@',0240,0333,0331,0324,02,0333,0325,'?','8',0240,0266,'4','>',0177,0270,0326,'`',0353,0267,0273,'K','=',':','J',032,016,0215,'~','=','!',0301,0367,'n',0371,'}',0261,0330,0223,'g','2',0305,0273,0177,0314,'G','"',0367,031,'>','~',0351,032,'V',0262,0227,0307,'6','r','<','m',016,'w','U',0226,0371,'g',0375,02,0177,0320,047,0375,02,035,'I','v',0263,0226,013,0244,0267,'I','n',0234,0367,'b','M',0234,0300,0232,':',';','>',':','K',020,'_','G',0334,0302,';',0362,0320,0230,0272,0246,0134,0236,07,'X',0235,'i',0272,0313,'}','K',0202,0212,0211,'.',0204,0360,'-','O','0',0303,0330,0372,0211,'H','w','C',0357,027,05,'M','C',',',0245,0207,0256,017,0246,'a',0200,035,025,'_',0231,0244,'v','Q','{',0200,'O','H',0277,03,0346,0177,0336,'`',015,0375,'f',04,014,021,0205,0313,0350,0272,0217,'=',0267,025,0366,0200,'n',';',034,'}','e','3','e','l',0243,0347,014,010,'t',0247,0361,0257,0323,0226,0364,')',0363,'<',';','E','w','k','[',0216,0361,025,012,'}',0304,'H',0355,'f','E',0335,'7','?',0250,'A','@',0240,'1',0235,017,',','t',0255,'-',0235,0221,'4','b','S',0244,0247,'H',0266,022,025,'G','H','_',0216,0245,0332,'Y',0273,0332,0301,0363,0336,'Z',010,'{','k',0363,0212,'X',0236,0361,'W','^','h',0245,0211,0321,0225,'A','K',025,0221,'(',0230,0372,0344,'|',0240,0345,013,0246,0217,0313,0365,0311,0327,020,06,0276,0246,0317,0303,'h',0344,0320,0327,'g',0307,0270,0,0255,':','M',0327,'O','o',0365,0350,0366,'c',047,0302,013,04,0240,016,'+',0350,0220,'8','}',0222,0331,027,'h','z',0217,0267,0340,0300,0215,0364,0317,0306,02,'%',0217,'#','/','f',0316,0347,0210,015,'e',0310,'4',0256,0374,0312,021,'=',0342,';',0316,0354,0321,036,'v','l',':',0273,036,'X',0,0357,0376,'A',0333,0327,0372,0273,'M','?','n',0205,'2','D',0216,0341,'d',0224,'+','v',0316,0217,0207,0221,0246,01,'#',07,'L',0377,0,023,0317,' ','u','M','.','i','S','t',0227,'o','-',0226,0304,'0',0313,'_','1',0216,0266,0356,0301,016,0206,'w','w','_',0327,07,0365,'v',0232,'~',0340,0205,'V','N',0267,04,'z','v','`',0355,032,0325,0251,0306,0340,0354,'p',0216,0362,0360,0317,'S',0371,0247,021,0263,'~',0343,'P','!',0220,'r',0361,0326,0335,0330,'!',0320,0316,0356,0353,0372,0341,0376,0256,0323,'O',0334,'P','5',0207,'I',0224,03,'M',0217,0237,0334,02,'%',0217,023,0203,0261,0302,';',0313,0303,'=','O',0346,0234,02,'h',0326,';',0267,0215,025,023,' ',0362,0354,0340,0241,0310,'c',0221,0273,0372,0342,0376,0256,0323,'O',0334,'p',0214,0221,0246,0317,0361,'<','A',0347,'M',0317,0354,'q','8',';',034,'#',0274,0311,0213,0305,'m',0331,0364,'9','%',0217,030,0134,0247,0226,'Y',0231,'(','&',0230,0272,0257,'N',0327,0367,0342,'p',0364,031,'W','i',0221,'Q',0333,0335,0320,0355,'4',0375,021,'F',0307,0252,0205,0255,'A',0241,0355,0360,0264,0263,0344,'L',0275,0206,0246,0347,0236,025,0254,0260,0343,'H',0341,'%',0346,0310,0327,'r','-',0300,01,'G','(','/',04,0250,0315,'i','v',':',0376,0270,0234,'=',06,'U',0332,'V',030,0352,0377,0,'4',0364,0323,0364,0270,'D',0350,0266,0342,0345,'R',036,'(',0262,'=',0301,'c',0255,0271,0262,'C',0251,0235,0315,0307,0365,0300,0234,0271,0217,036,'"','P','i',0310,'{',0235,'!',0232,'9','l',03,0270,0367,0355,0,0201,'A',0305,'R',0315,'A',0273,0365,0353,0247,0351,'m',0325,'4','Z','0','*','a',0223,'"','*','+',0334,'6',':',0333,0233,'$',0321,'|','d',0350,0364,0364,'x',0363,'-',010,'^',0344,013,'Q',06,0203,0226,'G','Z','T',0332,';','^',0356,0377,0,0347,025,'h',0333,'Y',0267,'h',0252,0267,0327,'O',0324,'Y','/',0353,014,0243,0355,025,0245,0356,':',0214,0263,'P','t',0256,0260,0204,0353,',','c',0325,024,0250,0326,'*',0266,0361,0273,0242,037,'2',0254,0275,0341,0241,0327,0343,0304,0261,'p','b',0266,':',0304,0253,'k',0301,0247,0350,0325,021,04,0331,0350,036,0303,0356,'8','.','X',0352,0362,'v',0224,0325,0326,';',0267,0214,'-',0242,'R',0346,016,'w','q','v','!',0305,'A','G',0203,0205,'y',0300,0301,0325,0330,0217,'1','V',0373,035,'8','t',0375,'(','=',0221,'F','0',0316,0313,'+',03,0334,'p',0324,'+',030,0334,0212,0324,02,0212,0345,0205,0264,'J','b',0335,'|','l','q','%',0207,0344,'w','x',0264,0375,',',':',0247,'r','w',' ',0320,'}',0307,'(',026,0303,'g','b','t',0322,035,'V','x',0226,0355,0241,0232,'9',0210,'#','{',0300,0200,'A','A',0302,'+',0262,0373,0206,0354,'U','[',0305,0247,035,'5','#','7','R',0376,0323,0307,'<','q',0277,'C',0334,'u','*','C','}',0351,'b',0262,0334,0260,'A','G',0314,06,0317,'U',0250,0205,'P','s','@',')','g',0370,'m',0363,0341,'|',0250,'-',0360,'G',0223,0252,0217,06,0234,'z','p',016,0304,'H',014,'3',0266,0235,0242,'3','c',0334,'Q',0311,0335,0262,0202,0313,0337,0211,0324,0264,0256,'4',0202,'s',0312,0316,0270,0212,0210,020,'b',036,0370,0177,0325,0223,0226,'/',']',020,0362,0240,0243,0301,0303,'D',0275,0177,0347,'^','F',0237,0245,0350,0231,0372,0276,0211,0372,'+',036,0341,0206,0306,047,0244,',',010,0365,'u',0207,023,'3','Z',0353,035,' ','d',022,0231,025,'X',0207,0316,'a',020,0352,'y','?',0316,']','a',0301,0247,0227,0374,0341,05,'J',015,'b',0371,0201,0243,0301,0247,'#','O',0320,024,'a',0202,0235,0224,'N',0225,0373,0202,'Z','-',0226,'=',013,'1',01,0232,'Y',0234,0306,'`','a',0300,0265,0,'!',0225,0264,0203,0204,0313,0301,0350,0206,',',026,'y','3',0366,0210,0313,'i','W',0310,05,'Q',015,0222,0262,'<',0277,0347,012,025,'V',047,0215,0342,0333,'o','#','O',0321,024,'n','z',0253,'~',0207,0270,'*','4',0213,'m',0301,'U',0264,0275,'8',0201,0233,',','X',0270,'#',020,0134,0315,'I',0252,0225,'Q','K',0,'@',0242,0217,'L',':',0304,0254,0311,0263,0303,'.',0271,04,'u',0330,0326,01,'4',015,'<','p',0351,0255,0325,'w',0337,0223,0247,0351,'k','V',0261,012,0355,0356,020,0356,0214,0213,0350,0304,0235,'T',0345,'h','h',0226,0217,'5',022,0311,0335,020,0344,024,'b',034,'=','8',032,0305,0206,0323,0275,0232,'}','9','6',026,0237,'{',037,'N',027,0317,05,'~','Q','K',0312,'^','N',0237,0242,'(',0330,0212,'F',0263,0307,033,0364,'=',016,0277,'l',01,'l',0306,032,'z','Y','X','2','b',0322,0304,'p',014,0301,'-',0252,0,014,0312,036,0203,0373,'[',0343,'O',0353,0363,0303,'Q','5',0257,0311,0267,0327,0222,'v',0227,0364,'+',0376,0360,0340,01,'(',0356,'n','}',0271,'Z','~',0210,'%','>',0251,'/','b',0275,036,07,0266,'T','z',0,0357,'i','j',0261,014,0264,'5',0306,' ','p',0326,017,'P',0263,'h',0,'Q',0351,0241,0200,'J',0352,0355,0365,0341,06,0266,047,0314,0251,0236,'.',0311,0365,0343,05,01,',','+','2','N',0357,0371,0134,'4',0255,0353,'=','3',0236,'V',0237,0245,0327,'D','U',0263,'-',0227,0232,0370,0304,0332,0335,'W',0266,0300,0321,0356,'}',030,0232,0270,'f',014,032,'F',')','s',01,'0',0365,'B',0240,0365,'b',0224,0241,0304,'0','t',03,0363,'/',0205,0312,0260,0263,0303,0307,0236,0252,0301,0365,0227,0376,0300,0371,025,0302,0345,'X','Q',0340,0345,'i',0372,0341,'q','=',0315,'"','[','g',0266,'@','-',0213,'V',0336,0205,0331,'Q',013,0275,'.','.',030,0333,',','P',0265,0252,'P','(','|',020,0250,'I','a','Y',0202,0367,'?',0312,0341,'{','}',',','x',0307,030,0273,'b','#',0234,0360,033,':',05,0371,027,'4',04,'G',0353,0312,0323,0364,0272,0352,0217,'a','l','f',020,0262,'8',']','O',0266,'U','c',0350,0312,016,0364,0345,'B',0263,',',0247,0202,' ',035,'F','e','e',0370,0235,06,'R',0376,'?',0363,0205,'O','0','S',0341,0257,032,0211,0320,0247,0220,0341,0325,0250,0177,0134,'~','b',0261,'y','Z','~',0232,0266,'c',0264,'T',0323,'_','l',0212,'L',0355,0364,0352,0216,034,'Y',0210,0307,'O','@','w','G',023,'0',0300,024,'q','m','I','_',025,0327,013,0203,0311,'W',0307,'_',0267,031,0241,0221,'o',0234,034,'=',015,'K',0303,0377,0,'9','z','~',0232,0224,'e','0',0363,011,'P',0334,'e',0227,0212,0366,0250,0205,0261,0275,047,'J',017,'N','g','M','`',0224,'L',0312,'w',0210,0,030,024,034,'a',035,'U',0374,'2','p',0211,013,0244,'_',05,0361,0375,'3',0356,'p',0257,0324,0205,'w',0253,0276,'^',0237,0246,0357,020,0261,0372,0302,'j',0232,023,0235,'(','k','5',06,'%','4',047,0223,'V','>',0210,0366,0240,'K',0301,'+','V','5',0203,0257,0242,016,03,'0',0254,'y',07,0207,'V',07,'u','8',0177,0237,0271,0307,0364,0317,0271,0303,0365,0337,0261,0313,0323,0364,'W','D',0352,0211,'b',0225,'#',' ',0346,'K','Z',0372,'6',0237,024,0353,0350,0356,0310,'<','p',0337,01,036,'*',0206,0251,032,0262,'>','h',0300,'k',0351,'r',0360,'+',0233,037,0317,0334,0343,0372,'g',0334,0341,0372,0357,0330,0345,0351,0372,'/','E','G',016,0331,0227,0257,0234,'[',017,'.',01,'l','f','*','V',0360,0340,0340,0331,'|','4','-',0236,'2',0134,'6','g',0304,',','-',026,0201,0254,'m',014,'J',013,'t','D','@',0303,'4','s',0243,0371,0373,0234,0177,'L',0373,0234,'/','s','_','R',0377,0,0347,'/','O',0323,'^',0314,0300,012,0346,0310,'c',0306,0254,'2',0235,0341,0255,'I','u',0272,015,0326,'.',014,'|',0324,0333,0254,0261,0273,'D','%','s',0257,010,0134,0251,'B','k','?','*',0341,0376,'~',0347,032,0204,0317,0332,0317,011,'Z',0177,0213,0345,0351,0363,0355,021,'*',0276,'F',033,'p',035,0214,'{',030,0342,'i',017,021,0274,0255,0274,'1',0255,0243,0221,'e',0225,'e',0313,'.',0177,0325,'p',0233,'7','C',0346,0377,0,0234,0177,0315,0333,0204,0257,0227,0376,0216,'^',0237,'>',0310,0227,034,0212,0210,0251,'~',0213,'E',0314,'3',0326,0234,0334,'%',014,0306,'f','H',047,'N',020,01,0202,'P',0243,0226,'*',015,0237,'~',037,0340,'w',0343,047,'U','m','>','8','i','b',0324,'+',0275,'5',0365,0202,'m','"',0362,0264,0375,0202,0256,0374,0201,0254,0314,'?',0246,030,0213,'y',0341,03,014,0303,'(',0207,'W','2',0277,'F',07,0255,031,0341,'a','(','U',0367,0301,0306,0243,0340,031,0370,0300,';',016,'O',034,03,'M',0306,'}',0272,0134,0255,'?','`',0263,'<',0235,'{','H',0134,'#',0334,0361,05,0312,0226,0346,0272,015,0345,0363,0177,0316,023,0320,01,'S',0313,0207,0345,0306,0350,'X','$',0320,'?','B',0277,034,'.','f',0202,'o',0253,0277,0327,0224,0250,'0','l',0276,'+',0271,'+',0262,033,047,0260,'g',035,' ',0245,034,0303,'~',0325,010,'C',0225,'A',']',032,0317,0327,0204,0330,0322,'/',0207,'#','1',012,0236,015,0217,0277,010,0352,0205,'O',0207,'O',0255,0362,0317,'x',0341,0275,'1',031,'r','R',0317,'`',0247,0240,0207,'G','4','D','n','<',031,0216,'s',0300,0205,0320,'2',0370,0231,'_',026,'y',024,0240,'f',0207,'U','?',0316,026,021,0225,047,0223,'$','&','2','5',0312,032,0322,'n',036,0240,0270,0231,0362,0330,'9',0300,0271,'R',0334,0352,027,0256,037,0224,0373,'p',0344,0200,'l',027,0325,0305,'|',0256,'+',027,'~','@',0250,0334,'x','q',034,'c',0203,'I','F',0253,03,0303,0236,'}',0362,0355,0340,0246,0271,0271,'D',012,'(',0346,0241,015,0341,'U',0323,'V',0371,'s',0366,0256,021,0325,012,0337,06,0237,'[',0344,0240,'t',0241,0233,01,037,'=',0370,'H',016,'Z','^',0316,0236,0324,0226,'T',0266,0346,'0',04,':',016,'q',0225,0274,0217,04,0323,'N',033,'5',0207,0346,0336,0274,0362,0256,0306,'U',0236,037,0366,0270,'@',0274,032,0204,0336,'R','r',']',0241,027,0253,'-',0326,'[',0254,026,0214,'R',0207,'2',0303,0226,0326,'T',0267,'=',010,0346,0243,0301,0373,0341,'a',0350,'g',0365,0365,0232,0203,'%',0345,';',0332,'?',0314,0232,'p',0321,014,'a',0345,0327,0343,0310,013,'j',015,'[',0360,0235,0210,0254,0271,'v',0344,0270,036,'S',0330,0351,05,'+',0234,'n','j',0347,0306,0360,'M',0240,03,0206,0260,011,'o',0203,0375,0345,0203,'Z','L',0317,013,0217,0223,0177,0217,011,0235,0243,035,0235,0230,'/',0322,'W',031,0260,'<','`','=',0224,0205,0240,0203,'W','>',0200,'l',0370,'n',0374,'x','p','k','7','3',0320,0354,'s',',',0323,0245,0333,'g',021,' ',0365,0300,0357,0327,0343,0307,0243,0354,'v','6','"',0247,0221,'Q','~','~',024,0215,'W',0240,'k',04,0312,012,'8','E',0257,'a',0371,'b','%','j',0363,027,0212,'U',0307,0323,')','^','F',0274,'&','u',0215,'0','O',0301,0247,'s','n','*',0206,' ','Y',0305,'l',0234,0307,'>',0214,0225,0207,0205,'4',021,0226,0,'(',0347,'"',06,0254,032,0274,031,0354,'m',0363,0341,0323,'Y','f',0266,037,0227,0235,'f',0335,'.',0333,'8',0234,016,0361,'F','S',0244,'V','t',0234,'O',0320,'M',021,0235,0351,0336,0211,'o','+','s',0224,035,'f','B',0243,013,0375,020,0315,034,0201,0134,0366,0355,'j',0314,'.',0223,'M','8','A',0257,0370,026,'"','V',0257,'8',0212,0322,'K','1',0212,0206,0366,'o',0361,0342,0275,0317,0351,'6','z',0370,0367,'u',0311,015,0335,011,'J',0317,0255,0337,0343,0302,0341,0350,'2',0254,'P','6','<',017,'`',0134,0266,0307,'h',0361,'X','Y',0341,0341,0262,0261,'R','v',0202,0222,0363,0235,0273,'>',0354,011,0255,'*','k',0247,0376,01,0333,0213,0374,05,'z','~',0375,0210,0265,0301,0257,'w',0267,0353,0212,0312,0313,0346,'w',' ',036,0365,0272,0236,0352,012,'6',0262,0300,0307,'y',0372,016,0374,'H',0361,0260,';',0277,0344,'M',0255,'/',0330,0252,0340,0226,'0',026,',','C',0277,'_',0217,023,0320,0316,0316,0343,0372,0230,0353,'l',0354,0236,0350,012,026,0262,0316,013,' ',0375,'O','~',047,0212,0202,0337,04,'e','t',0302,'?','?',030,0373,032,'>',0364,0272,0222,0302,0337,'0',0354,0361,'=',014,0354,0356,'?',0250,'.',0303,0320,'h',0373,0233,'e','0','#','T',0233,06,0247,0372,0342,0323,'X','v',0224,'r','4','{','x',0364,0277,'d',0326,0242,0344,0351,0334,0226,'V','+',036,0334,'V','F','>',0217,'R',024,0265,0264,'z','v','}',0311,'k',010,'o',0214,'e',0351,0326,0277,'|','n',0215,0225,'.',0207,'o','1',022,0265,'}',0235,'R',0265,0243,0374,0322,030,'{',034,0211,0277,023,0221,'&',0316,'H',0325,013,'m',0275,'>',':',0307,0245,'I',0356,033,010,0263,'+',0361,017,'g','n',0265,0177,0272,'q',0253,'^',0213,0356,'{',0304,')','k','W',0332,'o',014,0364,0177,0232,'C',017,'c',0221,'7',0343,'C',0134,'x',037,0222,'(',0355,0303,'G',0333,0227,0202,'h',020,'|',0207,'n',0227,0277,0352,031,020,'l','`',0343,'@',0373,03,0356,'{',0315,'T',0301,'}',0256,0201,'W','c',0253,0376,'!',0202,0312,023,0215,0240,'S','f','"',0245,0267,'_',0206,047,'r',':',0236,0324,030,0255,'g',0317,'M',0253,0340,0206,'B','=','Y','~','{','r','6',']','=',0277,0324,0337,'L',037,'m','d',027,0354,0355,0334,0226,'V','_','3',0263,0310,'Z','.',0367,0342,'X','Q',0356,0374,'2',0334,'>',017,'f','.',0204,0364,0206,0217,0317,0253,0340,0201,'<',0313,'/',0371,0311,0316,0245,')',0351,0361,022,0245,0257,0267,0341,'D','k',0261,0204,'A',0271,0372,0362,'Z',025,'6','K',0207,05,0375,'2','|',0277,0354,0263,027,0316,'y',0255,0245,0201,0256,0347,0260,'#','B',0342,'e',0207,'S',0202,',',0177,021,0277,0352,016,'P',0272,0352,0374,0377,0,0134,0227,'C','-',0331,'y',0213,'u','5',0362,0212,0253,'}',0302,'}',01,0271,037,0340,0203,0247,0317,'X',014,0223,'D',0323,0224,0240,'k',0324,0374,0353,'(','Z',0373,'d',0371,':','E',0306,'l','8',0371,0272,'O',0212,0357,'"','4',015,0273,014,'O','*',0342,0321,027,'/','m',0247,'A',0201,032,036,0323,'D','k','[',0277,0241,',',0211,0232,0206,07,0343,0257,0322,'S',0240,'L','Z','[',0361,0274,'}','&',0205,'r',0234,'6',0251,'F',0203,0336,'4',0276,'t',0330,0370,'{',0226,0331,'s',0325,'d',0251,'O','b',0335,0370,'y',0240,0326,'N',0216,0221,0312,'C',0256,037,0202,0177,';',0373,0237,01,0322,0243,0363,'?',0201,0372,0201,'7',0375,'>',020,'`',0373,0337,0270,0232,0333,'k',0213,0373,0334,0317,0237,0200,037,'i','w',0257,'2',0272,0206,0335,'_',04,037,'"',0302,0356,0376,0243,'g',0265,0367,'9','g',0244,0224,0230,'n',0272,0236,030,023,0314,0260,0377,0,0276,0334,0264,']',0357,0304,0260,0263,0335,0370,'#',0264,'.',0376,0353,014,0324,0222,0223,035,0327,'S',0303,'>',034,'_',0333,'H',04,'K',035,0375,0245,'@',')',0265,0333,0362,0226,0252,'/',0361,'D','N',0344,0365,'}',0336,'*',0262,'X',0315,'t','r','|',0245,025,'n',0377,0,'r','~',0240,0242,'7',0321,0303,0365,0307,0326,01,022,0307,0177,'c','p',' ',0326,0322,0376,'Z',0313,047,'|',0242,0377,0,'$','L',0305,0333,'W',0317,'X',0201,0311,0352,0373,0321,'2','U',07,0240,036,'f',0,'_',0227,0333,'Y',0243,0223,0256,0277,'H','d','6',0332,0303,0371,0225,'B',0227,'J',027,0362,0271,'I',0267,' ',027,'H','m',0220,0356,0207,0336,'U',']',0363,0177,'k',0224,'@',0266,012,0277,014,'e',0320,0306,0252,0321,0373,'K','!',0260,'R','`','E','K','W',0253,0357,0302,0215,023,0274,035,'x','w','}',' ',0203,'=',0310,',',0376,'b',0177,'1','?',0230,0237,0314,'D',0341,0227,0261,0244,'*',0360,'w',0224,02,'w','X',0344,'/',0376,0271,0377,0304,0,'-',021,01,0,02,01,02,05,04,02,02,03,01,0,03,0,0,0,01,0,021,'!',' ','1','0','A','Q',0241,0261,020,'@','a','q','P',0221,0201,0361,0301,0321,0360,0341,'`','p',0200,0377,0332,0,010,01,02,01,01,'?',020,0377,0,0362,'e',0204,0247,'Y','N',0262,0235,'e',':',0377,0,0360,036,'Z','@',0271,0276,0241,032,'t',0207,' ',020,0272,0217,0231,033,0261,0177,'s',0346,'~',0347,0314,0375,0317,0231,0373,0237,'3',0367,01,'(','Q','K','/',0367,026,0272,'1','k',0237,0361,023,05,'P',0253,'8','#',0267,0345,0266,0364,030,014,'Y',0367,024,0344,0372,0233,0252,0375,0200,0323,'d',0337,'9','L','Y','1','K','O',0314,026,0325,0376,'D','{','h',0230,0341,'n',0323,014,0320,0370,0213,'m',0276,0335,'[',0242,015,01,'g','S',0361,0334,017,'m',023,0,0337,0314,'Z',0354,0367,0210,0255,'S','9','2',0357,012,0347,'t',0374,'H',013,'f',05,'K',0257,'(',0205,0205,0237,'.','|',0271,0362,0340,026,0257,'x',0212,0325,'3',0232,0244,0267,027,0370,'k','s',0317,'I',0260,0276,'C',0254,0247,'4','C','l',0217,0271,0375,0241,'?',0264,'#',024,'o',0322,'D',022,0230,'J','y',0351,021,032,'}','S',01,'q','P','$',013,'A',017,'L',0324,0274,0317,0207,04,0241,0237,026,'|','X',0276,'k','6',':','}','M',0302,'!',036,0134,032,0362,0372,0213,0323,034,';','U','L',0242,0305,0345,06,0366,0374,022,0202,0330,'I',0312,0365,0203,0226,0356,030,0330,'!',0246,'^','g',0227,0376,0242,'K',07,0313,'?',0270,'g',0367,014,0260,'C',0355,0233,'6',0221,0314,'?','?',020,0303,'X',0305,021,0214,0376,011,0236,0201,0324,'G',030,'Z',027,':',')',0370,0231,0313,0276,0347,' ','8',0134,0375,0202,015,0177,0200,0267,'4','F',0334,'^','^',0204,0263,0310,0214,'u',010,0366,0212,025,0251,'t',0215,'d',0231,'^',0312,0376,'"',013,'o',0264,026,0205,0303,'T','[',0342,021,'L','>','"','&',036,05,0262,0202,0363,']',034,';',0250,0226,0354,'C',0234,'C','v',015,0316,'l',014,033,0342,0334,'i','e','~',0207,0257,'a',';',0337,0215,'}',0377,0,0307,0270,0311,0245,'=','g','"',034,03,017,'I',06,'0','p',04,0332,0316,'c',022,0352,'w',0327,0242,024,0200,0240,0215,'0',0177,021,'t',0372,'E',0366,023,0275,0370,0327,0337,0374,'{',0235,0341,0212,'*','*',0303,035,'u',0212,'6','C',02,0177,0266,0245,'J',0307,'U',0304,'v',0326,0242,'h',0304,'#',034,'7','O',0250,'_','a',';',0337,0215,'}',0377,0,0307,0273,0247,'6','D','.','S',0244,'D','i',0324,'(',0331,014,011,0376,0332,032,0346,'3','W',032,0315,'@',01,0134,'7',0257,0210,0215,0355,0313,'W','a',';',0337,0215,'}',0377,0,0307,0274,0250,'s',0202,'(','M',':',0205,033,' ','5',0303,0321,02,0261,0326,'q',0254,0314,0204,0206,'a',0216,023,0206,0301,033,0240,'j',05,'h',0216,0274,0356,'S',0275,0370,0364,0336,0336,'U',0275,0,0327,0360,0317,0203,0376,'~',0247,0301,0377,0,'?','Q',')',0311,'M',036,0316,'_',0262,':','k',013,',',037,'G','$',0331,'9','|',0210,0316,0377,0,0343,0337,'S','v',0344,'e','"',0324,'+','d',013,'H',0355,0261,0255,025,022,0220,031,0200,'(',0341,0334,0277,034,0365,02,0264,'C',0,0177,0247,0247,'{',0361,0350,0305,')','e',0261,0244,0334,0247,0223,'F',030,'f','0',0344,07,'#','n','u','P','h',0201,032,'R','4',0354,0213,'H',0363,'9',0303,0134,'V',0355,0363,0214,'r','R',0212,'S',0201,'3',03,0230,0257,'q',0376,023,0277,0370,0367,0356,0217,'H',0262,'3',';',0216,0326,0213,'y','u',0241,014,012,034,'>',0276,'"',0333,'n',0243,07,0227,'o',0217,'^',0367,0343,0320,'+',0264,')',0324,0346,0177,'%',0220,0336,'y',0227,0271,0314,'i',023,0251,'e',0374,0225,02,0260,0326,'-',047,0255,'!',0332,012,0326,0305,0330,'-',025,'{','a','j',0330,0272,0344,0312,'o','(',0332,0353,0,'_',0335,0263,0277,0370,0374,03,0243,0212,0271,036,0202,0304,0272,0302,'e',0314,'f','Z',0314,06,'!',0261,0303,'E',0262,'D',':',0203,'U',0343,0224,0333,0327,0275,0370,0365,0263,0267,0222,0224,0364,'K',0241,0363,'U','>','/',0360,0247,0351,0223,'(','`','l',0312,'-','P',0256,0303,0351,0337,0374,'~',05,0266,'0',0332,031,0303,'0','9',0204,'p',016,'c',0275,'p',0200,'b',022,03,0210,0374,0254,0337,'R','r','$',0,0243,'G','{',0361,0350,'S',0213,'*','9',032,024,023,0345,02,'Y',0200,'(',014,0325,']',0252,0,'Y',0327,'}',0243,0311,0377,0,0263,0342,'<',0,'n',0243,0260,'V','=',035,0377,0,0307,0340,0213,'W','1',0302,0306,'J',0343,'Y','9',022,'S','<','K',0221,0273,0264,'D',0255,0335,'"',0271,0220,'@',0355,0247,0275,0370,0364,0257,0216,'S',0260,0200,'/',0300,0357,'2',0255,0371,'d',0241,0203,'K',0204,'U',0233,'o','?',0277,0230,0372,0315,'r','Z','.','c',031,'z','w',0377,0,037,0202,'P',0243,'3','c','Z','*','%','p','s',0,024,'q','0','-',0265,'0',0216,'Z',0273,0337,0217,'B','V',0323,'G','e','C','O',0352,0177,'u',0376,0323,0373,0257,0366,0204,'%',033,0246,0354,05,'g',0321,0337,0374,'~',04,05,0262,0321,0345,0333,06,0337,':',0230,0216,010,016,'%',0232,'n',0355,026,0333,'t',0255,024,'6',0325,0336,0374,'K',0370,0335,0323,'N',011,0234,0363,010,0246,0363,'R','9','M','5',0214,030,0303,0237,'_','>','T',0264,0216,0302,'R',0274,0206,'l','z','w',0377,0,037,0200,0332,022,0207,'1',032,0363,0313,024,0214,'Y','-',0210,0233,'=','X',024,0304,'6','8',0270,013,0215,'$','@',0335,0203,0315,'u',0367,0277,021,'Q',0134,0244,0334,0261,035,0376,024,0210,016,0206,0305,0226,'E','P','l',0253,'7','q',0374,0317,0354,'_',0365,011,0237,0266,033,'.',0222,0376,0351,'}',';',0377,0,0217,0300,':','V',')','[','E',0242,0375,'$',0300,0267,0215,'S',022,0251,'M',04,' ','@',011,0213,0335,014,'N','|','2','s',0221,021,'+','w','O','I',0274,0270,035,0357,0307,0246,0324,'C',015,0351,0232,'|',0320,0305,0340,034,033,07,0375,0277,'k',020,0377,0,0327,0375,'B',0326,'X',027,0260,'w',0223,0252,'~',0375,';',0377,0,0217,'~',',',0243,0206,0307,0241,0264,'B',0265,0302,'@','-','E',0233,0305,'d',0214,0303,'2',0303,031,0254,0264,'N','Y',0341,0322,'N','y',0322,013,0202,021,0274,016,0367,0343,0321,0330,0324,0206,0352,0352,0237,'6',0257,0346,01,0257,' ','T',0252,'/','q','V',036,0216,'9',0317,0371,'o',0361,01,0273,0264,'(',027,'K','V',0233,0320,0376,0275,';',0377,0,0217,'|',0240,'[','*','+',025,'[','a',027,015,0265,012,0347,'E',0251,'%','0',0225,'q',0311,0245,0312,'+',07,036,0213,'$','l',0276,016,0323,0246,0206,'4',0321,0336,0306,'x','=',0357,0307,0246,0366,0362,0255,0350,026,0277,0202,'|',0237,0363,0367,'>','O',0371,0373,0214,'5','"',0300,'P','=','^','c',0323,0277,0370,0367,0310,0201,0314,'g','*',013,')','D','A','l',0270,0344,'%','0',0233,'Z',012,',','J','Y','.',0321,'u',0362,'W',0,'W',0351,025,'r',0351,'+','f','x','.',0367,0343,0321,0206,'7',0210,0332,0354,'R',0376,0256,035,'+',0320,'K','O',0315,033,0206,'t','w',0377,0,036,0365,032,0212,'s',0217,'K','^',0241,0334,0313,0217,0236,'H',0360,0,033,'C','@','B','a',0274,'k',032,'7','_',0276,017,0316,016,0225,023,0316,01,'<',0270,'=',0357,0307,0245,0247,'^',0353,'z',01,0257,0232,'q',031,'a',012,'E','j',0300,0274,'(',032,'1',0267,0247,0225,'-','#',0260,0224,0257,'!',0233,036,0235,0377,0,0307,0271,0277,'R','6',0314,0367,0350,'M',0262,0376,'n','F',0321,0313,'=','0',0305,026,'X',0,0214,0372,02,0344,'t',0375,0263,034,032,'.',0223,'M',022,0230,'8',']',0357,0307,0245,0262,0230,0211,0270,0215,0211,0364,0317,0354,0247,0366,'P','@','K','`',0254,0272,'K',0375,'/',0357,0323,0270,0373,0220,0257,'Q','@',0346,'*','@',0231,'J',0201,07,'<','F',0312,030,0206,0322,'a',0204,0345,'p',05,036,0230,031,0223,'M','W','D',0371,0240,0327,0264,0311,0327,0235,'4',0365,0217,013,0275,0370,0364,'_',')',0270,0351,'m','_',0361,0274,0260,0361,0301,'T',0341,0234,0344,0271,0265,0203,0220,022,0241,0367,013,031,035,0216,'k','l',0254,'f','X',0305,'H',07,'2','C','9','W',0305,0327,0247,0177,0361,0356,0334,'&','9',']',0275,032,':',0365,0341,0227,'|',0276,0350,0244,'X',0206,'#',0327,0347,'R','X','W','-','6',013,0264,0327,0361,'A',',',':',0264,0320,'*',0227,0205,0336,0374,'z','3',0310,'[',0367,0203,0275,'K',0371,0330,'O',0264,0277,0304,0246,'6',0360,'-',01,'E','6','L',0263,0313,'2',0230,024,0373,0325,0372,03,0374,'-',0353,0351,0337,0374,'{',0241,0271,0211,0177,0350,'5',0250,0223,'9','`',0333,'(',0336,0357,'D',0350,'!',' ','4','o','0','u','g','O',0300,'.',0267,0350,'M','6',016,0250,0214,'r','8',']',0357,0307,0243,0355,03,'6',0272,'m','/',0344,0304,'P',0252,'j',0206,0315,0353,'f',0311,'g',0333,'+','6',05,024,027,0232,0203,0207,'z','i','6',0316,0361,0234,027,0242,0341,'N','u',0310,015,0271,0345,'^',0204,0357,0376,'=',0321,0273,'f',':','@',0254,'L','^','Z',0304,0207,'+',0312,0,'f',01,0243,':',0232,0327,'3','K',0364,'z',0325,0203,0236,0223,'K',0254,012,0307,013,0275,0370,0364,0273,0376,030,0257,0344,0354,025,',','B',0364,013,0372,0344,0375,0244,0265,'B','9',017,' ','w',0210,0230,'}',';',0377,0,0217,'r',0201,'1',012,'q',0350,0346,020,036,013,0212,',',0233,0367,'h',0352,0270,02,0215,'E','|',0375,0264,0255,016,'f',0263,02,0335,'t',0220,0236,'Y',0341,0367,0277,036,0230,0321,'6',0252,0232,0375,0253,0370,0251,'n',047,0300,'}',0234,037,0274,07,0324,'#',0325,'f',0337,0305,0227,0364,'_',020,0257,0230,' ','X',0272,0226,0256,0254,'1','|',0217,'N',0377,0,0343,0334,013,',','u','L','z',034,0330,'1',0231,'Q',04,'m','K',0330,0312,':','0','C','c','Y',047,0234,'t',0215,0355,'}',0366,0226,'J','r','8','}',0357,0307,0245,'@',0313,0235,0373,'_',01,'*','%',0344,'5','9',0356,0352,0354,'*','s','%',0330,0236,0255,'_','`','P',0376,'n',02,' ',0233,'(',01,0244,0272,0,0272,0134,0357,0237,'N',0377,0,0343,0210,0203,'y',0271,'1',026,0256,'n',0216,011,0260,'s',035,0224,033,022,0335,' ',0331,0201,'C','6','h',0251,033,0300,'X',0340,'6',016,0272,'{',0315,'}',0366,0236,0307,0207,0336,0374,'z','U',0216,0372,0357,0177,0221,'+',0231,'?',035,0343,'0',0270,06,0333,'2',0365,0311,'}',')',036,024,027,'C',0275,0201,03,0341,'M',0375,0372,'w',0377,0,034,'%',015,0341,'y','c','l',020,0270,'|',0320,0333,'x',0202,0223,'[',0205,'c','#','`',0226,0224,'j','#','6',0216,'S',0264,':',0306,'"',0242,'a',034,0300,0242,0270,035,0236,0236,0363,'_','}',0247,0261,0341,0367,0277,036,0231,'V',0376,'(',0376,0262,0206,' ',0206,0373,'/',0345,0265,0332,'W','#',0302,0216,0304,0251,'*',0203,'n',026,0320,05,012,'9',0267,'z','w',0377,0,034,020,'6',0313,'G',0314,0270,'=',')','i',0203,'e',0351,'#','l',0270,'I','s','.',0205,'N',0203,0313,0335,'F','l',0332,'(','T','S',034,'B',01,0301,0354,0364,0367,0232,0373,0355,'6','}','G',017,0275,0370,0364,0266,'H',0345,0233,0270,0277,0252,0237,'$',0301,037,'.',0216,0377,0,0343,0203,'o',0275,0257,03,024,031,0272,'I','A',0314,01,'[',0261,0313,0320,'#','-',';','"','0',0303,'@','p',0250,0335,'q',0247,0274,0326,0235,025,0323,0331,'<','>',0367,0343,'_',0177,0361,0300,'t','D',0255,0326,'4',0334,0252,'N','t',013,'(',0311,0234,'J',023,026,0370,0231,'1',0,0250,0350,0304,'"',0324,03,'F','x','~','C','K',04,0345,0235,'~','C','K',0257,0263,0207,0336,0374,'k',0357,0376,'8',033,'&','k',0201,0220,0363,0225,011,0350,0251,'l',0271,0277,0324,'M','>',0232,0245,'1',0347,'}',024,'2',016,033,0307,0363,0247,0266,'u',0221,0277,'O',0330,0220,0201,'8',']',0357,0306,0276,0377,0,0343,0203,'a',0300,0261,010,'e',0237,'B','|',0306,':',0256,0242,03,020,0200,0342,030,0216,0306,0220,',',0364,0327,0212,'/',022,0223,016,0237,0243,0270,']',0357,0306,0276,0377,0,0343,0203,'{',05,0223,0201,0230,0361,'2',04,0304,034,'j',047,'"',05,'3',0305,0261,0364,0306,0232,0336,'k','K','*',':','|',0235,';',0323,'#',0302,0336,']','|','E','W',0270,0326,0256,'M',031,'8','"',0247,06,'A','F',0310,05,'.',0273,01,0300,024,'q',011,024,0317,033,0272,'X',0227,0236,'x',026,0210,'a',0323,'t',0371,0360,0220,024,0307,'~',0275,0343,'4',0363,0275,'?','&',07,' ','@',0177,015,'p','E',0225,'1',0276,'|','s','8',0304,04,'8',0266,0343,'w',032,'i','p','@','0',0254,'p','0',0237,0326,0226,0371,0330,0200,047,011,011,0223,'q',0210,'!',0247,0252,0247,0367,0363,0373,0371,'_',0376,025,0225,'}',0361,'p',0357,'!',')',0256,'+',034,01,')',0236,'5',0250,'}',0351,0373,0316,05,'c',0201,'N','7','3',0252,0334,0356,'c',0335,033,0221,0310,0361,'l','k',0200,'(',0342,0255,027,0250,0233,0247,0313,0202,'L',0271,0305,'S',0223,0246,0335,0354,0373,0241,'e','q','@','g',0241,04,0207,032,0334,'n',0343,'U','z',0337,'.',025,'1',0347,0244,'G','"',01,036,'|',024,'D',017,0333,0365,'>',0340,'W',023,0347,'G',0316,0212,0273,0374,015,0314,0234,'<',0307,0177,0327,022,0352,0221,')',0247,0204,0307,03,05,'3',0307,'z',';',032,'P',0216,'l',021,034,0270,'A','P',0311,0223,'U',0207,'+','n',06,0307,0201,'_',0342,'"',0352,0264,'9',06,0226,024,017,0354,0351,'9','+','3',0360,0363,0341,0223,'(',0356,'<','%',0253,0204,'(',0343,033,021,0323,'y',0322,'J',0314,034,'4',05,'2',0251,0333,'K',011,0312,021,0355,':',0331,'Z','p',0375,0353,'`',0360,0201,0303,'K',0227,0340,0340,0221,'9','@',03,0217,'W',0264,'o',0250,'H',0346,0347,0211,0324,03,0306,0253,0273,032,0373,'s',0316,0276,0377,0,0343,0210,016,'1',0335,'k','P',020,01,031,0343,0232,'(',0351,0274,0351,0253,0275,0214,0260,'+',034,'B','e',0316,'#',032,'L',0356,0220,0316,0240,0250,0356,0312,0373,0345,014,0312,'J','M','(',0215,0306,'W','K','3',0256,'z',0361,022,0345,0241,0346,'[',021,0360,0305,034,0245,'0',']',0210,0225,'B',0351,0271,014,0321,0306,'Z',0313,':','|',0325,'R',0273,0271,0343,'P','n',036,'5','=',';',0220,'A','f',0244,0324,'s',0216,'_',0372,0226,'@',0372,',',0237,0330,0247,0366,')',0226,0247,0311,'R',0240,0221,0266,0363,0355,0200,012,'8',0250,024,0305,'-','"',0374,0243,0310,'L',0227,'S',0225,0315,0230,0200,033,'q',0362,'.',']',0265,'U',0336,0306,'X',025,0216,'0',012,'b',0257,'#',0266,0252,'7',0347,0226,0272,031,'G','I','G','I','A',0370,'D',0355,0365,023,0256,']',' ',0252,' ',010,0356,0357,0354,011,0303,'f',0321,022,0267,'4',0230,'L',0220,'h',0330,0374,'c','=',0242,'[',035,0215,0215,'X',0217,06,0336,0312,0345,'?','z',0202,0246,'a',0263,0277,'?',0305,' ','[',035,0246,035,0365,011,033,'s',0204,0366,0217,'d',0240,0260,0313,013,'g','m','b',0315,'?',0342,024,026,0307,'k',0377,0,0266,0244,'@',0335,0201,0327,'=',0243,0267,0277,'(',0224,'2','k',027,'d','y',0351,0370,'d',013,'A',033,0224,0362,0326,0370,0377,0,'^',0330,'9','B','8',014,0232,0202,0245,'0','=',0217,0302,036,0276,010,0247,'&',0262,'3','a',0267,0314,012,0301,0355,0304,'?',0372,0242,'#','N',0244,'V',0251,0227,'W',0354,0200,',',0374,013,0342,0357,0242,0134,'O',0343,'_','%','N',0360,'*','m',0356,'L','!',0376,0321,021,0247,'Z','u','w',0321,'-',0317,'=','=',0363,05,0242,'-',0277,'t','E','j',0335,'{','h',035,0340,02,0240,0367,'a',0377,0,'c',034,035,'&',0267,'-',0246,047,'5',0363,'2',0241,0356,0224,026,0313,0214,0210,0215,0377,0,07,01,0263,027,0224,04,'t',036,0364,0252,'b',022,0206,'x',027,02,0230,0206,017,0346,01,'v','{','a','m','T','>',0262,'F',0262,0243,0247,05,0301,0267,0322,0,'(',0367,0351,0307,0371,0211,0254,0276,0256,013,0226,0323,025,014,'S',036,0255,0363,012,0265,'~',0301,'C','y',0327,0311,0204,0253,0345,0234,0300,0340,0327,'+','g',';','|','?',04,'-',026,'M',0337,0321,034,05,'<','$','m',010,'=','A',010,'Q',07,0266,0237,'r',0226,0214,0312,'u',0324,0241,0274,0331,'B','9','F',015,0212,0262,0330,0242,'o',0237,015,0353,'b','+',0207,0341,'M',0303,'=','f','Y',',',0353,0305,'0',0331,022,0261,'~',0347,0314,0203,'Q','o',0271,0360,0277,'S',0341,'~',0242,0334,0323,'z',0331,0270,'/',0213,'T','.','V',0347,'`',02,0217,0303,0240,')',0226,'9',021,0254,',',0353,0357,0252,05,0261,034,0237,0304,0245,025,0370,0264,05,'2',0307,'"','g','R',0317,0210,0224,0323,0356,'U',0253,'&',0177,0322,'&',024,'?',037,0274,032,0244,0306,0177,'g',0240,0311,'M','>',0315,'z','f','g',0225,'"',06,'G',0314,026,0205,'~','Q',07,'y',0266,'s','|',010,05,0261,0216,0323,'y',0271,034,'$',0330,0270,'e',0254,'T',0262,0210,'[',0376,0271,0327,'O',0314,026,0205,'~','p','J','H','}',0214,0370,'q',0233,012,0237,'g',0356,'}',0237,0271,0366,'~',0347,0331,0373,0201,0225,')',0330,0304,'l',010,01,0267,0377,0,0134,0377,0,0377,0304,0,'+',020,01,0,02,01,02,04,06,03,0,03,01,01,0,0,0,0,01,0,021,'!','1','A',' ','0','Q','a',020,'q',0201,0221,0241,0360,'@',0261,0361,'P',0301,0321,0341,'`',0377,0332,0,010,01,01,0,01,'?',020,0377,0,0341,'B',0270,']','?',0370,0267,'O',0376,'-',0323,0377,0,0213,'t',0377,0,01,'q',0340,0206,0310,031,0374,0134,0376,'.',0177,027,'?',0213,0200,010,0210,0350,0217,0341,0326,'o',0360,0235,'?',')','C',0134,'B',0246,0332,0253,0265,'k',031,'%',',','[',017,0322,011,010,0302,'P',0265,036,'/','k',024,0275,0314,0355,')',0255,0225,0273,'6',0360,'$','k',0244,'q','1',0332,0177,'s','?',0271,0237,0334,0312,0377,0,0353,0225,0263,0253,0265,0242,032,'S',0252,0201,0334,0212,0221,0327,'D','z',0304,'L','F',016,0341,0251,0354,0240,'j',0322,016,'.',0220,'"',0275,01,0200,'Y',0275,'U',0376,'{',0247,0343,0324,0227,'Q','Q',06,014,0244,06,0306,0247,'h','_',0351,'Y','R',0263,023,0247,0220,'6',0333,'A','b',0362,022,'.',0241,'u',0301,0370,026,'M',0324,0224,0352,0304,'B',0302,0367,0247,'c',')',0224,0215,0254,0256,0330,0377,0,0311,'P',0217,0257,'n',0207,0366,'g',0344,'C',0207,0333,0363,035,'?',024,'1','-',0247,'&','-',0335,035,015,'5','}','a',0213,'U',022,0263,'`',0270,0274,0301,'M','V',0353,0257,0343,'9','d','X',032,'F','=',0246,';','n',']',0326,'`',012,'m',0330,0273,0325,'<',0273,'@',0223,014,'0','Y','p','l',0263,0362,']','?',014,'1','-',0247,'&',0240,'b',0374,'6','M','|',0317,0374,0213,'4',0232,'@',031,0305,'o',0257,0376,'~','b',0235,0233,026,0275,'z',0372,0305,0352,0216,0310,0316,0247,0267,'X',034,'s','%',013,0322,0240,0331,'g',0343,0272,'~',011,'2',0325,':',0,0207,',',0323,0346,0321,0322,' ',0302,'i',0,'g',025,0276,0277,0371,'?',0276,0237,0337,'O',0357,0241,030,';','E','D','J','y','J',0316,032,'R',07,0322,'}',0223,0375,'O',0262,0177,0256,'z',0235,0233,026,0275,'z',0372,0300,0201,'t','6','s',0327,'w',0363,'h',03,030,0260,0256,0305,0323,0370,0316,0237,0200,'f',0273,030,0273,0241,015,0266,'j',0207,0322,0321,0247,0326,'!','b',0212,02,0243,'4',0236,0264,0314,0376,0377,0,0376,'O',0357,0377,0,0344,0330,0216,'Z',0204,'h',04,0302,'&',0262,0353,'M',0214,0364,'v','c',0257,'J',05,'#',0342,0265,'x','d',0342,0256,0265,0322,'P',020,'5',0240,'*',0363,'0',0,0320,0254,0356,0274,0313,'j',0240,0360,0246,0260,014,0303,'7',0225,'u','<','4',0251,'s',0,0313,0326,'}','c',0375,'D','J',0244,0247,0370,'F',0267,'e','=','P','7',')',0247,'#','}','`','K','7',0275,0220,0222,'4','k',0326,0250,0300,0216,034,0341,0326,0263,011,'F','E',0320,037,'(',0345,0221,'J',')',036,'R',0226,'I',03,0346,0301,0362,0250,0250,0320,'_',0303,0336,036,'+',0344,'K',037,0304,'t',0347,02,0321,0263,0240,';',0262,0246,'@',026,036,0244,'N','`','4',0267,0255,03,'h','v','D',0320,0,0213,'C','X','Z',0363,0275,0240,0303,0342,0200,'I','G','B','Q',0320,0235,0254,' ','$',026,'a','f',036,0325,'l',0304,0270,0265,033,'3',016,0234,0307,0331,0251,0365,0226,'K',0225,0362,'[',0323,0333,0264,'P',0230,0272,0271,025,'U',')',0270,0342,'W',']','.',01,0,01,0240,'s','t','T',0271,0207,0316,017,0333,010,0301,0205,0333,'r',0266,0364,0277,'.',0361,0200,0322,034,0324,0353,0363,034,0262,')','E','#',0310,'y',0237,'f','G','Q','4',0200,033,0344,0267,'n',0353,015,0245,0230,0233,':',0234,0264,'j','j','|',0373,'3',0370,0351,0374,'T',0376,'*',0177,025,'?',0212,0207,'T','6',' ','$',0253,036,'i',0312,0205,'D',']',027,0210,0215,'l',0351,0336,0264,0307,',',0253,'R',0325,0353,'-',0310,'1','t',0267,'?',0250,0340,0227,'x',035,'/','0','.',06,0,'h',034,'N',0253,0206,032,'l','a',',',0360,01,'D',032,';','~','&',0272,'h','8','}',0342,023,'b',035,0255,0374,0204,0350,'h',024,014,0373,0355,0322,' ','^',0245,'C',0321,0344,021,'n',0213,024,0273,033,'2',0252,020,04,032,0346,0216,'C',04,0,0353,013,04,'l','c','X',';','B','h',0307,0243,'R',0315,014,0352,0263,0352,023,0210,0304,0251,0203,'Y',0260,'0',0274,0303,025,04,036,'f',026,'A','n','^',0304,'J',0230,015,'i',0352,'<','~',0357,0253,'>','?',0221,0347,0312,'~',0237,0214,014,01,035,'F',06,0274,'r','K','9',0263,0316,'4',0246,0326,0213,'1',0365,0333,0376,0304,013,024,0264,0256,0347,030,0363,'y','X',')',0263,016,'`',0327,011,'M',0307,'{',0203,'e',0232,'p',0227,'R','Z',0263,',',')',0204,'1','V',047,'9','e',0310,027,'h',0272,':','"',0266,0207,0223,'5',0324,0365,0216,0273,0334,0201,'i',0356,'F',0313,'W',0245,0313,'<',0276,0362,0307,0360,'U',0362,0354,0277,'Y',0273,0,'#',0326,0260,'o','d',0247,'^',017,0273,0352,0317,0217,0344,'y',0362,0237,0247,0344,';','2',024,0216,0214,'F',0325,'U',0303,0272,0274,0240,0363,',',0311,'M','s',0377,0,0177,0134,'g','B',0315,'R','$','1',0372,'N',0203,0324,0357,06,0313,'4',0361,'"',0200,0273,'e',012,'M',0200,0313,0324,'}',0346,'|','t','F','3','i','^',0374,'B','$',0333,'1',0276,0252,0203,'S',023,025,'_','*',0313,0365,0233,0260,02,'=','k',06,0366,'J','u',0341,0373,0276,0254,0370,0376,'G',0237,')',0372,'~','P',0202,0304,'L',0325,0233,'E','Z',0334,033,'N',0275,0221,0267,035,0270,037,047,0210,0350,'Y',0252,'D',0206,'?','I',0320,'z',0235,0340,0331,'f',0221,0232,'P','L',0210,0370,'K','H',012,'r',';',0304,'@',0333,0247,033,0212,'U',0332,02,033,0325,0264,0303,032,0310,'H',06,012,016,'J','f',0272,']','=',0204,0134,'^',0220,0301,0325,0134,'_','w',0325,0237,037,0310,0363,0345,'?','O',0312,027,0,0240,'#',0250,0302,0245,'{',0200,0246,0311,0336,'2',0362,0205,0224,0265,'c',0277,021,0320,0263,'T',0211,07,'q',06,0256,0233,0235,'a',0302,'J',0260,0351,037,'Q',0267,',','J','I','x',0343,020,'V',0260,0363,0213,'A','%',02,'V',0301,'5',0207,030,025,'D','t',0344,'6',0222,0263,'@',022,0352,'Q',' ',0252,0355,'k',0247,021,0320,0261,'V',0253,037,'z',033,'e','k','>','?',0302,0225,0233,',','2',0267,'(',0262,0177,'O','?',0323,0310,0223,'a','}',0352,'2',0216,0364,0371,'3',031,0302,0207,0301,0242,0205,0342,'4',026,'j',010,0204,0363,0345,'?','O',0315,'n',0362,'L','6',031,0226,0355,'u',0206,0317,0317,'g',0205,0,013,']',0243,0261,'p','*','Y',0322,'i',014,'n',0314,0272,0253,0203,0215,020,031,'b','u',034,0134,'D',03,026,0254,'@','r',0201,'i',0340,0351,0306,014,0232,02,0326,'0',013,'$',0367,0356,0342,':',026,'*',0325,'a',0217,0320,'v',036,0207,'x','h','O',0270,0317,0217,0360,0247,'5',010,'2',0207,0305,0202,0307,011,0210,016,'u','^','^','J','(',0227,0254,'a',010,012,0266,0242,0270,'B',0354,015,0211,06,'G',0305,0331,'h',011,'h',0225,0206,04,'F',0240,013,'D',03,'X',033,0357,0376,0357,017,'>','S',0364,0374,0353,'/',0326,'.',0301,030,0365,0254,0231,0331,013,0327,0201,'<',0326,0265,0255,'e','p',014,0231,0205,035,0230,0267,0307,0204,'Q',0336,0134,'7',' ',0321,013,'k','@',0255,'g',0305,0323,0217,'<',0304,'j',0325,'j',0305,'N','D','2',0246,0336,023,0214,0201,0355,'N',0304,'&',0247,0351,0257,'@','`','Q','F',0223,0352,'z','3',0343,0374,'(',02,0275,'n',0363,'O','z',027,0244,0260,0360,06,035,0302,'l',0233,024,'j',0335,033,'"',020,0363,0304,0352,0252,0311,0204,0274,0230,'c',047,'(',0220,010,'5',0341,'4','[',0226,0211,017,0350,0361,'r','d','Z',0326,'o','3',0303,0317,0224,0375,'9',015,' ',0337,0343,'Y','~',0261,'v',010,0304,0274,'M',0200,'x','-',0305,0276,'D','K',0250,'d',0313,'.','6',0215,'F','e','m','x',0317,'K','<',0263,'0',0324,030,'!','"','H','r','i',0,012,'4',0361,'t',0342,016,'*','2','<',0345,0242,0300,027,015,'w',0341,'@',05,'V',0200,0336,'Q',0315,030,025,'u',020,033,02,0200,0320,0360,0372,0236,0214,0370,0377,0,032,0235,'8','p','i',01,0204,0244,0273,'+','3','f',0262,030,0357,0241,'`','D','3','8',0236,0204,0341,0325,0336,'{','x',0371,0362,0237,0247,'!','.',05,'~','=',0341,0,020,' ',0301,'q',0272,021,024,'Y','z',0220,0325,0341,'j',0223,'4',011,'X',0215,0215,0253,'|','l','9',0266,05,'g',0332,0213,0216,0214,0204,0200,0235,02,0200,0340,'t',0341,'Z','-',0215,025,0236,0205,'_',0177,025,'B','U',0321,0177,0302,0,0,017,'@',036,'?','S',0321,0237,037,0340,0263,'w','9','Q',0231,033,'a',0222,0240,0371,0276,0220,'@',0244,'M',034,031,'Z','D',012,';',0201,'H',0270,0257,'a',0307,'T',0224,010,0256,0347,0217,0237,')',0372,'~',020,'U',0321,0277,'9',0253,0,'f',0345,0337,'k',' ','=',0342,0320,024,0240,'"',0252,'m',0343,020,0355,'Y','j','w',0234,0306,0310,'8',0344,0303,05,' ','+',034,'.',0234,'4',0333,'M','%',0256,014,'O','2',012,0243,0267,0246,0234,'4',0220,0365,0204,0356,0327,'_',0373,035,023,05,024,031,'x','>',0247,0243,'>','?',0300,0355,0236,0343,'{',0222,026,010,'Z','f',0262,'J',0321,0222,'Q',0257,0,0273,0265,0,0241,034,'J',0252,0236,0215,0205,0302,0346,'I',0245,'P',0347,0307,0317,0224,0375,'8','o',0233,'K',0272,0347,012,0212,0350,06,'Q','o','E',0313,'2','[','G',07,032,' ',013,'X',0230,0134,0310,'1',0250,'U','-','P','O',0201,0226,0270,0225,07,0223,0367,0300,014,0232,02,0326,'1','^',0264,'~',' ',0355,0377,0,'8','@',0322,0265,0344,0350,'G','T',030,0233,0245,0220,0341,0372,0236,0214,0370,0377,0,0,0322,037,015,0324,030,0260,'I','}','<','Y','2',']','y','R',0274,'(','7','`',0365,'|','|',0371,'O',0323,0206,0263,0177,0224,'~',0312,0264,0134,'|',0324,'Z',026,011,0314,'4',0324,034,014,'W','r',0336,'}','X',0210,0323,0207,0205,0361,'Q',0270,0207,0322,0206,010,'%','(',0265,'L',0361,0233,'<',0307,0357,0200,026,0245,'v',0224,0301,'Q',015,'8',0255,0332,'m',0341,'T','Z',0225,'h',0267,'6',0323,0336,033,'`','(',015,016,037,0251,0350,0317,0217,0207,0216,013,'}',024,010,0272,014,0353,'Q',0336,035,'>',0265,047,']','u','%',0230,0306,0276,'!',0303,0244,0337,0204,0210,012,'-',0212,0265,0254,0370,0371,0362,0237,0247,'&',0325,0355,0370,0246,0300,027,0230,0247,0207,'C','0',0363,0203,015,'@','V',0262,0334,0273,'*',025,'q',0331,'B','o',024,05,0232,0321,030,'1',035,'|','L','i',0266,'a',0226,'*','=','`','l','J',0304,'@',0,024,034,'b',0353,0305,'h',0266,023,033,'g','j',0335,'v',0353,0361,0302,0302,0310,'a','y',']','}',013,'}',' ',0212,'`','n',0263,'7',0305,0365,'=',031,0361,0363,'*','9',0264,0315,0232,'G',016,0327,'h',0216,0201,'h',0313,'D',0255,0240,0350,'@',0204,0327,'F',0303,0335,0237,'a',0377,0,'p',0237,'}',0222,020,0251,0334,0374,0303,0307,0317,0224,0375,'8','/',0362,0134,0232,05,0333,'1',030,0341,014,'T','p',':',0304,0134,0333,020,0315,'V',0240,0264,'Y','w',011,036,06,0256,016,'B',0306,'H','c',06,']',0223,'!',0335,0252,02,0252,0254,'$',0327,'/','0','%',0236,0320,'{','G',0373,')',0321,'u',0236,'C',0247,0213,0205,0273,'B',0322,0230,0304,0326,'p',0364,0345,0307,0261,'G',017,'K','Q','1',0272,0353,0366,0273,0300,0242,0216,'/',0251,0350,0317,0217,0360,' ','L','y',030,'Q','e',0231,0305,0344,0211,0217,0227,'$',0324,0325,0226,0270,'0','4','*',014,'J','^',0240,'g',015,0331,'j',04,0322,0312,0277,'W',0217,0237,')',0372,'E',0250,0274,0315,'9',0313,'E',0303,'M',']','P',0314,0362,0273,'r',0312,'G',03,0203,0300,0320,0320,'I','~',0254,0302,036,'(','s','D',0244,0203,0263,'6','g','T','H',0352,'!',0347,'w','%',0300,'P',030,021,0232,0241,0302,0345,'`','f',0202,0207,0260,0373,036,0236,05,0224,0342,'t',0361,0255,030,020,0354,'W',0321,'=','x','M','j',0335,0313,'Z',0322,'$','Q','l','R','F','o',0217,0352,'z','3',0343,0374,07,0214,0316,011,0330,'p',014,';',0203,0212,01,'9',015,'P','j','L',05,'4','|',01,'>',0317,0223,'Z',032,'(',05,'}','G','_',037,'>','C',0364,0341,014,0237,0216,'Q',0313,0250,0213,'g','6',0205,0215,0215,'X','j','*',0266,0301,'m','{',0312,0333,'y','!',0324,'g','D',020,0,0365,0217,':',0206,0204,'r',0362,'^','&','4',0327,'x',0341,0250,'H',0312,0352,'i',0327,0300,'R','(','(',0321,0322,0376,'}',0343,05,'b',036,0260,'_',0234,033,'8',']','<',05,0225,05,0260,0362,'T',06,0232,0327,'_','#','N',035,0345,0273,'J','6',0341,0373,0230,04,012,02,0203,0217,0352,'z','3',0343,0374,01,'d','-',0250,0312,0330,0242,0331,0375,0354,0377,0,'{',')',036,013,03,013,')',0215,'_',0227,0217,0237,')',0372,'x',0327,0344,022,' ',']',0261,02,'[','X','f','R',022,0242,0227,'j',0334,']','x',0265,06,0260,0245,0253,07,0134,'a','r',0212,013,0325,0301,0373,0202,0256,'_',0214,0351,'s','#',022,0345,0201,021,'C','3','l',010,0323,021,0225,0265,0317,0202,037,'M','=',0306,0317,0324,0307,'`','Q',0300,'4',0314,0310,'0','(',0341,'t',0360,'1',025,035,02,0224,'$','C','p',0322,0325,0253,0236,020,0222,0273,'T',0256,0314,0236,0336,0234,0217,0251,0350,0317,0217,0360,0253,'h',0251,0357,'h','#','W','S',0206,'#','A','0',07,0253,'`',02,0226,0263,0246,016,037,'>','S',0364,0374,0240,012,0350,'B',0330,0302,0214,0271,'K',0267,'1',0134,'%',0343,0300,0255,0224,021,'j',0272,'A','G','G',0314,024,0221,'.',0322,0225,'K',025,014,0225,0266,'o','Y',033,'N',0231,0326,'9','k','8',0362,0340,0275,0213,0257,'#',0247,0277,0304,0323,0211,0323,0302,0331,'F',0304,0323,'{','7','3',0302,'h',0223,0267,'K','q',0345,')','4',':',0202,0206,0265,0310,0372,0236,0214,0370,0377,0,05,0230,0322,020,0224,010,0264,',',023,033,0220,0256,'O',0225,0355,'@',03,'u',0270,0326,'|',03,0244,0337,0204,0210,012,'-',0212,0265,0254,0370,';','9','>','S',0364,0374,'u','K',0206,'q',0340,')','D',0250,0227,0244,025,'K','f','B',07,0200,0366,'W','X','S','l','W',014,0350,012,'F',012,02,016,0230,'&',0204,'_','V',0246,0202,016,'A',0351,'d',0310,'k',013,'j',033,0306,0221,01,'7','~',0353,0303,'k',0266,0336,0220,0354,0275,'u','`',0331,'|','N',0236,02,'+',0255,0240,0235,'1',0352,0360,0322,'&','x',0245,0332,'!',0355,0311,0372,0236,0214,0370,0377,0,02,'0',' ','[','a',0267,024,0217,0234,0376,'7',0376,0317,0343,0177,0354,0276,0226,01,0324,'7',0242,0277,'G',0202,012,0301,0362,0237,0247,0343,0245,022,'2','7',05,0240,'.',0330,0251,',','L','0',0362,0263,'Z','b','*','Z',0314,0357,'*',0240,'`',014,0213,'(',0210,'4',0306,'6',0222,0361,'.','A','Z',',',0311,0346,0366,0230,011,'r',0134,'i','M',0240,0321,'*',0326,0301,'m','J','<',011,0324,0251,0255,'|','p',0240,'C','8',011,'t',0347,0326,'w','j','%',0325,0207,023,0244,024,'T',012,0260,0356,'(',0211,0240,'l','_',015,0314,0323,'O',020,0331,'}',0271,'?','S',0321,0237,037,0340,0267,0317,'%','-',0301,0356,0200,0365,0217,0347,012,0366,0203,'v','B',07,'%',0253,'W','1',0242,0343,'*','t','b',0340,0201,'o',024,0336,0221,0324,'J','~','9',015,0253,'D','n',0272,'/',0300,'N','|',0247,0351,0371,010,012,0350,'C',0332,'A',0246,'X',0276,0310,0276,0255,0270,0360,0356,'V',031,0275,'#','h',0322,0250,032,0260,04,'0',0305,0304,'`','^',0365,0,0354,0227,',','+',0275,0321,'A',012,'b','6','Y',0244,0,06,0204,0257,'X',0341,0273,'V',026,'9','/',0261,01,'U','z','p','9','d','X',032,'F',015,0261,0330,']','6',0317,023,0244,027,0252,0311,'j',0351,'C',032,0221,'[','u',0227,03,0226,'E',0,0265,'`',0333,035,0205,0333,'|',0362,'~',0247,0243,'>','?',0300,03,'v',0362,037,0341,0205,0266,0300,014,0257,0236,0303,'s',0326,014,'K',0212,0212,'J',0311,0211,'y',022,'d',0233,04,0250,015,015,0224,0337,'P','t',0361,0363,0345,'?','N','[',07,0230,0,0355,'T',0277,0330,0252,'[','1',0364,'>',027,'0',0245,0302,0232,0261,010,' ',012,0200,0305,0267,',','m',0310,'Q',0357,035,0325,016,021,0346,0226,'&','k','U',0204,0203,0360,025,'G',0200,0202,0260,'D',0207,'Q','D',015,07,'r',0370,'@',026,0231,'f',0313,0371,0304,0351,01,0251,0341,'K',0327,014,'I',0254,0223,0252,0345,0340,'$',0210,'t',014,'!','6','L','h','P','r','~',0247,0243,'>','?',0302,0262,0306,0274,0341,0222,'.',0310,0325,0227,'P',0202,0202,024,021,'A','A',024,0212,0366,'"',020,'&',0263,'o',01,0227,'Y',06,0257,027,'E',0220,0364,0277,0324,'5',0312,0262,'1',0200,0272,'W',0303,0317,0224,0375,'9','n',0220,0327,0226,0267,0320,']',0263,'8',01,032,'e',0306,'k',0206,0230,0350,0265,'a','o','j',0304,0262,'W','+',032,0264,033,0264,024,0273,0224,'F',0313,03,027,'/',0322,'6',0200,0205,0231,031,',',0206,'W','a','j',0304,'-','4',014,034,025,'2',0261,0321,'_',0307,0205,0342,022,05,'N',0215,0370,0235,'!',0346,'H',0250,'9','p',0247,'u','y',0351,0263,'H',03,0350,01,0311,0372,0236,0214,0370,0377,0,05,0304,'e','H',';',0354,'7',0337,'S',0256,0221,'z',0134,026,0272,015,'~','D','3',0277,0305,0306,'5',02,'_','A',0353,0,0220,'B',0304,'l','|','|',0371,'O',0323,0361,0317,05,025,'C','2','!','{',0254,'Y',0356,0337,012,0261,'F',0221,037,0241,'t','G',0234,0220,0251,0244,0222,'o',034,01,'o','H',0200,'j',0336,'e',0217,0325,014,021,0205,'4',012,0246,'x','Y',0266,0360,017,0323,'^',021,0264,0255,023,')','{',0361,':','B',0244,'J',0265,0267,0327,0204,027,'[','F',0217,'7',0267,036,0257,0217,0324,0364,'g',0307,0370,030,0215,'R',022,0273,'U',0215,'N',0204,0270,0211,036,0,013,0206,'^',0321,'j',0363,0217,'<','R',0205,0323,026,05,0275,0256,'5',0205,'8',0211,0200,0315,'h',0,0260,0272,']','_',037,'>','S',0364,0345,'(','-','j',':',0243,'u','b',0304,023,0274,';',0203,03,'T',',',024,0261,0321,0343,'*','V','*',0345,0262,035,0325,'0',0354,0265,0340,',',0340,0335,0205,0344,0255,0242,'"',0275,0267,011,0350,07,'H',0235,'p','(',0206,'r','.',0251,0235,'~',0214,'A',0335,0240,04,02,030,016,032,0204,0224,0254,'[',0327,0333,0204,0247,022,'Q',0362,'>','x',0235,047,0312,0177,0256,024,'+',0320,'L',0215,0326,'x',0234,'M','^','?','S',0321,0237,037,0341,0217,'N',0305,036,0201,0224,0363,'~',0322,0254,0236,0275,'v',0331,'G',0350,'@','q','K',037,036,024,0336,032,0321,0207,0251,'j',0351,0254,'u',0254,'U',0304,';',01,'T',0242,0306,'1',0343,0347,0312,'~',0234,0215,'%','8',03,'E',0212,'e',023,024,0203,0224,'v',0207,0327,0317,'"',0241,'O','x',0231,0213,0265,0214,0211,0300,'[',035,0373,05,0360,0233,',',04,0323,0324,0330,0315,'E',0332,0323,035,023,'k',02,'{','U','@',032,0351,'s','g',0210,0215,0342,0363,010,'8',0326,'X',0325,0332,0242,'f',014,0355,031,025,0366,'Y',0,020,'+',034,'@','k',0211,'6',0203,'W',0207,0353,'y','C','N',027,'I',0362,0237,0353,0207,0354,';','q','*','!',0361,0372,0236,0214,0370,0377,0,013,'r',031,'Q',0354,0134,0377,0,' ','K',0344,0303,0246,'l','b',0355,'P',0216,0335,'*','U',',',0313,'h',033,'o',0250,0307,05,0350,0234,'/',05,'l',0321,'4',012,0337,0307,0317,0224,0375,'8',0315,0222,0202,032,0272,0350,06,012,0202,'w','b',030,07,0315,0213,'C','j',0245,0231,017,'9',0336,'b',0305,')',0322,0345,0177,'W',035,'c','6',010,'<','-',0302,'%','D',0261,0323,0251,'l','I','V',0260,'A',0315,'h','Z','C','@',0203,'P','9',0270,0322,027,'U',0325,017,0237,0272,0240,'V',0232,0306,0306,032,0227,035,0375,022,0320,0332,034,0360,026,0234,0177,'9',0303,0365,0274,0241,0247,013,0244,0371,'O',0365,0303,0366,035,0270,0306,0236,'?','S',0321,0237,037,0341,'t',0340,'E',0,0354,0226,017,'W',036,'T','2','^',016,'-',015,'l',0214,0276,0220,034,'j',0272,0332,'K',0254,0200,'p',0363,'C','E',032,0240,':',0327,0333,0307,0317,0224,0375,'8',0316,0355,'4','S',023,0372,'s',0224,0362,0234,0262,',','j','z',0360,0261,0262,' ',035,0344,'A',0262,0374,010,0373,0320,'[','q','r',0336,0350,0304,0250,0226,0250,0204,'Y',0232,0227,'5',0333,0206,0210,0321,'4',0364,'G',0345,0202,0311,04,0224,0220,0356,'L','@',0372,013,'E','[',0325,'F',010,014,'+',0273,'I',0247,037,0316,'p',0375,'o','(','i',0302,0351,'>','s',0375,'p',0202,0315,0324,0351,';','z','q','j',0206,0236,'?','S',0321,0237,037,0340,0235,02,')',0313,0245,'n','v',021,'n','$',0335,06,0325,011,'j',0356,0360,0371,0362,0237,0247,027,'~',0206,0134,012,0250,021,07,'3','z',0210,0222,0327,0211,0304,0331,0216,'n',0264,'2',0217,'-',01,0277,022,0204,05,'a',0210,0347,025,0266,0343,012,'X','m',0270,'u',0224,0224,'!',026,0251,'`',0301,0242,024,0240,0214,'h',0273,'e',0207,'R','Q','l','<',015,0324,04,0324,010,0370,0211,0220,' ',0205,'@',0243,0220,017,'<','x','R',0227,'~',037,0255,0345,015,'8',']','!','"',0266,0251,'n',0234,'"',0354,027,0250,0371,0361,0356,0361,0372,0236,0214,0370,0376,'G',0237,')',0372,'q','8',0332,0256,023,':',0332,0313,'U',0242,0361,0215,'7',021,0134,0311,'y',0360,0254,0276,01,010,'#',0230,0366,0252,'!',0270,0326,022,0361,010,'6','7','!','B',0350,'1',05,'+',';',0220,0203,0275,010,05,0224,0353,01,0335,'k',015,'J',0254,0207,'%',0300,0325,'^','[','X',0206,0240,01,0203,0222,047,' ',0264,027,0257,011,0276,0313,0277,'C','c',0347,0211,0322,016,030,'q',020,0264,032,0263,030,0206,'C',0207,'|',036,'/',0251,0350,0317,0217,0344,'y',0362,0237,0247,025,0337,0271,'4','A','d','p','U','[',0310,'|',0232,024,0322,0315,'c',0230,047,'W','k',0270,0303,'W',0254,'2',0341,'a',0314,0327,0300,'s',021,0322,'=',0237,'k','@',0344,'Y','K',0240,0312,010,0324,0234,0254,0305,0216,0252,030,'%',0246,'D',025,0256,'R','.',06,05,0327,'M','N',037,0251,0347,0304,0351,04,0316,0341,'u','=','x','X','#',0340,0274,026,0266,0363,0235,0335,'d',0302,'q',07,0213,0352,'z','3',0343,0371,036,'|',0247,0351,0304,0226,'M',0377,0,034,0265,',',01,'W',0310,'P','p',0214,0305,'e','J',0326,0225,'i','o',0316,'m',0270,0245,'Z',0274,02,0253,032,0224,'!',0364,'Y','P','V',0372,'K',0226,0252,'4',0207,0274,'U',020,010,'0',034,0247,024,0346,'e','t','=','7',0341,020,'8','7',0260,'}','^',047,'H','k',020,0226,0326,0265,'b','!','%','6','V',013,025,0301,0334,0266,'U','t',0335,'F','Z','L','m',0325,025,0302,0351,07,0217,0324,0364,'g',0307,0362,'<',0371,'O',0323,0214,0311,0261,0331,031,0325,0251,'p','R',0235,'9',010,'L',0215,'e',0134,0254,0353,026,0206,'X','8',0214,025,0254,034,0311,0316,'f','d','M',0344,0326,033,'`','V','9','`','c',0246,0326,0326,0353,0361,0303,0200,0325,'P',0244,0357,0276,0207,023,0244,'a',0365,'@',0366,0205,06,'m','Z','x','R','.','/','T',0354,'g',0210,'+',0307,0352,'z','2',0330,0263,'U',0337,034,'v',0315,0373,0246,0347,0310,'~',0234,'d','E',027,023,'z',025,';','l',0274,0201,0246,0310,035,')','8',0214,0370,'l','+',0361,'X',032,' ',0323,'*',0266,0271,'}',0216,0252,0240,'k',020,0266,0225,0271,06,0215,'|',0270,'Y','$',035,0250,';','q',':','x',017,'z','6','4','5',0375,0277,'N',025,0207,0255,0205,016,0366,0372,'>',0374,0234,'q',0366,013,'W','*','!',0325,0257,0331,'!',0306,'&',0203,0310,0341,02,06,0356,'>',0204,0244,0362,0360,033,033,036,0321,'E','Q','T',0327,'Q','=','x',0315,015,022,'-','S',012,010,0241,'s',0331,0302,'^','`','X','t',030,'&',015,'M',0226,'i',02,0212,'9','v',0341,0212,03,0221,022,'k','$',0352,0271,'x',012,'j',0353,'n',0300,0254,'F','`',015,'{',0253,'?','<','N',0236,030,0277,04,0333,':',0373,0374,'p',0211,03,0310,0245,'M',0375,0177,'p','W',026,0305,0210,0234,0204,020,'K',023,'$',0334,0330,0200,'N',0365,0322,'>',0231,0261,')',030,'B',0224,'U',0320,0373,0223,0373,037,0365,'?',0261,0377,0,'S',';','3','H',0376,0323,013,0366,0213,'`',0362,'"',0220,01,'s',01,0320,0352,0300,0330,0262,'+',0327,0220,'/',0210,'Z',0204,0275,0214,014,'J','y',0242,025,0253,017,'y','l',0314,0253,033,',',0201,'0',012,0307,'3',026,'X',013,0303,'g',0331,0357,0302,0200,04,'a',0240,0335,0373,0264,01,0264,0,0342,'t',0360,0247,014,'@',014,0210,023,'Y',07,'D',0303,0301,'D','B',0350,023,'$','#',0246,0244,015,0207,'C',0220,'A',0210,'j','B',0306,'Z','R',0326,0266,0236,0277,0370,0205,'w','|',021,'N',0344,0376,'T',0177,'*','?',0227,017,0300,')','l',']','E',0326,034,'4',0241,'W','%',0336,']',0251,'p',0344,0324,'F','d',0252,'y',0270,'R','s',0231,0217,'A','-',010,'`','P','.',0216,'c',05,'J','^',0220,';','G',' ','P','y','z','{','p',0214,'=','l',')','w',0263,0325,0366,0343,'t',0360,'8',0217,0206,0342,'T',015,0215,026,0253,027,'~',0367,0302,0247,0366,0260,'Q',0337,'>',0376,0374,0235,'r',0342,0325,0351,025,0322,'P',0232,0372,' ','a',0326,0301,'A',0300,'q',0307,'c','a','L','#',0275,'h',0312,0230,0203,'6','~',0211,0267,'$',034,0321,'*','a',0226,0333,'j','%',025,013,0230,':',')','y',0231,']',0240,0301,05,'%','w','i',0231,0247,'2',0355,0212,0244,'[',021,0226,0246,0375,'Q',0265,0367,0341,0324,'B',0251,'m',0365,0277,'^','7','O',024,0322,0244,0212,0275,0261,0350,'{',0360,0357,'l','r',0205,0245,027,0347,0322,'k',0324,')',02,0231,'/',0214,0200,0252,0355,0203,'X',030,'&','@',0300,0235,']',0330,'m','*',0362,0340,'z',0254,0266,033,06,0246,0237,'6',0177,033,0377,0,'g',0361,0277,0366,'k','+','n',0325,'z','0',0327,0232,023,0355,'q','7',0205,0323,0275,0300,0314,0342,'^',0272,0267,'=',0371,'9',0203,0314,0261,0211,0262,'D',0245,034,'r',0224,025,0253,013,'}','l',0314,0306,0253,0261,04,0232,012,0243,0232,0205,04,023,'z',02,'y',0376,0270,'Q','N',06,03,'F',0335,'~',0346,0,010,'"',0365,0301,0134,'n',0236,' ',0211,'|','a',014,0335,0276,0362,0310,0205,0320,'&',036,035,0307,06,0273,'c','V',0377,0,0217,032,0272,0333,'[','E',031,'a',0207,'a','8',0275,'X','.',0304,010,0231,0336,'^',023,':','T',010,0277,'[',0302,0253,'Z','K',0216,014,'{',0232,'q','O',0216,'J',0220,0273,'#','i',0202,0326,'!','!','T',0362,0260,0206,0273,0304,'A','a','`',0200,0316,0202,0361,0315,'`','"',']','W','L','L',0247,034,'/','&',017,'n',022,0216,034,022,033,0261,0257,0363,0220,0351,0342,'<',036,'a','b','0','0',04,020,'P','[',0223,'N',0347,0273,0302,0302,0317,0271,'B',0234,0336,'v',0377,0,0260,032,'"',013,0324,0343,0250,06,0201,037,'0',0307,030,'E','U','W','Z','q','>','S',0364,0344,0202,016,0214,0264,0352,0345,'E','|','g','^','H','m','v',0346,'5',0233,'I',0202,010,'j',0355,'S',0235,0223,0317,0365,0222,0247,0355,'<',' ','}',0224,0367,'Z','?','r',0213,0256,0305,' ',0274,0343,0220,0351,0301,0325,0134,'S',';',0247,023,'=',0353,'n',']',0263,'<','u','}','W','W','#',0317,0224,0375,'9','K',0353,024,0222,0245,'*',0246,'a',015,'T',0361,0250,0202,0326,'k','B',0322,0343,0357,'}','b',02,'T',012,0346,0273,0211,0203,';',030,'#',0317,'P','%',0245,0340,0366,0341,'e',0215,021,'1',0262,'k',0366,0310,'n',0202,0,'6','9',016,0234,05,'M','E','n','%','E',0222,0331,0201,'M',0247,0245,0374,0360,0322,'@','K',0356,0217,0275,' ','`','$',020,0254,'9','8','R',0202,0320,'o',0206,'?','P',0220,07,035,0326,'X','`',02,'0',015,023,0212,0233,06,'Q',0262,0367,0257,'X',04,'@',0257,0252,0255,0377,0,0256,'Q',022,0261,'*','^','g','-',010,0206,015,0250,'F',0251,023,0264,0356,'%',0215,0245,'0','M',023,010,0240,0371,'J',0205,06,0314,'o',0302,0226,0250,'g',0250,030,0346,0273,0240,0225,']',0210,0217,0245,0330,0252,0266,'|',0234,0373,'p',0262,0320,0317,0252,'4',036,0360,011,05,0253,0233,'s',0376,0371,'.',0234,'>','H','a',0235,0362,'"',02,'#','H',0355,0303,'Q',0263,0233,'F',0271,'z','g',0356,0260,'=',0200,0265,0210,0350,0360,'b',0333,'$',0330,0344,0371,0217,011,0267,'u','%',0342,0300,016,'Q',0321,0352,'J',0347,'*',0352,0202,'y',0214,0372,0367,0373,0237,'^',0377,0,'s','&','v',0255,020,'-','G','T','P','7',0363,'w',0200,'A',0202,06,'U','a',0315,'K','G','K','0','{','r',0303,0350,025,0230,0310,0310,'P',010,0354,0267,033,0261,0205,0352,'P','#',0204,0213,022,030,'i','N',0260,032,0267,'(',0207,0204,014,0323,0234,0375,014,0245,'l',':','#',0223,'Q',0353,'R',0332,0274,'(',0355,' ',0235,0211,0367,0257,'h','n',0202,0,'6','9','.',0234,'*',0321,'@','X',0214,'B','d',02,0201,'e',0321,0353,0357,0302,0345,0225,'b','R','=','a',06,0200,0330,0246,'c',0206,0337,0235,0212,0340,'t',0377,0,0250,0263,05,0213,0227,0334,'L','K','w','$',0357,'=',0347,'y',0357,024,0352,0254,'c',021,'@',0251,0352,0303,0314,0300,0353,047,'W',0253,'4',0346,011,'^','r','G',0327,0333,0315,'S',0331,0232,0257,0267,022,0277,0216,'4','8',0275,0241,0341,'M',0320,0202,'(',0,0347,05,0356,'5',0325,0340,0250,0230,0,'.',0227,0340,0256,022,0254,'p','-','V',016,0200,032,04,0262,0336,'9','N',0234,'F','E','z',0332,0213,'/','e',0215,'i',0324,0354,0360,0277,'p',0200,0374,'0',0375,014,',','Z',0255,'C',0207,0260,0374,'$',0214,0324,'-',0134,0317,0,0303,'L','x',0260,012,037,0323,0374,023,0225,'R',' ',0272,'4',0216,0331,0300,0334,'l',0267,'^','-','c',0275,'.',0221,':',';',0377,0,0310,024,'Q',0247,')',0323,0211,',',0214,0244,'*',016,0253,0276,'7',0373,0277,021,0211,0345,'O','t','$','p',0222,'g',0236,0202,'q','_',0370,'D',0,05,0350,02,'[',026,0321,'g',0347,0323,0211,0256,'J','l',035,'9',0373,0357,01,0243,0200,013,0243,'^','[',0247,032,022,0211,0266,'#','*',0310,'t',0342,0355,0333,0247,021,0326,0260,0357,'t',0207,'Y','E',0372,0315,0334,011,0303,0254,'?',0301,' ',0,'/','@',021,0363,'%','b',0225,0270,'1',021,025,'[','W','~',026,'^','K',032,'[',0253,0330,0203,'s',0265,'A','s','W',',','+',0226,0351,0310,'q',0226,'g',0236,0240,0307,0224,0253,0314,'-',0317,0216,'#',0255,'a',0336,0351,016,0260,01,0321,'4','m','Y',0307,0370,'d','m',0347,'h',02,'8',0347,'c',0303,0332,'D','D','U','m',']',0370,0134,0230,0207,'Z',0226,0200,0227,'r','+','t',0215,0237,'9','X',0255,0245,0203,0267,'-',0323,0222,0273,'$',0245,0277,'f','?','t',0220,'|',0234,'F',024,016,01,0364,'b','=',0261,'e',0367,' ',0337,0370,033,0315,'x','#',0326,0252,05,0354,'K','d',011,'H',015,0342,0373,'q',0243,0341,0313,0302,0366,'P',0335,04,0,'l','s','n',0316,'S',0332,'1',024,036,0217,'x',0364,',','U','"','q','.',0360,0261,'6',0354,0365,' ',0340,'k','<',016,0275,0341,'2',0321,';',021,0377,0,0,0343,'0',0355,'{',0330,'#',0244,'K',0251,'K','P','4',0263,'~','2',0313,0252,022,0377,0,0344,0330,0352,'5',03,0232,0312,0243,0224,0226,'S',0244,'q',0372,016,0203,0321,0357,036,0205,0212,0244,'N','$',04,'D','l','M',0243,'h',0247,030,'4',0302,0375,0363,0216,'+',0225,0213,0272,'?',0234,0225,021,'X',0,0213,012,0311,0346,0265,'X',0357,0177,0250,0273,0302,0324,0323,0261,0320,0343,'3',';',06,0226,0177,0250,'x','~','m',0,'@',02,0202,0216,'s',0247,'-',',',0247,'I',0243,'D',0301,'A',0336,'/',0271,0,0323,0334,'w','8',0336,0376,015,0270,'Q',0334,0336,';','B',0340,032,'+','~',0232,'o',0,034,0336,025,'<',0317,0312,'/',035,'t',0200,'C',0342,02,'&',0213,'5','o',0231,',','/',033,012,':','5',0256,0234,'h',0,0252,0320,033,0304,'k','a',0267,'z','Y',01,0267,0315,0240,017,0315,0257,03,0224,0302,'V',06,'%',0311,'O','%',021,0344,'&',0370,0272,0247,0314,0365,'m','=','O',0342,0365,0313,0322,'R',0264,'j',':','z','~','0',0314,0273,030,020,0212,0272,0326,03,0235,'}','H',0305,'a',020,'I',0235,'_',047,'o','x',0345,0225,'j','Z',0275,'x',0320,',','R',0332,0273,020,036,'*','#','F',0314,0,0,017,'@',037,0237,'D','{',0223,'~',0310,0302,0317,0233,0276,'K',0263,0311,07,'L',0313,'4','5','4','t',0233,'*',')','5','k',0337,035,0346,'G',020,0340,0254,0325,'@',0250,0230,0241,0372,'~',02,0221,015,0325,'D',03,0302,'T',0315,'b',04,'*','c',035,07,'P',0367,0204,026,0260,0343,027,'O',0216,'K','!',0216,0304,0365,'X',012,'G','R','W','p',0206,0314,05,01,0241,0376,04,0320,015,04,037,'H',025,'Z','W',0312,0335,0320,0332,' ','?',03,'W',0334,'w',0345,'_',0244,0251,'u',0211,'Z','1',01,0234,'3',015,0352,0372,'w',0231,036,0275,'W','C','H',0,03,'?','V',0362,0214,'L','"',031,015,'1','q','@',031,'t',03,'/',0202,0345,026,'O','J',010,'K',023,'k',0264,0,0375,'h',0277,0311,034,031,0365,'A',0324,'z','K',0345,'!','k','#',0276,'?',0362,'c','[','$',0247,'d','J',0363,0253,0375,0307,0222,0345,0225,'@','Z',0275,'&',0214,0336,0204,0271,0263,0266,' ','`',0305,'(','z',0317,0342,'?',0203,0227,0276,'K','M','(','T',0314,'S','6',0251,0372,0343,0177,0272,0307,',',0252,'B',0221,0351,0314,'J',0204,'(',030,'i','Y',0204,0134,'K',0224,0263,0267,0201,'#','q','y',0177,'$',0356,0375,0374,0243,'k',013,'*',0317,0374,0314,0357,0205,0243,07,0226,'b','B',026,'z',0224,'8',011,'j','V','.',' ','X',0325,'m','}','y',0207,0,020,025,015,0326,0273,0377,0,0344,'r',0317,010,'/',016,0225,01,'h',0321,0320,035,0217,0305,0177,010,026,0215,035,0211,0334,0205,0350,0312,025,013,0235,'O','X',0305,'a','P','A',0235,'O','#','o','h',0345,0225,'H','R','=','?','5','7',0305,'U',036,'g',0243,'i',0350,0177,023,0256,036,0260,0276,'e','c',027,0315,0374,'w',0361,013,0307,'U',0240,0220,0277,031,'B',0241,'s',0251,0353,'0','y',0354,0343,0246,0333,0357,0322,'/','0','S','U',0232,0353,0371,016,'Y',024,02,0325,0207,'k',0236,0371,0227,'W',0231,'o',011,'A',0253,0326,'G',0257,0314,0,'s','X','E',0363,0177,'%',0374,'j',0222,0350,013,'"',0267,036,06,0333,0326,0372,0305,'T',025,0372,'@',0372,'C',0321,0300,032,'*','E',0346,012,'j',0263,']',0177,011,0313,'"',0200,'Z',0260,'L','e',']','@',0363,0210,0251,0265,0213,035,027,0374,0214,'J',0332,0336,'7','w','L',0307,0310,0207,07,0267,0345,0277,0222,05,013,0320,0134,0,06,0256,'!',0267,'|','K',0272,'d',025,0226,0320,0256,0221,0266,023,05,'^','e',0306,'t',0217,'T',0303,'m',0254,'E','$',0324,0351,'2',0255,0242,01,'m','T',07,0255,'r',034,0226,0227,'a','W',0244,0267,0224,030,'#',0332,'!',0245,'n',0213,0362,0231,0315,0275,'Y',0255,'=',0373,'O','e',0375,0222,'L','E','2',0350,'f',0212,0227,'0','y','~','s',0371,0250,':',0223,'I','n',0262,'0','|','u',0,'_',0251,0341,0246,0355,'V',0364,'A',0303,0255,'k','B',03,0231,0310,'j','Z',0361,'B',',','z',0301,'l',024,0250,'O','h',05,033,0320,'W',0377,0,015,'}',0245,0362,'+',0202,0237,0375,'7',0377,0331,}; diff --git a/src/embedded_images/nwipe_exclamation.jpg.h b/src/embedded_images/nwipe_exclamation.jpg.h new file mode 100644 index 0000000..124fcb6 --- /dev/null +++ b/src/embedded_images/nwipe_exclamation.jpg.h @@ -0,0 +1,16 @@ +/* Autogenerated by hxtools bin2c */ +#ifndef NWIPE_EXCLAMATION_JPG_H +#define NWIPE_EXCLAMATION_JPG_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern const unsigned char bin2c_nwipe_exclamation_jpg[63304]; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* NWIPE_EXCLAMATION_JPG_H */ diff --git a/src/embedded_images/nwipe_exclamation.xcf b/src/embedded_images/nwipe_exclamation.xcf Binary files differnew file mode 100644 index 0000000..dcbbe78 --- /dev/null +++ b/src/embedded_images/nwipe_exclamation.xcf diff --git a/src/embedded_images/redcross.c b/src/embedded_images/redcross.c new file mode 100644 index 0000000..fa22606 --- /dev/null +++ b/src/embedded_images/redcross.c @@ -0,0 +1,4 @@ +/* Autogenerated by hxtools bin2c */ +#include "redcross.h" +/* Autogenerated from redcross.jpg */ +const unsigned char bin2c_redcross_jpg[60331] = {0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,02,0,'v',0,'v',0,0,0377,0341,'(',0246,'E','x','i','f',0,0,'I','I','*',0,010,0,0,0,07,0,022,01,03,0,01,0,0,0,01,0,0,0,032,01,05,0,01,0,0,0,'b',0,0,0,033,01,05,0,01,0,0,0,'j',0,0,0,'(',01,03,0,01,0,0,0,03,0,0,0,'1',01,02,0,015,0,0,0,'r',0,0,0,'2',01,02,0,024,0,0,0,0200,0,0,0,'i',0207,04,0,01,0,0,0,0224,0,0,0,0246,0,0,0,'v',0,0,0,01,0,0,0,'v',0,0,0,01,0,0,0,'G','I','M','P',' ','2','.','1','0','.','3','0',0,0,'2','0','2','3',':','0','2',':','2','1',' ','2','0',':','3','9',':','5','5',0,01,0,01,0240,03,0,01,0,0,0,01,0,0,0,0,0,0,0,011,0,0376,0,04,0,01,0,0,0,01,0,0,0,0,01,04,0,01,0,0,0,0,01,0,0,01,01,04,0,01,0,0,0,0,01,0,0,02,01,03,0,03,0,0,0,030,01,0,0,03,01,03,0,01,0,0,0,06,0,0,0,06,01,03,0,01,0,0,0,06,0,0,0,025,01,03,0,01,0,0,0,03,0,0,0,01,02,04,0,01,0,0,0,036,01,0,0,02,02,04,0,01,0,0,0,0200,047,0,0,0,0,0,0,010,0,010,0,010,0,0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,0,0,01,0,01,0,0,0377,0333,0,'C',0,010,06,06,07,06,05,010,07,07,07,011,011,010,012,014,024,015,014,013,013,014,031,022,023,017,024,035,032,037,036,035,032,034,034,' ','$','.',047,' ','"',',','#',034,034,'(','7',')',',','0','1','4','4','4',037,047,'9','=','8','2','<','.','3','4','2',0377,0333,0,'C',01,011,011,011,014,013,014,030,015,015,030,'2','!',034,'!','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2',0377,0300,0,021,010,01,0,01,0,03,01,'"',0,02,021,01,03,021,01,0377,0304,0,037,0,0,01,05,01,01,01,01,01,01,0,0,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,020,0,02,01,03,03,02,04,03,05,05,04,04,0,0,01,'}',01,02,03,0,04,021,05,022,'!','1','A',06,023,'Q','a',07,'"','q',024,'2',0201,0221,0241,010,'#','B',0261,0301,025,'R',0321,0360,'$','3','b','r',0202,011,012,026,027,030,031,032,'%','&',047,'(',')','*','4','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0341,0342,0343,0344,0345,0346,0347,0350,0351,0352,0361,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0304,0,037,01,0,03,01,01,01,01,01,01,01,01,01,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,021,0,02,01,02,04,04,03,04,07,05,04,04,0,01,02,'w',0,01,02,03,021,04,05,'!','1',06,022,'A','Q',07,'a','q',023,'"','2',0201,010,024,'B',0221,0241,0261,0301,011,'#','3','R',0360,025,'b','r',0321,012,026,'$','4',0341,'%',0361,027,030,031,032,'&',047,'(',')','*','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0202,0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0342,0343,0344,0345,0346,0347,0350,0351,0352,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0332,0,014,03,01,0,02,021,03,021,0,'?',0,0367,0372,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'*',0275,0345,0365,0256,0237,'n',0323,0335,0334,'E',04,'K',0311,'y',030,01,'^','W',0342,0217,0217,0336,036,0321,0314,0220,'i',021,'I',0252,0134,0216,03,')',0331,020,'?',0357,'w',0374,05,0,'z',0345,'V',0273,0324,'l',0254,'c','2',']',0335,0301,02,016,0255,'$',0201,'@',0374,0353,0345,015,'s',0343,0177,0214,0265,0215,0313,025,0324,'V',021,036,0211,'l',0230,' ','}','N','M','p','w',0332,0235,0376,0247,')',0226,0372,0362,'{',0227,'=',0345,0220,0267,0363,0240,017,0257,'u','/',0213,0276,06,0322,0311,'Y','u',0350,'%','q',0374,'6',0352,0322,0237,0374,'t',021,0134,0345,0317,0355,015,0340,0370,0230,0210,'a',0324,'g',0307,'q',010,'P',0177,'3','_','-','Q','@',037,'J',0311,0373,'H','h','*','~','M',036,0375,0276,0254,0242,0226,'?',0332,'?','@','b','<',0315,'"',0375,'>',0214,0246,0276,'i',0242,0200,'>',0247,0266,0375,0241,'<',033,'3',01,'4','z',0204,031,0356,0320,0206,03,0362,'5',0322,0351,0237,025,0374,021,0252,0220,' ',0327,0355,0243,'s',0374,'7',031,0210,0377,0,0343,0300,'W',0306,'t','P',07,0337,026,0367,0226,0267,'q',0207,0266,0270,0212,'e','=',014,'n',030,037,0312,0247,0257,0203,0264,0375,'g','S',0322,'e',022,'i',0367,0367,026,0314,'9',0375,0324,0205,0177,'J',0364,015,013,0343,0267,0214,'4',0202,0211,'s',',',032,0214,'#',0252,0334,'.',030,0377,0,0300,0205,0,'}','c','E','y','g',0205,0276,';','x','g',']',')',06,0241,0277,'J',0272,'n','1','1',0314,'d',0373,'7',0370,0342,0275,':',0336,0352,013,0270,'V','k','y',0222,'X',0233,0220,0350,0331,06,0200,'%',0242,0212,'(',0,0242,0212,0316,0324,'5',0313,015,'1',0202,0134,0316,03,0221,0235,0252,'2','h',03,'F',0212,0347,'O',0215,'4',0254,0377,0,0313,'o',0256,0312,'_',0370,'L',0364,0237,0357,'K',0377,0,'|','P',07,'C','E','b','E',0342,0315,'"','S',0217,0264,024,0377,0,'}','H',0255,013,'m','N',0306,0360,0342,0336,0352,047,'>',0201,0271,0240,013,'t','Q','E',0,024,'Q','E',0,024,'Q','E',0,024,'Q','X','~','(',0361,'f',0223,0341,035,'*','M','C','U',0271,021,0242,0217,0221,07,'/','!',0354,024,'w',0240,015,0231,'e',0216,030,0232,'I',']','Q',024,'e',0231,0216,0,025,0343,0376,'6',0370,0363,0245,'h',0376,'m',0237,0207,0325,'u',013,0301,0225,0363,0217,0372,0245,'?','_',0342,0374,'+',0311,'<','}',0361,'c','Y',0361,0244,0217,'m',033,'=',0226,0227,0236,'-',0221,0271,'q',0376,0331,0357,0364,0351,'^','}','@',033,'~','!',0361,'v',0273,0342,0233,0266,0270,0325,0365,031,0247,'$',0361,036,0354,'"',0373,05,034,012,0304,0242,0247,0264,0263,0271,0276,0270,'[','{','H','$',0236,'f',0340,'$','j','X',0237,0312,0200,' ',0242,0275,'C',0303,0177,02,'<','W',0255,0354,0226,0370,'E',0245,0333,'7',';',0247,0371,0237,0360,'A',0375,'H',0257,'Y',0320,0376,01,'x','O','L',010,0367,0306,0343,'Q',0230,'u','2',0266,0324,0377,0,0276,'G',0365,0240,017,0225,0325,'Y',0216,024,022,'}',0,0253,0326,0332,036,0257,'z','3','k',0245,0336,0316,'?',0351,0225,0273,0267,0362,025,0366,0276,0235,0341,'/',017,0351,'H',0253,'e',0243,0331,0302,027,0246,'"',031,0255,0205,'E','A',0205,'P',0243,0320,014,'P',07,0304,'P',0370,017,0305,0327,037,0352,0374,'3',0253,'}','Z',0315,0327,0371,0212,'I',0274,013,0342,0333,'s',0373,0317,014,0352,0343,0334,'Y',0310,0303,0363,02,0276,0337,0242,0200,'>',015,0271,0321,0265,'K','#',0376,0225,0246,0336,'A',0377,0,']','`','e',0376,'b',0251,0220,'T',0340,0202,017,0241,0257,0277,036,'4',0221,'J',0272,'+',03,0331,0206,'k',023,'R',0360,'g',0206,0365,'d','+','{',0243,'Y',0313,0236,0247,0312,0,0376,0224,01,0360,0355,025,0365,026,0275,0373,'>',0370,'g','Q','W','}','2','{',0215,'6','c',0310,0332,'|',0304,0317,0373,0247,0267,0320,0212,0362,'o',022,'|',020,0361,'v',0202,'^','H',' ',0217,'R',0266,'^','D',0226,0307,0346,0307,0272,0236,'G',0353,'@',036,'m',']',027,0206,'|','s',0342,037,011,']',',',0332,'V',0243,'*','F','>',0364,016,'w','D',0343,0320,0251,0343,0362,0346,0260,'g',0202,'k','i',0232,031,0342,'x',0245,'C',0206,'G','R',010,0374,'*',':',0,0372,0243,0301,037,034,'t','O',020,0230,0254,0365,'m',0272,'m',0373,'a','A','s',0373,0247,'>',0315,0333,0361,0257,'V','V',016,0241,0224,0202,017,' ',0216,0365,0360,015,'{',0227,0302,'_',024,'x',0256,0317,'J',0222,')',0346,0363,'t',0260,0270,0267,0373,'F','Y',0224,0377,0,0262,'}','(',03,0333,0274,'E',0342,'$',0322,0342,'0','@','C',']',0260,0343,0321,07,0251,0257,'0',0325,'5','T',0265,015,'=',0324,0214,0362,0271,0310,04,0345,0230,0322,'j',0272,0250,0265,'G',0271,0270,'s','$',0256,'x',04,0362,0306,0270,0213,0273,0271,'o','n',032,'i','N','I',0350,'=',07,0245,'c','R',0247,'.',0213,'s',0351,'2','<',0212,'X',0331,'{','j',0332,'S','_',0217,0374,017,'3','Z','_',024,0134,0226,0375,0324,'1','*',0377,0,0265,0222,'j','h',0274,'R','z','M','l','>',0250,0325,0316,'Q','X','{','I','w','>',0316,'Y',026,'_','(',0362,0373,'%',0375,'y',0235,'z','x',0222,0305,0207,0315,0346,'!',0364,'+',0232,0320,0263,0324,'m',0356,0216,0353,'i',0301,'a',0316,01,0303,012,0340,'+','G','C',022,0235,'Z',037,'+','#',0256,0357,0367,'{',0325,0306,0254,0257,0251,0344,'c',0370,'g',07,012,023,0251,'I',0270,0264,0233,0337,'M',017,'{',0360,0256,0266,'u','+','S','o',';','f',0346,021,0311,'?',0304,0276,0265,0320,0327,0231,0370,'V','G','O',020,0333,0354,04,0356,0312,0266,'=','1','^',0231,']','G',0347,0341,'E',025,0300,'k',036,',',0277,0373,'t',0261,'Z','H','!',0212,'6','*',010,'P','I',0307,'~','h','l',016,0376,0212,0363,0315,'7',0306,'7',0326,0322,0377,0,0246,'7',0332,'b',047,0234,0200,030,'}','1','Z','~','(',0370,0213,0243,'x','s',0303,017,0253,0274,0302,'G','o',0222,030,07,0337,'g',0364,0307,'o',0255,'+',0201,047,0216,0374,'{',0246,'x',033,'H','k',0233,0247,'Y','.',0334,037,'"',0330,037,0231,0317,0370,'{',0327,0310,0376,047,0361,'f',0257,0342,0355,'Q',0357,0365,'[',0223,'#',023,0362,'F','8','H',0307,0242,0212,0217,0304,0276,'#',0324,'<','U',0256,'O',0252,0352,'2',0227,0232,'S',0302,0347,0204,'^',0312,'=',0205,'d','S',0,0245,012,'Y',0202,0250,'$',0236,0,035,0352,0366,0217,0242,0352,032,0376,0247,016,0237,0246,'[','=',0305,0314,0247,012,0252,':','{',0223,0330,'{',0327,0323,0377,0,016,0376,015,0351,'~',024,0216,'+',0355,'M','#',0276,0325,0207,0315,0275,0227,')',011,0377,0,'d',036,0376,0364,01,0345,'~',07,0370,027,0253,0370,0205,'"',0275,0326,']',0364,0333,026,0303,04,'+',0373,0327,037,'C',0323,0361,0257,0240,0374,'3',0340,0217,017,0370,'J',0324,'C',0244,0351,0361,0306,0330,0371,0246,'a',0272,'G',0367,',','k',0242,0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,'9','_',025,0374,'<',0360,0347,0214,'-',0331,'5','+',024,023,0343,011,'s',020,0333,'"','~','=',0376,0206,0276,'x',0361,0317,0301,']','o',0302,0251,'%',0345,0201,'m','K','O','^','K',0306,0237,0274,'A',0356,0243,0372,'W',0326,'5',0207,0342,035,'z','-','&',03,032,'m',0222,0345,0307,0312,0207,0240,036,0246,0200,'>','P',0360,'W',0202,0344,0326,0246,'[',0353,0324,')','`',0207,' ',036,0262,0237,'O',0245,'z',0305,0335,0325,0276,0223,'d','0',0252,0252,0243,'l','q',0257,031,0366,0247,0352,032,0204,'6',020,0264,0262,'m',05,0211,'*',0212,'1',0223,0354,'+',0211,0274,0273,0226,0366,0341,0246,0224,0344,0236,0203,0260,036,0202,0261,0251,'S',0227,'E',0271,0364,'y',036,'G',',','l',0275,0255,']',')',0257,0307,0313,0323,0273,013,0273,0311,0257,'g','2',0314,0331,047,0240,0354,'>',0225,05,024,'W',')',0372,'D','!',030,'E','F','*',0311,05,024,'T',0366,0266,0262,0336,0134,',','1','.','X',0367,0354,07,0255,01,'9',0306,021,'r',0223,0262,'B','Z',0332,0313,'y',':',0303,012,0345,0217,0344,'+',0264,0323,'t',0330,0264,0370,02,'/',0315,'!',0373,0317,0216,0246,0227,'N',0323,'b',0323,0341,0331,030,0334,0355,0367,0233,0271,'5',0350,'^',032,0360,0270,'@',0227,0267,0361,0374,0377,0,'z','8',0233,0267,0271,0256,0252,'t',0355,0253,0334,0374,0347,'<',0317,'e',0214,'n',0215,027,'j','k',0361,0377,0,0200,'?',0302,':',024,0266,0214,'u',013,0221,0265,0235,'6',0306,0207,0250,07,0271,0256,0266,0212,'+','c',0346,0204,'=',015,'x',0217,0211,0311,'[','}','C',07,037,';',0177,0350,'U',0355,0307,0241,0257,022,0361,' ',0315,0276,0241,0376,0363,037,0326,0263,0253,0360,0263,0267,'-',0377,0,'}',0245,0376,'%',0371,0234,0265,0216,0277,'s','k',0204,0227,0367,0321,0217,'S',0310,0374,'k',0242,0315,0206,0267,'d',0321,0272,0244,0321,'0',0303,'#',0216,'E','p',0365,'$','3',0313,'o',' ',0222,027,'(',0303,0270,0256,'h',0324,'q','?','@',0315,'8','{',017,0214,'N','t',0375,0311,0367,'[','?','U',0372,0231,'~',047,0370,'o','5',0263,'=',0336,0217,0231,'a',0352,'`','?','y','~',0236,0242,0271,'=',013,0303,0232,0237,0210,0265,0270,0264,0235,'>',0331,0336,0351,0333,05,'H',0306,0301,0334,0267,0240,025,0354,0372,'o',0210,'#',0270,02,';',0254,'G',047,0367,0277,0205,0277,0302,0272,0257,016,'_',0332,0350,':',0224,0267,0221,0331,'B',0315,'p',02,0313,'"',0250,016,'@',0351,0315,'u','F','j','G',0347,0330,0334,06,'#',05,'S',0222,0274,'m',0347,0321,0372,'3',0250,0360,017,0303,0355,'3',0300,0332,'J',0303,02,',',0267,0322,'(','7',027,'$','|',0314,'}',07,0240,0256,0302,0252,'i',0372,0225,0256,0247,07,0233,'m','(','a',0335,'{',0257,0324,'U',0272,0263,0214,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0261,0365,0355,'z',035,036,0337,'h',0303,0334,0270,0371,023,0323,0334,0373,'P',03,'u',0375,'z','-','"',0337,'j',020,0367,'N','>','D',0364,0367,'5',0345,0272,0266,0255,0344,0254,0227,'w','R',031,'%','s',0300,047,0226,'4',0355,'[','V',0362,0374,0313,0273,0271,013,0310,0347,'<',0236,'X',0372,012,0341,'/','o','f',0276,0234,0313,'+','}',027,0262,0217,'J',0306,0245,'N',']',026,0347,0321,'d','y','$',0261,0322,0366,0265,'t',0246,0277,037,'%',0372,0260,0275,0275,0226,0372,0340,0313,')',0347,0260,035,0,0252,0364,'Q',0134,0247,0351,'0',0204,'i',0305,'B',012,0311,05,024,'U',0213,';','9','o',0256,04,'1',016,'{',0236,0300,'P',023,0234,'i',0305,0316,'n',0311,011,'i','i','5',0354,0342,'(','W','$',0365,'=',0207,0326,0273,'m',';','N',0216,0306,025,0212,'%',0335,'#','}',0346,0307,',','i',0266,'6','0','i',0266,0333,'T',0217,'W','v',0357,'W','~',036,'x',0307,'@',0325,'<','i','>',0223,0303,0334,',','{',0255,0245,047,0344,'v',037,'x',017,'|','c',037,0215,'u','S',0247,0313,0253,0334,0374,0343,'<',0317,'%',0215,0223,0243,'G','J','k',0361,0377,0,0201,0331,035,0327,0206,0374,'0','-',0202,0336,0337,'(','3',036,'R','3',0374,036,0347,0336,0272,0272,'(',0255,0217,0233,012,'(',0242,0200,012,0361,'_',022,017,0223,'R',036,0357,0374,0315,'{','U','y',016,0272,0326,'r',0353,0332,0235,0224,023,',',0206,'9','6',0310,0243,0252,0226,031,0307,0353,'Q','5','x',0330,0337,013,'Q','R',0257,012,0217,'d',0323,0374,'O','0',0242,0255,0352,032,'|',0332,'|',0345,'$',031,'S',0367,'X','t','"',0252,'W',021,0373,035,'*',0260,0253,05,':','n',0351,0205,'i',0351,0332,0325,0305,0216,020,0376,0362,037,0356,0223,0323,0351,'Y',0224,'P',0235,0210,0257,0207,0245,0210,0203,0247,'V','7','L',0364,'-','#',0134,06,'E',0270,0261,0270,'1',0312,0275,'W','8','#',0352,';',0212,0364,'=',027,0305,0360,']',0225,0202,0373,020,0314,'x',017,0374,'-',0376,025,0363,0354,'R',0311,014,0202,'H',0334,0253,016,0204,'W','E',0246,0370,0210,'1',021,'^',0340,036,0202,'A',0323,0361,0255,0341,'[',0243,'>',027,'4',0341,'z',0224,'o','S',011,0357,'G',0267,'U',0351,0337,0363,0365,'>',0210,0316,'F','E',025,0347,032,037,0213,'n',',','B','G','9',0373,'E',0257,'n','~','e',036,0306,0273,0333,035,'B',0333,'Q',0200,'K','m','(','u',0356,';',0217,0250,0256,0204,0356,'|',0233,'M',';','2',0325,024,'Q','L','A','E',024,'P',01,'E',024,'P',01,'E',025,0223,0256,'k',0220,0350,0366,0304,0222,032,0341,0207,0356,0343,0376,0247,0332,0200,023,']',0327,'b',0321,0355,0270,0303,0334,'8',0371,023,0372,0237,'j',0362,0335,'_','W',0330,'d',0274,0274,0220,0274,0216,'x',035,0311,0364,024,0272,0276,0256,'G',0231,'{','y','!','y',033,0267,'r','}',05,'p','w',0327,0323,'_',0316,'e',0224,0377,0,0272,0243,0240,025,0215,'J',0234,0272,'-',0317,0241,0311,'2','I','c',0247,0355,'*','i','M','~','>','K',0365,'a','}','{','-',0375,0311,0226,'C',0354,0253,0331,'E','V',0242,0212,0345,'?','J',0247,'N','4',0342,0241,05,'d',0202,0212,'*',0315,0225,0214,0327,0363,0210,0242,037,0357,'1',0350,05,01,'R',0244,'i',0305,0316,'n',0311,011,'g','e','5',0365,0300,0212,'%',0372,0267,'e',036,0265,0331,0332,'Y',0333,0351,0226,0244,'.',024,01,0227,0221,0273,0373,0232,0233,'K',0322,0304,013,035,0255,0254,'e',0344,'c',0216,07,',','k',0277,0267,0360,'E',0234,0332,035,0315,0246,0240,0242,'I','n',0242,'(',0347,0262,02,';','W','U',':','|',0272,0275,0317,0315,0263,0274,0362,'X',0331,'{','*','Z','S','_',0217,0233,0375,021,0363,'W',0215,0274,'t','u','/','7','M',0323,030,0255,0246,'J',0311,'/','O','3',0330,'{','W',037,0244,0352,'w',032,'6',0255,'k',0251,'Z','1','Y',0355,0344,022,'!',0372,'v',0251,0374,'G',0242,0134,'x','s',0304,'7',0332,'M',0322,025,0222,0332,'R',0234,0377,0,022,0366,'?',0210,0301,0254,0272,0330,0371,0323,0356,'o',012,'x',0202,0337,0305,036,032,0261,0325,0355,0230,024,0270,0214,026,037,0335,'a',0303,')',0367,07,'5',0263,'_','<','~',0316,0276,'(','1',']','_','x','n','y','>','I',0177,0322,' ',04,0364,'n',0214,07,0351,'_','C',0320,01,'E',024,'P',05,'-','_','Q',0213,'I',0321,0357,'5',011,0330,',','V',0320,0264,0254,'O',0240,031,0257,0213,0355,0374,'_',0177,'o',0342,0273,0235,'p','9','g',0271,0225,0236,'h',0311,0341,0224,0236,0237,0205,'}',027,0361,0357,'Z','m','3',0341,0343,0331,0306,0333,'d',0324,'&','X','z',0377,0,0,0371,0233,0371,01,'_',')','P',07,0277,0330,0337,0351,0336,'*',0322,'<',0310,034,'2',0237,0274,'?',0212,'6',0256,0177,'P',0323,047,0323,0345,0303,0215,0321,0237,0272,0343,0241,0257,'8',0360,0326,0251,0250,'i',0232,0315,0277,0366,'s',023,'$',0322,',','~','_','i','2','p',01,037,0215,'}','1',0253,'x','R',0362,0312,0325,'^','D','[',0210,'Y','F',0362,0243,0356,0236,0371,037,0326,0261,0235,'.','m','Q',0356,'e',031,0335,0134,0275,0362,'?','z',017,'u',0333,0315,036,'C','E','o','j','~',037,'x',0211,0232,0320,'n','N',0246,'>',0343,0351,0353,'X','$',020,'H','#',04,'W','3','M',';','3',0364,'|',036,'6',0206,'2',0237,0264,0243,'+',0257,0305,'z',0205,024,'Q','H',0352,'/',0351,0372,0255,0305,0203,0200,0254,'^','.',0350,0307,0217,0303,0322,0273,'=',027,0304,037,0275,'Y',0354,'n',014,'s','/','T',047,0237,0304,'w',025,0347,0264,0350,0344,'x',0234,'<','l','U',0207,' ',0203,'W',031,0270,0236,'&','i',0221,'a',0361,0311,0313,0341,0237,'u',0372,0367,'>',0207,0321,0274,'[','o','}',0266,033,0275,0260,'N','x',04,0237,0225,0217,0364,0256,0222,0276,'v',0323,0274,'F',016,0330,0257,'x','=',04,0200,'q',0370,0327,0240,0350,0236,',',0270,0260,'T','I','[',0355,026,0275,0271,0344,017,'c',']','0',0250,0244,'~','y',0217,0313,'q',030,031,0362,0326,0216,0235,037,'F','z','E',025,'V',0307,'Q',0265,0324,0240,022,0332,0312,034,'w',035,0307,0324,'U',0252,0320,0340,012,'(',0254,0315,'k','Y',0207,'G',0265,'.',0330,'i',0233,0375,0134,'~',0247,0374,'(',01,0272,0336,0267,06,0217,'m',0271,0260,0323,0260,0375,0334,'~',0276,0347,0332,0274,0267,'W',0325,0316,0351,'/','o','e',0334,0354,'x',036,0276,0302,0227,'Y',0326,'I','i','/',0257,'d',',',0307,0240,0365,0366,02,0270,'+',0373,0371,'u',013,0203,',',0234,01,0302,0257,'`','+','*',0225,'9','t','[',0237,'A',0222,'d',0223,0307,'O',0332,'T',0322,0232,0374,'|',0227,0352,0302,0372,0372,'k',0373,0203,',',0247,0217,0341,'^',0312,'*',0255,024,'W','!',0372,'U',':','p',0247,05,010,'+','$',024,'Q','V',0254,'l','&',0277,0234,'G',020,0371,0177,0211,0217,'E',024,05,'J',0220,0245,07,'9',0273,'$',026,'6','2',0337,0334,010,0243,034,'u','f',0354,05,'w',':','V',0222,'#',0331,'i','g',021,'y',034,0366,0352,0307,0324,0323,0264,0235,'$',0203,035,0235,0224,'E',0235,0277,'3',0356,'k',0324,'4','-',06,035,036,014,0234,'=',0313,017,0236,'O',0350,'=',0253,0256,0235,'>',']','^',0347,0346,0331,0336,'w','<','t',0275,0235,'=',')',0257,0307,0315,0377,0,0220,0315,03,0303,0361,'i',021,'y',0222,'a',0356,0230,'|',0317,0375,0337,'a','[','t','Q','Z',0237,'<','x',07,0355,025,0341,'e',0305,0227,0211,0240,'L','7',026,0367,04,016,0243,0370,'I',0376,'U',0363,0375,'}',0267,0343,0335,07,0376,022,'O',04,'j',0272,'j',0250,'2',0311,03,'4','Y',0354,0340,'e',0177,'Q','_',022,0262,0225,'b',0254,010,' ',0340,0203,0332,0200,'6','<',047,0256,'I',0341,0277,024,0351,0332,0264,'l','G',0331,0346,'V','p',';',0247,'F',037,0226,'k',0356,033,'i',0343,0272,0266,0212,0342,'&',015,034,0250,035,030,'w',04,'d','W',0300,0265,0366,037,0301,0335,'_',0373,'_',0341,0246,0226,'Y',0267,'I','l',0237,'g','l',0365,0371,'x',037,0245,0,'w',0224,'Q','E',0,'|',0347,0373,'H','j','f','M','[','I',0323,03,'|',0261,0306,0323,'0',0367,047,03,0372,0327,0206,'W',0244,0374,'t',0275,0373,'_',0304,0373,0310,0363,0221,'o',024,'q','~',0231,0376,0265,0346,0324,01,0336,'|',035,0321,0227,'Y',0370,0233,0245,0243,0250,'h',0255,'X',0335,'8','#','?','p','q',0377,0,0217,025,0257,0260,0210,04,'`',0214,0212,0371,0307,0366,'n',0260,0363,'5',0335,'^',0375,0227,0375,'T',013,032,0267,0324,0222,0177,0220,0257,0243,0350,03,0226,0326,0374,'!',015,0336,0353,0213,014,'E','7','S',037,0360,0267,0370,'W',0231,'k','~',033,'-','3',0254,0221,0233,'{',0245,0353,0221,0303,'}',0177,0306,0275,0332,0250,0352,'Z','M',0246,0253,017,0227,'s',030,'$','}',0327,037,'y',0177,032,0231,'A','I','j','t',0341,'1','u',0260,0225,025,'J','2',0263,0376,0267,'>','f',0272,0264,0232,0316,'c',024,0310,'U',0273,'z',037,0245,'C','^',0261,0342,'?',011,'I','j',0204,'O',027,0237,'j','O',0313,'(',034,0257,0327,0322,0274,0353,'S',0321,0246,0261,'b',0351,0231,'!','=',030,016,'G',0326,0271,047,'M',0304,0375,023,')',0342,012,'8',0333,'S',0251,0356,0324,0355,0321,0372,0177,0221,0231,'E',024,'T',037,'@',025,'z',0303,'U',0271,0260,'`',021,0267,'G',0335,033,0247,0377,0,'Z',0250,0321,'A',0235,'j','4',0353,'A',0323,0250,0256,0237,'F','z',016,0215,0257,0346,'A','5',0224,0355,024,0303,0252,0347,0237,0313,0270,0257,'F',0321,'|',']','o','z',026,033,0335,0260,'O',0323,'w',0360,0267,0370,'W',0317,'H',0355,033,0207,'F','*',0303,0220,'A',0344,'W','A',0247,'x',0217,01,'c',0274,0317,0247,0230,07,0363,0255,0341,'[',0244,0217,0205,0315,'8','^','t',0357,'S',07,0252,0376,'^',0253,0323,0277,0347,0352,'{',0316,0261,0254,0333,0351,026,0236,'c',0220,0322,'0',0375,0332,03,0313,0177,0365,0253,0313,'5',0215,'a',0235,0244,0276,0275,0227,',','z',017,0350,'*',013,0275,'J','8',0355,'E',0304,0323,0227,'E','P',027,0346,0317,0320,012,0342,'u',013,0371,'u',013,0203,'#',0222,024,'p',0211,0331,'E','i','R',0252,'K','M',0316,014,0233,'#',0251,0215,0251,0315,'U','Z',013,0177,'?','%',0372,0205,0376,0241,'6',0241,'9',0222,'C',0205,037,'u',07,'E',025,'R',0212,'+',0220,0375,'*',0235,'8','R',0202,0204,025,0222,012,'(',0253,0232,'v',0237,'.',0241,'p','#','@','B',017,0274,0370,0340,012,02,0255,'X','R',0203,0251,'Q',0331,'!','4',0375,'>',']','B',0177,'.','>',024,'}',0346,'=',05,'w',0232,'6',0214,0314,'c',0262,0262,0214,0263,036,0247,0371,0223,'O',0321,'4','F',0226,'D',0262,0261,0213,0223,0313,'7',0365,'&',0275,'G','G',0321,0255,0364,'{','o','.','1',0272,'F',0373,0362,021,0313,037,0360,0256,0272,'t',0371,'u','{',0237,0232,'g','Y',0334,0361,0363,0366,'t',0364,0246,0277,037,'7',0376,'C','4','M',022,015,036,0333,012,03,0316,0303,0347,0223,034,0237,'a',0355,'Z',0264,'Q','Z',0236,0,'Q','E',024,0,036,'F','+',0342,0237,0210,0332,'8',0320,0376,' ','k',026,'J',0273,'c',0373,'A',0222,'1',0376,0313,'|',0337,0326,0276,0326,0257,0226,0377,0,'h','[',01,'m',0343,0310,'.',0200,0307,0332,'m','T',0237,0252,0234,0177,'Z',0,0362,'J',0372,'#',0366,'n',0325,014,0232,'v',0257,0245,0263,'g',0312,0221,'f','Q',0350,030,'c',0371,0212,0371,0336,0275,'w',0366,'w',0275,'0','x',0372,0346,0323,'8',027,'6','m',0370,0225,' ',0377,0,0215,0,'}','E','E',024,'P',07,0306,037,024,0346,'3',0374,'N',0327,0334,0366,0271,'+',0371,0,'?',0245,'q',0365,0324,'|','H',05,'~','$','x',0204,'7','_',0267,'H',0177,'Z',0345,0350,03,0350,0337,0331,0262,' ','4','M','j','l','r','n','U',0177,0361,0321,'^',0345,'^',')',0373,'7',0262,0237,013,'j',0240,'u',027,'c','?',0367,0310,0257,'k',0240,02,0212,'(',0240,06,0274,'i','"',024,'u',014,0244,'`',0202,'8','5',0307,0353,0236,015,'W',015,'>',0234,07,'<',0264,07,0241,0372,0177,0205,'v','T','P',033,037,'?',0352,0376,031,'>','c',030,'S',0311,0234,037,0232,'6',030,07,0374,'+',0226,0236,0336,'[','i',014,'s','!','V',036,0265,0364,0266,0255,0241,0331,0352,0321,'b','T',0333,'(',037,',',0253,0324,0177,0215,'y',0277,0210,'|',')','%',0260,'+','w',017,0231,016,'~','I',0224,'t',0377,0,012,0302,'t','z',0304,0372,0234,0257,0211,0252,0341,0355,'O',023,0357,'G',0277,'U',0376,'g',0226,0321,'Z',0272,0226,0211,'=',0231,'2',047,0357,'!',0365,03,0221,0365,0254,0252,0346,'j',0332,'3',0357,'p',0330,0252,'8',0232,'j',0245,031,']',05,024,'Q','A',0270,'Q','E',024,0,'Q','E','Z',0323,0254,0215,0375,0342,0300,033,'h',0306,'I',0366,0240,0212,0225,'#','J',016,'s','v','K','V',';','N',0323,'f',0324,'&',0332,0203,010,'>',0363,0236,0202,0275,07,'C',0320,0236,0345,0322,0316,0312,'<','(',0373,0316,'z',017,'s','N',0320,'4',06,0272,0221,',',0254,0324,'*','/','.',0347,0260,0365,'5',0352,'Z','f',0231,'o',0245,0332,',',020,'/',0373,0314,'z',0261,0365,'5',0327,'N',0237,'.',0257,'s',0363,'<',0353,':',0236,'>','|',0220,0322,0232,0331,'w',0363,'c','4',0255,'&',0337,'I',0265,021,'B',0271,'c',0367,0334,0365,'c','W',0350,0242,0265,'<',020,0242,0212,'(',0,0242,0212,'(',0,0257,0236,'?','i','H',0,0277,0321,047,0307,'&','7',0134,0376,'"',0276,0207,0257,0237,0377,0,'i','R','?',0342,'D',';',0376,0363,0372,'P',07,0200,'W',0241,0374,021,0270,0362,'>','+','i','C',0376,'z',0254,0261,0377,0,0344,'6','?',0322,0274,0362,0273,0237,0203,0200,0237,0213,':',016,'?',0347,0244,0237,0372,')',0350,03,0354,'j','(',0242,0200,'>','4',0370,0265,01,0267,0370,0243,0256,0256,'0',032,'p',0343,0361,'P','k',0213,0257,'R',0370,0373,'`','m','~','$','=',0306,0334,'-',0315,0262,'>','}','H',0310,'?',0310,'W',0226,0320,07,0321,037,0263,'d',0343,0373,'3','Z',0267,0317,'"','d','|',0177,0300,'q',0375,'+',0335,0353,0346,'_',0331,0317,'Q','X','<','_',0250,'X','3','`',0334,0332,0357,'Q',0356,0207,0377,0,0262,0257,0246,0250,0,0242,0212,'(',0,0242,0212,'(',0,0246,'I',022,'M',033,'G','"',07,'F',030,'*','F','A',0247,0326,'v',0261,0254,'A',0244,'Z',0231,'$','!',0244,'o',0365,'q',0347,0226,'?',0341,'@',034,0177,0212,'t',033,'M','8',011,0340,0225,'T','H','q',0344,'7','?',0227,0265,'y',0247,0210,'t',0350,'`',0205,'.','a',01,'2',0333,'Y','G','N','{',0327,'U',0253,'j',0357,';',0311,'{','}','/',0377,0,'[',0330,012,0340,0265,'=','N','M','F','l',0237,0226,'%','?','"',0177,0217,0275,'a','Y',0306,0326,0352,'}','O',013,0341,'q','R',0304,'{','h',';','A','o',0331,0371,0177,'[',024,'h',0242,0212,0346,'?','D',012,'(',0242,0200,012,0232,0322,0352,'K',';',0205,0236,'#',0363,'/',0257,'C','P',0321,'A','3',0204,'g',027,031,'+',0246,'w',032,'/',0211,'w','N',0217,024,0246,0336,0344,'t',031,0353,0376,'5',0351,'Z','7',0214,'a',0271,'+',05,0376,'"',0220,0360,'$',037,'t',0375,'}','+',0347,0320,'H','9',07,04,'V',0346,0233,0342,011,'!','+',025,0327,0317,037,'M',0375,0307,0370,0326,0320,0254,0326,0222,'>','#','5',0341,'v',0257,'W',05,0377,0,0200,0377,0,0227,0371,037,'H','+',06,0,0251,04,036,0204,'R',0327,0227,'h','>','*',0236,0311,'S',0313,0220,0134,'Z',037,0340,047,0247,0320,0366,0257,'C',0323,0265,'k','M','R',021,'%',0274,0231,'?',0304,0207,0206,'_',0250,0256,0224,0356,0256,0217,0215,0224,'e',06,0343,'%','f',0213,0324,'Q','E','2','B',0212,'(',0240,02,0276,'r',0375,0244,0256,'C','k',':','5',0267,'u',0205,0330,0376,'$','W',0321,0265,0362,0217,0307,0275,'G',0355,0237,021,'^',0334,020,'V',0326,04,'O',0241,'<',0237,0351,'@',036,']','^',0221,0360,'*',0337,0317,0370,0251,'`',0330,0317,0225,024,0262,'}','>','B','?',0255,'y',0275,'{','7',0354,0345,'a',0347,'x',0303,'Q',0276,'+',0305,0275,0246,0300,'}',0335,0207,0377,0,023,'@',037,'L',0321,'E',024,01,0340,037,0264,0226,0227,0362,0350,0332,0252,0216,0357,03,037,0324,0177,'*',0371,0376,0276,0277,0370,0317,0240,0266,0271,0360,0333,'P',0362,0223,'t',0366,'{','n',0220,016,0277,')',0371,0277,0361,0334,0327,0310,024,01,0325,0374,'5',0326,0306,0201,0361,017,'F',0276,'v','+',027,0236,'"',0227,037,0335,0177,0224,0347,0363,07,0360,0257,0265,07,'"',0276,01,'F','(',0352,0312,'p','T',0344,032,0373,'o',0300,0272,0362,'x',0223,0301,0232,'f',0244,0255,0271,0236,020,0262,'s',0310,'q',0301,0240,016,0216,0212,'(',0240,02,0212,'+',';','X',0326,' ',0322,'-',014,0262,035,0322,036,022,'<',0362,0307,0374,'(',0,0326,'5',0213,'}','"',0327,0314,0220,0356,0221,0270,0216,'1',0325,0217,0370,'W',0226,0353,032,0303,'M','$',0227,0327,0322,0365,0350,'=','=',0,0243,'Y',0326,0232,'W',0222,0372,0372,'^','{',01,0374,0200,0256,013,'Q',0324,'e',0324,'g',0336,0374,' ',0373,0251,0351,'Y','T',0251,0313,0242,0334,0367,'r',0134,0226,'x',0371,0363,0317,'J','k','w',0337,0311,013,0251,'j','R',0352,'3',0226,'b','V','!',0367,023,0323,0377,0,0257,'T','h',0242,0271,033,0271,0372,'e',032,'0',0243,05,'N',0232,0262,'A','E',025,'=',0245,0254,0267,0227,013,014,'K',0222,'z',0236,0300,'z',0320,'T',0347,030,'E',0312,'N',0311,011,'o','k','=',0323,025,0202,'&',0220,0201,0223,0216,0325,033,0243,'F',0345,035,'J',0260,0352,010,0257,'G',0320,'4',011,'%','+','e','d',0200,0266,'2',0356,'z','}','I',0250,0265,0277,017,0260,'v',0202,0372,03,034,0243,0356,0276,'?',0221,0357,'[','{',031,'Z',0375,'O',0222,0134,'[','K',0353,016,016,037,0273,0350,0372,0372,0330,0363,0272,'*',0365,0376,0227,'q',0247,0267,0316,'7','G',0331,0307,'J',0243,'X',0237,'U','F',0265,':',0360,'U',')',';',0247,0324,'(',0242,0212,015,'K','6','w',0363,0330,0311,0276,026,0343,0272,0236,0206,0273,'-',037,'_',022,'H',0222,'A','1',0202,0345,'y',0300,'l',037,0376,0275,'p',0224,0252,0305,030,'2',0222,010,0344,021,0332,0252,'3','q',0330,0361,0363,'L',0227,017,0217,0215,0336,0223,0356,0277,'^',0347,0320,0232,047,0213,0241,0273,0333,05,0366,'"',0230,0360,037,0242,0267,0370,'W','Q',0326,0276,'t',0323,'<','D','A','X',0257,':','t',022,0177,0215,'z','&',0205,0342,0311,0254,'B','G',';',031,0355,'{',034,0344,0250,0366,0256,0270,'T','R','?','9',0307,0345,0270,0214,014,0371,'+','-',':','>',0214,0364,'z','*',013,'K',0310,'/','`','Y',0255,0344,'W','F',0356,'*','z',0263,0200,'l',0216,0261,0306,0316,0347,012,0240,0222,'O','`','+',0341,0317,027,'j',0377,0,0333,0336,'.',0325,'u','@','r',0267,027,014,0310,'s',0374,'9',0302,0376,0200,'W',0325,0277,026,0265,0377,0,0370,'G',0376,036,'j','r',0244,0233,047,0270,0214,0333,0304,'G',0134,0267,031,0374,0263,'_',034,'P',01,'_','K','~',0316,'z','W',0331,0374,'/',0250,'j','L','9',0272,0270,0332,0247,0331,'F','?',0236,'k',0346,0232,0373,'O',0341,0256,0212,0332,017,0303,0355,'"',0316,'T',0331,'9',0201,'e',0225,'}',031,0271,'#',0365,0240,016,0262,0212,'(',0240,010,0256,' ','K',0233,'i',' ',0220,02,0222,')','V',07,0270,'#',025,0361,017,0214,'4',031,'<','5',0342,0275,'G','J','p','@',0206,'S',0263,0335,017,'#',0364,0257,0270,0353,0347,0357,0332,'#',0302,'M',0276,0317,0305,026,0261,0344,'c',0354,0367,'X',035,'?',0272,0337,0314,'~','T',01,0340,'5',0357,037,0263,0277,0213,0204,'7','W','~',027,0272,0223,013,'(',0363,0355,'s',0375,0341,0367,0227,0371,037,0316,0274,036,0264,'4','=','^',0343,'A',0326,0355,'5','K','V',0304,0326,0322,07,036,0376,0243,0362,0240,017,0273,0350,0254,0217,014,'x',0202,0323,0304,0376,036,0263,0325,0354,0234,'4','S',0246,'H',037,0302,0335,012,0237,'p','j','m','c','X',0203,'H',0264,'2',0312,'w','H','x','H',0307,'V','?',0341,'@',06,0257,0254,'[',0351,026,0246,'I','H','2',037,0271,036,'y','c','^','Y',0255,'k','M','+',0311,'{','}','.','I',0350,0277,0320,012,'M','s',0134,'2','H',0367,0267,0262,'e',0217,012,0243,0371,01,0134,015,0375,0374,0267,0367,06,'I',011,0333,0374,'+',0331,'E','e','R',0247,'.',0213,'s',0350,'2',0134,0222,'x',0351,'{','J',0232,'S','_',0217,0222,0377,0,'1','u',015,'F','m','B','m',0362,034,'(',0373,0250,':',012,0251,'E',025,0310,'~',0225,'J',0224,')','A','S',0246,0254,0227,'@',0242,0212,'r','#','J',0352,0210,0245,0231,0216,0,035,0350,'-',0273,'j',0307,'A',04,0227,'3',',','Q',')','g','c',0300,0256,0367,0303,0372,013,0253,'G','i','l',0236,'e',0304,0237,'}',0261,0376,'x',025,'[','A',0320,0332,02,0221,0242,'y',0227,'r',0361,0307,'o','a','^',0273,0240,'h','q',0350,0366,0277,'6',032,0345,0307,0357,037,0372,017,'j',0351,0245,'N',0336,0363,'?',';',0342,014,0357,0353,'R','x','z',017,0334,'[',0276,0377,0,0360,013,032,'>',0223,016,0221,'d','!',0214,02,0347,0231,037,0273,032,0232,0373,'O',0266,0324,'m',0314,'7','1',07,'S',0320,0367,037,'C','V',0250,0255,0317,0226,'<',0317,']',0360,0264,0372,'z',0273,05,0373,'E',0241,0376,',','r',0243,0334,'W',0237,'j','~',037,')',0231,'l',0306,'W',0251,'N',0377,0,0205,'}',030,'@','`','A',0,0203,0324,032,0344,0265,0277,010,'$',0273,0256,'4',0340,021,0372,0230,0273,037,0247,0245,'g',':','j','g',0241,0227,0346,'x',0214,04,0371,0251,'=',':',0256,0214,0360,022,010,'$',021,0202,':',0212,'J',0355,0265,'m',02,'9',0335,0301,0214,0301,'r','8','9',030,0347,0334,'W',037,'s','i','5',0234,0246,'9',0220,0251,0354,'{',037,0245,'r',0312,016,'.',0314,0375,'#',',',0316,'0',0371,0204,'}',0307,'i','u','O',0177,0370,'(',0206,0212,'(',0251,'=','P',0255,015,';','W',0236,0301,0202,0347,'|',']',0320,0237,0345,'Y',0364,'P','c','_',017,'K',021,'M',0323,0253,033,0246,'z','f',0201,0342,'I',' ','e',0270,0261,0233,0217,0343,0211,0272,037,'b','+',0323,'4','}','v',0327,'W',0213,0344,';','&',03,0346,0210,0365,037,'O','Q','_','6','A','q','-',0264,0242,'H',0134,0253,017,'N',0365,0327,0350,0336,'"',022,0312,0230,0220,0301,'t',0277,'t',0203,0214,0375,'+',0246,0235,'k',0351,'#',0363,0374,0337,0207,'j','a','o','W',017,0357,'C',0361,'_',0346,0274,0316,'w',0366,0200,0361,'h',0325,'<','G',016,0201,'k','&',0350,'4',0361,0231,0260,'x','2',0236,0337,0200,0376,'u',0343,'u',0350,0236,'7',0360,'5',0314,'s',0334,'j',0366,06,'K',0205,0221,0332,'Y',0320,0374,0316,011,'9','$','z',0327,0235,0220,'A',0301,0353,'[',0237,'0','u',0277,015,'|','8',0336,047,0361,0326,0235,'d','T',0230,022,'A','4',0377,0,0356,')',0316,'?',036,05,'}',0242,0,'P',0,030,03,0201,'^',047,0373,'<',0370,'Q',0254,0264,';',0257,021,']','E',0266,'K',0326,0362,0355,0362,'9',0362,0327,0251,0374,'N',0177,'*',0366,0332,0,'(',0242,0212,0,'+','7',0304,032,'5',0277,0210,'4','+',0275,'.',0351,'C','E','q',031,'C',0236,0307,0261,0255,'*','(',03,0341,'-','{','F',0272,0360,0366,0273,'y',0245,'^','!','I',0255,0244,'(','s',0334,'v','?','B','9',0254,0332,0372,'c',0343,0277,0200,0206,0257,0245,0177,0302,'K','a',016,'o',',',0323,0375,' ','(',0345,0342,035,0377,0,012,0360,'o',013,0370,'^',0353,0304,'w',0301,'U','Y','-',020,0376,0366,'l','p','=',0207,0275,0,'z',047,0300,0337,025,'j','Z','4',0267,0326,'f',0335,0347,0322,0334,'o',0316,0354,010,0345,0366,0372,0367,0256,0337,']',0327,'Y',0331,0357,'o','d',0334,0307,0205,'A',0374,0205,'d',0306,0232,0177,0206,0264,0250,0355,0340,'E',0216,'4',030,'T',035,'X',0372,0377,0,0365,0353,0225,0275,0275,0232,0372,'s',',',0315,0364,'^',0312,'+',032,0225,'9','t','[',0237,'E',0222,'d','r',0307,'K',0332,0325,0322,0232,0374,'|',0227,0352,0307,'_','_','K',0177,'?',0233,')',0343,0370,'T','t','Q','U','h',0242,0271,'O',0322,')',0323,0215,'8',0250,'A','Y',' ',0242,0212,'(',',','P',013,020,0,0311,'<',0,'+',0257,0320,0264,'S','l',026,'I',023,'u',0313,0360,0252,'9',0333,0355,0365,0252,0372,026,0217,0345,'*',0335,0334,047,0357,017,'(',0247,0370,'}',0376,0265,0353,'^',026,0360,0350,0265,'U',0277,0273,'O',0337,'0',0314,'h',0177,0200,'z',0375,'k',0242,0225,'?',0264,0317,0205,0342,',',0363,0236,0370,'L',';',0323,0355,'?',0321,'~',0245,0257,015,'x','}','t',0310,05,0305,0300,06,0351,0307,0375,0360,'=','+',0241,0242,0212,0350,'>','0','(',0242,0212,0,'(',0242,0212,0,0312,0325,0364,033,'M','^','#',0346,015,0223,01,0362,0312,0243,0221,0365,0365,0257,'6',0327,'|',';','%',0251,'6',0367,0320,0206,'C',0367,'d',035,017,0320,0327,0257,'T','7','6',0260,'^','@',0320,0317,032,0311,033,'u',04,'R','i','5','f',']',':',0223,0247,'%','8',';','5',0324,0371,0257,'R',0321,0247,0261,'%',0327,0367,0220,0366,'a',0324,'}','k','2',0275,0247,'^',0360,0234,0266,'!',0346,0266,06,'k','n',0245,'q',0222,0243,0337,0324,'W',0235,'j',0236,036,030,'i',0254,0307,'=','L',0177,0341,0134,0263,0244,0343,0252,0330,0373,0274,0243,0211,'c','V',0324,'q','z','K',0371,0272,'?','^',0337,0221,0315,0321,'J',0312,'U',0212,0260,' ',0216,010,'4',0225,0221,0365,0341,'@','$',034,0216,015,024,'P',07,'E',0245,'k',0305,'U','a',0274,'`','W',0240,'r','y',037,'Z',0243,0254,0374,'<',0261,0327,'u','[','[',0253,'Y','R',0324,'I','*',0213,0217,0356,0262,023,0311,036,0207,025,0227,'Z','z','f',0261,'5',0213,0204,'r','^',03,0325,'O','o',0245,'k','N',0253,0216,0217,'c',0344,'s',0236,033,0215,'k',0326,0302,0253,'K',0252,0350,0375,';','?',0300,0372,'?','L',0263,0266,0323,0364,0313,'k','K','@',0242,0336,030,0325,'#',013,0323,0,'U',0272,0363,'/',014,'x',0270,0332,0242,0251,0220,0315,'f',0335,0263,0222,0237,'O',0360,0257,'H',0266,0271,0206,0356,05,0232,011,03,0306,0303,' ',0212,0352,'M','5','t','|',024,0341,'*','r','p',0232,0263,'D',0264,'Q','E','2','B',0212,')',031,0225,020,0263,034,'(',031,'$',0366,0240,012,'Z',0275,0364,032,'~',0233,'4',0327,0,'2',0355,'*',020,0377,0,031,'=',0253,0305,0256,'&',0260,0320,0355,010,0202,04,0205,013,022,0220,0306,'1',0311,'9',0256,0213,0305,0276,'$','[',0231,'d',0231,0230,0213,'X','x',0211,'?',0274,'}','~',0246,0274,0272,0356,0356,'[',0331,0314,0262,0266,'I',0350,';',01,0351,'X',0325,0251,0313,0242,0334,0372,',',0213,'%','x',0351,0373,'Z',0272,'S','_',0217,0227,0371,0213,'y','y','-',0365,0301,0232,'S',0311,0350,';',01,0351,'U',0350,0242,0271,'O',0322,'a',010,0302,'*',020,'V','H','(',0242,0212,012,012,0350,0264,'-',034,0261,027,'w',')',0362,0365,0215,'O',0177,'z',0203,'D',0321,0315,0313,0255,0314,0343,020,0251,0312,0251,0376,'#',0376,025,0352,'^',027,0360,0351,0275,0221,'o','.','S',026,0250,'~','U','?',0306,0177,0302,0266,0245,'N',0372,0275,0217,0220,0342,034,0363,0331,047,0205,0303,0277,'{',0253,0355,0345,0353,0371,026,0374,'+',0341,0335,0373,'5',013,0304,0371,'G','1','#',016,0277,0355,032,0355,'i',0,0,0,06,0,0350,')','k',0250,0370,020,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',0,'#','5',0313,'k',0276,022,0216,0350,'5',0305,0200,'X',0346,0352,'c',0350,0255,0376,06,0272,0232,0243,0252,0353,032,'~',0207,'c','%',0356,0245,'w',025,0265,0272,014,0227,0221,0261,'@',036,'/',0254,'h',013,';',0272,0311,031,0202,0351,'x',0344,'c',0363,0256,':',0346,0326,'k','I','L','s','!','V',0355,0350,'~',0225,0241,0343,'O',0215,0221,'j','z',0374,'C','K',0323,0320,0351,0320,022,036,'W',030,0222,'o','q',0350,'=','+','b',0312,0377,0,'K',0361,'N',0235,0346,'@',0341,0324,0216,'W',0243,'!',0254,'*','Q',0276,0261,'>',0223,047,0342,032,0270,';','R',0255,0357,'C',0361,'^',0236,'^','G','#','E','h',0352,'Z','D',0332,'y',0334,'~','x',0211,0341,0300,0376,'u',0235,0134,0307,0350,'t','1',024,0261,024,0325,'J','R',0272,'a','E',024,'P','l','[',0261,0324,047,0261,0233,'|','m',0220,'x','e','=',0305,'z',047,0205,0374,'X',0366,0347,0314,0267,'m',0321,0237,0365,0260,'1',0257,'0',0251,'m',0356,'%',0265,0231,'e',0211,0212,0260,0375,'j',0341,'7',07,0241,0341,0346,0371,'%',034,'|','y',0227,0273,'5',0263,0357,0344,0317,0247,'4',0355,'J',0337,'S',0265,'Y',0355,0337,' ',0375,0345,'=','T',0372,032,0271,'^','5',0341,0237,021,'I',023,'%',0324,015,0206,030,022,0307,0236,015,'z',0355,0215,0354,'Z',0205,0234,'w','0',0234,0243,0214,0375,017,0245,'v','F','J','J',0350,0374,0316,0275,011,0320,0250,0351,'T','V','h',0261,0134,0337,0214,'u','/',0262,'i',0242,0325,011,022,0134,'q',0307,'e',035,'k',0244,0256,'S',0306,0366,017,'5',0244,027,0210,011,0362,'I','W',0307,0241,0357,0371,0377,0,':','f','G',0214,0370,0232,0345,0236,0365,'m',0301,';','#','P','H',0367,'5',0207,']','n',0271,0244,'5',0356,047,0200,017,'9','F',010,'?',0304,'+',0226,0232,011,'m',0337,'l',0261,0262,'7',0241,025,0305,'Q','5',047,'s',0365,',',0207,023,0207,0251,0202,0204,')','=','b',0265,']','o',0327,0357,'#',0242,0212,'*',017,'l','+','W','F',0322,'M',0374,0236,'d',0240,0210,024,0363,0376,0321,0364,0250,0364,0255,'*','M','B','`',0314,012,0300,0247,0346,'o','_','a','W',0374,'Q',0342,'{','O',012,0351,0313,014,'*',0255,'t',0313,0210,0241,035,0275,0317,0265,'k','N',0237,'6',0257,'c',0346,'s',0354,0361,'a','"',0350,'P',0177,0274,0177,0207,0374,021,0336,'(',0361,'m',0257,0205,0355,'R','8',0321,'%',0273,' ','y','p','g',0200,'=','O',0265,'u',0336,017,0370,0355,0341,0315,'N',010,0255,'u','e',032,'L',0352,02,0345,0271,0213,0360,'n',0337,0215,'|',0313,'{','{','q',0250,0336,'I','u','u',')',0222,'i',016,'Y',0215,'W',0256,0263,0363,0226,0333,'w','g',0337,'6',0267,'v',0327,0266,0351,'=',0254,0361,0317,013,0214,0254,0221,0260,'e','#',0352,'*','j',0370,'g','B',0361,'f',0273,0341,0251,'|',0315,'#','S',0270,0266,031,0311,'E','l',0241,0372,0251,0342,0275,'G','D',0375,0242,0265,0253,'U','H',0365,'m','6',013,0305,035,'^','6',0330,0307,0372,'P','#',0351,'Z','+',0311,'t',0277,0332,027,0302,'7',0213,0213,0350,0257,0254,033,0276,0370,0274,0305,0374,0324,0223,0372,'W','Y','i',0361,'C',0301,'7',0201,'|',0257,022,'X',02,0335,04,0222,'l','?',0223,'b',0200,':',0352,'+','!','<','U',0341,0371,'@',')',0254,0330,0260,'>',0223,0257,0370,0322,'I',0342,0317,017,'B',0244,0311,0255,'X','(',036,0263,0257,0370,0320,06,0305,025,0307,0336,'|','T',0360,'E',0222,0261,0223,0304,'v','O',0267,0250,0205,0374,0303,0377,0,0216,0346,0271,015,'W',0366,0210,0360,0255,0247,0313,0247,0332,0337,0337,0267,'f',010,'#','_',0374,'x',0347,0364,0240,017,'_',0252,0327,0332,0215,0226,0231,'j',0367,'W',0327,'P',0333,'@',0203,'-','$',0256,024,017,0304,0327,0315,0272,0347,0355,017,0257,0336,0253,'G',0245,'Y','[',0330,0251,0350,0354,'w',0260,0376,0225,0345,0372,0327,0210,0365,0217,021,0134,'y',0372,0266,0243,'=',0333,0216,'G',0230,0334,'/',0320,'t',024,01,0364,'?',0213,0276,'?',0350,0332,'b','=',0276,0201,037,0366,0215,0317,'A',')',0342,' ','}','}',0353,0300,'<','I',0342,0355,'s',0305,0227,0315,'u',0253,0337,0311,'9',047,0345,0217,'8',0215,07,0242,0257,'A','X','t','P',01,'W','4',0315,'V',0367,'H',0274,'K',0253,')',0332,')',024,0366,0350,0336,0304,'w',024,0232,'v',0233,'{',0253,0336,0245,0235,0205,0264,0227,027,016,'p',0261,0306,0271,'&',0276,0201,0370,'s',0360,'*','+',037,'+','T',0361,'Z',0244,0267,' ',0206,0216,0310,034,0252,'z','n','=',0317,0265,0,'3',0303,'m',0251,'x',0213,0302,0303,'U',0271,0322,0245,0206,03,0362,0261,'e',0371,'_',0375,0240,':',0343,0336,0261,0265,']',05,0241,015,'=',0240,'-',037,'t',0356,'>',0225,0364,'b','C',034,'p',0210,0221,025,'c','Q',0264,'(',030,0,'z','b',0271,'-','{',0302,'+',' ','k',0235,'9','@','~',0255,017,'c',0364,0377,0,012,0316,'t',0324,0317,'K','.',0315,'+',0340,'*','s','S','z','u',']',037,0365,0334,0360,'*','+',0256,0326,'<','>','%','g','x','S',0313,0270,'S',0363,'!',030,0315,'r',0222,0305,'$','2',024,0221,012,0260,0352,015,'r','J','.','.',0314,0375,'+','.',0315,'(','c',0351,0363,'R','z',0365,']','W',0365,0334,'e',024,'Q','H',0364,'M',015,032,0363,0354,'z',0202,022,'p',0217,0362,0265,'{',027,0202,'u',023,035,0324,0226,',',0337,'$',0243,'r',017,'q',0377,0,0326,0257,015,07,07,'"',0275,037,0303,'Z',0201,'V',0323,0357,013,'`',0253,'.',0363,0370,0340,0326,0364,'%',0253,'G',0304,'q','v',021,'.','L','J','[',0350,0377,0,'5',0372,0236,0315,'H',0350,0262,'!','G','P',0312,'F',010,'#',0255,'-',025,0322,'|','I',0310,'j',0336,013,'Y','d','i',0264,0347,'X',0311,0344,0304,0335,'?',03,0332,0271,0351,0374,'#',0252,'t','{','!',' ',036,0204,032,0365,012,'(','j',0373,0225,031,'J','.',0361,'v','g',0224,0177,0302,'/',0250,016,'?',0263,033,037,0356,0212,'r',0370,':',0376,'C',0377,0,' ',0305,037,0357,05,0257,'U',0242,0247,0226,'=',0215,026,'&',0262,0332,'o',0357,'g',017,0244,'x','%',0326,'E','{',0375,0211,022,0377,0,0313,'$',0357,'V',0374,'W',0360,0343,0303,0236,'.',0261,020,'^',0331,0254,'S','"',0355,0212,0346,020,026,'H',0377,0,036,0343,0330,0327,'[','E','Q',0223,'m',0273,0263,0345,'O',027,'|',013,0361,026,0203,0276,'}',',',0177,'j','Z',016,0177,'v','1',' ',036,0353,0337,0360,0257,'.',0232,031,'m',0345,'h',0246,0215,0343,0221,'N',031,035,'H',' ',0373,0203,'_','~','W',';',0342,037,02,0370,'o',0305,0,0235,'W','I',0267,0232,'l','`','N',020,',',0203,0376,04,'9',0240,'G',0304,'T','W',0321,032,0377,0,0354,0343,'k','.',0351,'4','-','U',0340,'n',0321,0134,0215,0313,0371,0216,'k',0315,'5',0257,0203,'~','6',0321,0213,'1',0322,'Z',0362,'!',0377,0,'-',',',0330,'I',0307,0323,0257,0351,'@',034,025,025,'v',0343,'F',0325,',',0311,027,':','m',0344,'$','u',022,0300,0313,0217,0314,'U','2',012,0234,020,'A',0364,'4',0,0224,'Q','E',0,024,'R',0252,0263,034,'(','$',0372,012,0277,'k',0241,'j',0367,0254,026,0327,'K',0275,0234,0236,0202,'8',031,0277,0220,0240,014,0372,'+',0320,0364,'_',0202,0236,'6',0326,012,0263,0351,0253,'a',021,0376,';',0267,010,'q',0376,0350,0311,0375,'+',0323,'4',017,0331,0323,'M',0267,0333,'&',0271,0251,'I','v',0343,0254,'p',015,0211,0371,0365,0240,017,0235,0255,'m','.','/','n',022,0336,0326,011,047,0231,0316,026,'8',0324,0263,037,0300,'W',0254,'x','K',0340,036,0271,0254,04,0270,0326,0344,0376,0314,0266,'<',0354,0306,0351,'H',0372,'t',025,0364,'.',0201,0340,0375,03,0303,'1',0355,0322,'t',0273,'{','f','?','z','E','A',0275,0276,0255,0326,0267,'(',03,0235,0360,0267,0202,'4',037,07,0331,0210,'4',0233,'$','G',0307,0317,';',0215,0322,'9',0365,'-',']',025,024,'P',01,'E',024,'P',06,'&',0267,0341,0333,'}','Y',013,0256,'"',0271,03,0211,0,0353,0354,'k',0313,0274,'A',0341,0307,022,030,'.',0243,'1','N',0277,'u',0307,'C',0376,'"',0275,0262,0251,0352,':','e',0266,0251,'l','a',0270,0214,'7',0367,'[',0272,0237,'j',0231,'E','I','Y',0233,0341,0361,025,'p',0365,025,'Z','N',0315,037,'3','^','Y',0315,'e','9',0212,'U',0301,0354,'{',021,'U',0353,0325,'|','I',0341,'W',0264,0314,'w',021,0371,0266,0354,'~','I','@',0351,0365,0364,'5',0347,'Z',0226,0225,'6',0237,'&','N','Z','#',0321,0307,0365,0256,'I',0323,'p',0364,'?','F',0311,0363,0352,'X',0344,0251,0324,0367,'j','~',017,0323,0374,0214,0372,0353,0374,'6',0373,0264,0275,0277,0335,'r','+',0220,0256,0263,0303,037,0361,0341,047,0373,0377,0,0322,0235,'/',0215,023,0305,021,'O','/','o',0263,'G',0320,'4','Q','E','v',037,0232,05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',021,0313,'o',014,0343,023,'C',034,0203,0321,0324,032,0313,0271,0360,0256,0201,'w',0237,'?','G',0262,0223,'>',0260,0212,0330,0242,0200,'9','w',0370,'s',0340,0371,'>',0367,0207,0254,'?',0357,0320,0245,'O',0207,'^',020,0214,0202,0276,037,0260,0343,0376,0231,012,0351,0350,0240,014,0233,0177,014,'h','V',0230,0362,'4',0213,'8',0361,0351,010,0255,'8',0341,0212,025,0333,024,'H',0203,0321,'T',012,'}',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,0311,0241,0216,'x',0232,')','Q',']',030,'`',0253,016,015,'p','^','"',0360,'y',0205,'^','[','H',0314,0326,0307,0357,'D','F','J',0377,0,0210,0257,'@',0242,0206,0256,'4',0334,']',0326,0347,0316,'z',0207,0206,0335,'d','/','i',0202,0247,0252,'1',0344,'}','+','[','F',0262,'{','+',021,024,0237,0353,030,0356,' ','W',0256,'j','>',027,0323,0265,027,'2',024,'h','e','=','^','>','3',0365,035,'*',013,037,07,0330,'Y',']',',',0345,0344,0230,0241,0312,0253,0343,0,0372,0326,'Q',0245,030,0312,0350,0365,'q','9',0316,'+',023,0206,'X','z',0256,0351,'u',0352,0375,'O',0377,0331,0377,0341,015,'7','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0,'<','?','x','p','a','c','k','e','t',' ','b','e','g','i','n','=','"',0357,0273,0277,'"',' ','i','d','=','"','W','5','M','0','M','p','C','e','h','i','H','z','r','e','S','z','N','T','c','z','k','c','9','d','"','?','>',' ','<','x',':','x','m','p','m','e','t','a',' ','x','m','l','n','s',':','x','=','"','a','d','o','b','e',':','n','s',':','m','e','t','a','/','"',' ','x',':','x','m','p','t','k','=','"','X','M','P',' ','C','o','r','e',' ','4','.','4','.','0','-','E','x','i','v','2','"','>',' ','<','r','d','f',':','R','D','F',' ','x','m','l','n','s',':','r','d','f','=','"','h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#','"','>',' ','<','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n',' ','r','d','f',':','a','b','o','u','t','=','"','"',' ','x','m','l','n','s',':','x','m','p','M','M','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/','"',' ','x','m','l','n','s',':','s','t','E','v','t','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#','"',' ','x','m','l','n','s',':','d','c','=','"','h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/','"',' ','x','m','l','n','s',':','G','I','M','P','=','"','h','t','t','p',':','/','/','w','w','w','.','g','i','m','p','.','o','r','g','/','x','m','p','/','"',' ','x','m','l','n','s',':','x','m','p','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','"',' ','x','m','p','M','M',':','D','o','c','u','m','e','n','t','I','D','=','"','g','i','m','p',':','d','o','c','i','d',':','g','i','m','p',':','e','5','9','4','4','0','5','e','-','8','d','f','0','-','4','a','b','a','-','a','2','d','a','-','c','d','f','c','8','0','0','2','8','5','9','e','"',' ','x','m','p','M','M',':','I','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','f','c','4','3','7','6','9','5','-','f','e','5','5','-','4','b','c','f','-','9','4','2','3','-','8','4','f','9','d','e','b','2','c','9','1','7','"',' ','x','m','p','M','M',':','O','r','i','g','i','n','a','l','D','o','c','u','m','e','n','t','I','D','=','"','x','m','p','.','d','i','d',':','8','0','6','1','1','f','0','9','-','1','5','8','1','-','4','b','9','c','-','b','4','5','8','-','9','8','4','f','e','e','c','e','1','2','6','0','"',' ','d','c',':','F','o','r','m','a','t','=','"','i','m','a','g','e','/','j','p','e','g','"',' ','G','I','M','P',':','A','P','I','=','"','2','.','0','"',' ','G','I','M','P',':','P','l','a','t','f','o','r','m','=','"','L','i','n','u','x','"',' ','G','I','M','P',':','T','i','m','e','S','t','a','m','p','=','"','1','6','7','7','0','1','1','9','9','7','6','6','7','0','8','1','"',' ','G','I','M','P',':','V','e','r','s','i','o','n','=','"','2','.','1','0','.','3','0','"',' ','x','m','p',':','C','r','e','a','t','o','r','T','o','o','l','=','"','G','I','M','P',' ','2','.','1','0','"','>',' ','<','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','r','d','f',':','S','e','q','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','9','2','f','7','c','d','9','7','-','d','a','8','4','-','4','9','3','e','-','b','e','0','8','-','b','c','6','3','2','3','4','5','b','d','7','2','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','2','-','1','2','T','2','0',':','5','9',':','4','9','+','0','0',':','0','0','"','/','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','9','5','5','4','6','6','0','d','-','7','8','b','4','-','4','e','b','7','-','9','1','c','4','-','9','e','d','0','4','3','9','7','0','0','e','8','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','2','-','2','1','T','2','0',':','3','9',':','5','7','+','0','0',':','0','0','"','/','>',' ','<','/','r','d','f',':','S','e','q','>',' ','<','/','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','/','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n','>',' ','<','/','r','d','f',':','R','D','F','>',' ','<','/','x',':','x','m','p','m','e','t','a','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','<','?','x','p','a','c','k','e','t',' ','e','n','d','=','"','w','"','?','>',0377,0342,02,0260,'I','C','C','_','P','R','O','F','I','L','E',0,01,01,0,0,02,0240,'l','c','m','s',04,'0',0,0,'m','n','t','r','R','G','B',' ','X','Y','Z',' ',07,0347,0,02,0,025,0,024,0,022,0,030,'a','c','s','p','A','P','P','L',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,0366,0326,0,01,0,0,0,0,0323,'-','l','c','m','s',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,015,'d','e','s','c',0,0,01,' ',0,0,0,'@','c','p','r','t',0,0,01,'`',0,0,0,'6','w','t','p','t',0,0,01,0230,0,0,0,024,'c','h','a','d',0,0,01,0254,0,0,0,',','r','X','Y','Z',0,0,01,0330,0,0,0,024,'b','X','Y','Z',0,0,01,0354,0,0,0,024,'g','X','Y','Z',0,0,02,0,0,0,0,024,'r','T','R','C',0,0,02,024,0,0,0,' ','g','T','R','C',0,0,02,024,0,0,0,' ','b','T','R','C',0,0,02,024,0,0,0,' ','c','h','r','m',0,0,02,'4',0,0,0,'$','d','m','n','d',0,0,02,'X',0,0,0,'$','d','m','d','d',0,0,02,'|',0,0,0,'$','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,'$',0,0,0,034,0,'G',0,'I',0,'M',0,'P',0,' ',0,'b',0,'u',0,'i',0,'l',0,'t',0,'-',0,'i',0,'n',0,' ',0,'s',0,'R',0,'G',0,'B','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,032,0,0,0,034,0,'P',0,'u',0,'b',0,'l',0,'i',0,'c',0,' ',0,'D',0,'o',0,'m',0,'a',0,'i',0,'n',0,0,'X','Y','Z',' ',0,0,0,0,0,0,0366,0326,0,01,0,0,0,0,0323,'-','s','f','3','2',0,0,0,0,0,01,014,'B',0,0,05,0336,0377,0377,0363,'%',0,0,07,0223,0,0,0375,0220,0377,0377,0373,0241,0377,0377,0375,0242,0,0,03,0334,0,0,0300,'n','X','Y','Z',' ',0,0,0,0,0,0,'o',0240,0,0,'8',0365,0,0,03,0220,'X','Y','Z',' ',0,0,0,0,0,0,'$',0237,0,0,017,0204,0,0,0266,0304,'X','Y','Z',' ',0,0,0,0,0,0,'b',0227,0,0,0267,0207,0,0,030,0331,'p','a','r','a',0,0,0,0,0,03,0,0,0,02,'f','f',0,0,0362,0247,0,0,015,'Y',0,0,023,0320,0,0,012,'[','c','h','r','m',0,0,0,0,0,03,0,0,0,0,0243,0327,0,0,'T','|',0,0,'L',0315,0,0,0231,0232,0,0,'&','g',0,0,017,0134,'m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'G',0,'I',0,'M',0,'P','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'s',0,'R',0,'G',0,'B',0377,0333,0,'C',0,03,02,02,03,02,02,03,03,03,03,04,03,03,04,05,010,05,05,04,04,05,012,07,07,06,010,014,012,014,014,013,012,013,013,015,016,022,020,015,016,021,016,013,013,020,026,020,021,023,024,025,025,025,014,017,027,030,026,024,030,022,024,025,024,0377,0333,0,'C',01,03,04,04,05,04,05,011,05,05,011,024,015,013,015,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,0377,0302,0,021,010,02,'X',02,'X',03,01,021,0,02,021,01,03,021,01,0377,0304,0,035,0,01,0,02,02,03,01,01,0,0,0,0,0,0,0,0,0,0,06,07,05,010,01,03,04,02,011,0377,0304,0,034,01,01,0,01,05,01,01,0,0,0,0,0,0,0,0,0,0,0,05,01,02,03,04,07,06,010,0377,0332,0,014,03,01,0,02,020,03,020,0,0,01,0332,0220,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,07,0311,0211,'!',04,'0',0213,030,03,030,'x',0216,017,'a',0222,'3',0304,0240,0230,023,0223,'8','}',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0305,025,'1','Q',025,'y',014,':','@',0,0,0,07,'a',',',',',0362,0334,'-',0303,'8','r',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'y',0212,'|',0240,'J',0204,0360,0,0,0,0,0,0,0,017,'I','j',0227,0361,'t',0236,0360,0,0,0,016,0263,0306,'|',035,0247,047,0321,0334,'v',0200,0,0,0,0,0,0,0,0,0,'b',0215,'w','5',0304,0213,0,0,0,0,0,0,0,0,0,03,':','l','A',0261,0346,'|',0344,0,01,0360,'V',0204,'$',0353,0,034,0237,'f','D',0367,0222,'B','n','z','@',0,0,0,0,0,0,0,0361,032,0332,'k',')',0204,0,0,0,0,0,0,0,0,0,0,0,'d','M',0217,'6','x',0313,0,016,0262,0242,'#',07,']',0233,'X','=','o','m',0215,0305,'?',0350,0277,'C',047,0223,0317,0344,'r',0300,0367,'d',0216,'V',0200,'f',0213,0244,0355,0,0,0,0,0,0,07,05,'2','i',0371,022,0,0,0,0,034,0231,'b','F','d',0214,0231,0311,0216,'1',0244,'p',0303,03,0200,0,0,0,014,0361,0266,0345,0366,'v',037,05,'F','E',0217,'.',')','z',0346,'7',0275,'x',')','&',0,0346,0224,0366,'4',0275,'7',0307,0344,0362,'y',0371,'V',0347,'4',0366,'f',0204,0237,0226,'H',0,0,0,0,0,016,014,'1',0247,0245,022,'|',0200,0,0,0344,0365,0226,'q','k',026,'I','<','3','g','`',0,03,0340,0304,0220,'B',0267,'*',0302,0254,'1',0307,0,0,0,'9','-',0343,'r',0310,'a',024,'<',0270,0245,0253,0230,0336,0365,0340,0244,0240,0,0,06,'V',0350,'+','*','W',0347,0256,0372,0333,'~',0235,0200,0,0,0,0,016,012,0320,0322,022,'*',0,0,034,0235,0245,0266,'_',0245,0304,'e',0,0,0,0,0,0,'x',0312,0210,0241,'J','`',0362,0200,0,07,0240,0331,02,'h','y',0261,'J',0327,021,0275,0353,0301,'I','P',0,0,01,0355,'G',0332,'R',0377,0,'6',0253,'m',0344,'e',0200,0,0,0,0,0340,0327,0343,'N',017,' ',0,0,'{',0215,0203,'6','P',0227,0200,0,0,0,0,0,0,0,'#',0246,0271,032,0340,'b','@',07,'y',0261,'d',0350,0363,'b',0224,0256,'c','{',0326,'>',0222,0300,0,0,03,0352,0224,0235,0356,'r',011,026,0357,';',0366,027,0311,0366,0,0,0,0,'>','M','X','5',0134,0370,0,0,'v',0233,02,'m','I','%',0,0,0,0,0,0,0,0,0,06,034,0325,0363,'[',0317,031,0334,'l','I','=','<',0370,0344,0353,0230,0316,0365,0216,0244,0270,0,0,0,0372,0245,0263,0275,0316,'C','"',0335,0347,'b',0303,',','P',0,0,0,01,0362,'j','a',0254,047,0,0,'r','O','M',0314,',',0240,0,0,0,0,0,0,0,0,0,0,04,' ',0323,0242,'f','X',047,0237,034,0225,'s',031,0336,0261,0324,0230,0,0,0,037,'T',0266,'{',0271,0307,0244,033,0274,0370,'O',0313,' ',0344,0,017,'5',025,0305,0264,0302,')',0350,',',0213,0253,0233,0255,'x','5','`',0325,'C',0200,0,'>',0315,0224,'6',0304,0366,0,0,0,0,0,0,0,0,0,0,0,07,05,'Z','B',0216,0214,'r','5',0314,'o','z',0306,0333,'2',0,0,0,'>',0351,'l',0367,'w',0216,'g',0367,'<',0,0261,'K',014,0,0,' ',0226,0326,0261,0267,037,026,0345,0346,0354,'_','E',0201,'u','`','w',']',0246,047,0300,0,036,0363,'t',0213,0310,0344,0,0,0,0,0,0,0,0,0,0,0,'8','+',022,014,'t','c',0220,0256,'c','{',0326,'6',0331,0240,0,0,01,0366,0262,'}',0271,0306,0263,0333,0236,017,0222,0312,047,0240,0,0,'+','{','m',0257,0255,'V','1','_','J','H','6','<','$',0253,'o',0227,0366,']',0253,0204,'(','K',0356,0205,'V',0240,'r','f',0315,0354,',',0300,0,0,0,0,0,0,0,0,0,0,0,034,025,0231,04,':','1',0310,'W','Q',0275,0347,031,'l',0330,0,0,0,0373,'Y','?',0335,0343,031,0335,0277,013,0364,'Y',0344,0334,0,0,0,0256,'-',0266,0275,0262,0352,0242,'/',0351,0356,0212,0346,0366,'V',':','q',0265,0310,'s','[','>',037,0344,0253,'k','Z','N',0373,0274,0246,'h',0337,0202,0301,0,0,0,0,0,0,0,0,0,0,0,0,'+','R',02,'t',0331,0277,']','F','w',0234,']',0263,0200,0,0,03,0261,0216,0300,0335,0342,0371,0275,0277,017,0366,'Z',0204,0304,0,0,0,025,0275,0212,0372,0226,0325,'Q','_','N',0371,0253,0262,'9','R','I',0223,0304,'L',0367,'x',0377,0,'u',0372,030,'B',0220,0276,0355,0307,0255,'l',0300,0,0,0,0,0,0,0,0,0,0,0,02,0267,'+',0363,0246,0315,0352,0352,'3',0274,0342,0355,0235,0,0,0,035,0214,'v',016,0367,024,0315,'m','x',0256,0302,0330,'%',0200,0,0,0,025,0255,0227,'@',')',0212,0257,0212,0372,'c',0303,']',0360,07,0255,0241,'8',0333,0343,0371,0275,0237,017,0364,'X',027,'V',0303,0272,0356,0300,0,0,0,0,0,0,0,0,0,0,0,0256,'J',0364,0352,0263,'v',0272,0215,0357,'8',0253,047,0200,0,0,07,'k',025,0203,0275,0304,0363,';','^','3',0254,0366,0227,0370,0,0,0,0,0255,0354,0255,'}','L','u',0224,'W',0322,'x',0352,0312,0,07,'*','H',0362,'x',0231,0236,0347,' ',0357,0311,035,0230,0255,'m','[',0253,0234,0255,'@',0,0,0,0,0,0,0,0,0,02,0274,'+',0243,0252,0315,0312,0356,'7',0274,'b','l',0364,0,0,0,03,0265,0206,0303,0336,0342,'9','}',0257,037,0320,'k',0311,025,'?','G',0211,010,0,0,0,05,'w','m','+',0253,'m',0255,'#','>',0216,0306,'R','d',0,0,0364,0264,0346,0273,'<',0233,'?',0265,0317,0376,0353,'l',0376,0267,0330,'w',0273,'@',0,0,0,0,0,0,0,0,01,'_',025,0301,0327,'f',0335,'w',033,0336,'1',026,'z',020,0,0,01,0334,0303,'a',0357,0360,0374,0266,0317,0221,0363,032,0350,'A',0301,0261,'f',0344,034,0200,0,0,02,0275,0266,0225,0305,0266,0326,0361,0237,'D','b','i','>',0,0,016,'L',0335,0336,'Z','m',0273,0307,'=',0231,'a','2',0253,0355,'K',0256,0220,']','h',0,0,0,0,0,0,0,0,' ','%','j','u',0331,0267,'^','F',0367,'l','=',0236,0214,0,0,0,'w','0','X',0233,0374,';','+',0263,0344,0374,'f',0270,020,0340,017,'I',0372,':','K',0200,0,0,01,06,0265,'W',0333,'d',032,'?',0267,'F',0261,0373,0220,0,0,01,0333,'L','3',015,0216,'c',047,0334,0346,'=',0265,0305,'e',']','t',0352,0352,0375,0,0,0,0,0,0,0,01,03,'+','C',0252,0315,0252,0366,'7',0273,'a',0254,0364,0200,0,0,03,0275,0257,'b','H','p',0334,0246,0307,0225,0367,0220,0323,'U',0200,0,0330,0303,'r',0,0,0,01,0211,0245,0324,036,';','z',0361,0315,0327,032,035,0363,0312,0335,0,0,0,03,')','X','9',0316,0347,031,0310,0347,0363,'R',012,0326,0324,0272,0354,0255,'@',0,0,0,0,0,0,'A','J',0310,0353,0263,'f',0275,0215,0356,0330,'[','=','(',0,0,0,0357,'k','X',0262,034,'3',047,0261,0345,0362,'E',0310,'}',0237,0233,0304,'l',0,'d',017,0322,0223,'6',0,0,0,'R',0246,0256,'Z',0330,'+','m',0361,0341,0236,0256,'t','{',0337,0225,0272,0,0,0,07,'e','1',0313,0266,'9',0234,0253,'o',0226,0367,0335,0212,0305,0272,0351,0355,0325,0372,0,0,0,0,0,01,010,'*',0363,0256,0335,0212,0372,'3',0272,0341,',',0364,0340,0,0,03,0320,0325,0261,'d','8','^','K','c',0314,0345,0213,0214,0367,0203,'Z',015,'B',0,03,'p',015,0224,0,0,01,0301,0243,05,'&','Z',0366,'_','y',0323,026,'7',07,0247,0257,0264,0273,0227,0225,0272,0,0,0,0,0312,'V',012,'u',0271,0306,'r',031,0374,0336,'z',0265,0265,'.',0256,'^',0265,0,0,0,0,01,012,'*',0323,0256,0335,0212,0376,'3',0272,'`',0354,0365,0,0,0,03,0322,0324,0261,'d','x','V','G','?',0233,0315,027,021,0354,0,0305,0237,0232,0306,' ',0,'X',0207,0350,'q',0364,0,0,030,0243,0363,'8',0360,0202,0324,0307,0236,0364,0246,0277,'M',0222,0220,'=',036,0331,0206,0267,0322,0200,0,0,0,'>',0351,'d',0273,'?','5',0225,0356,'r',0276,0353,0260,0330,0227,']','?',0272,0277,'@',0,0,0,020,0302,0254,':',0355,0317,'_',0306,'w','<',025,0236,0250,0,0,0,'z',0232,'v',',',0217,011,0310,'g',0363,0271,0342,0340,'=','@',0,'i',0261,0256,0200,03,0350,0375,037,'&','`',0,01,'H',0232,'4','p',01,'`',0343,0330,0330,'j','k',0375,0253,025,0323,0352,'P',0375,'~',0235,0361,'[',0300,0,0,0,031,':',0302,'N',0267,'8',0316,'G','?',0231,0316,'V',0266,0255,0325,0314,'V',0240,0,0,020,0362,0251,':',0355,0317,0,0214,0356,'X',033,'=','X',0,0,0,0365,'4',0254,'i',036,021,0357,0317,0347,0344,'E',0276,'w',0200,0,'+','C',0363,0334,0340,0,'m',0341,0263,0,0,01,0246,'f',0273,0200,017,'a',0372,'S','D',012,0333,'b','T',0246,'3',07,0251,0201,0351,0366,0257,05,'%',0,0,0,0,037,'t',0262,'Y',0237,0233,0313,'w','9','W','u',0330,',','+',0253,'`',']','w',0330,0,02,'"','T',0347,']',0271,0240,021,0275,0313,03,0217,0326,0,0,0,017,'[','F',0306,0221,0340,0376,0354,0360,'2','r',0334,';','@',0,03,0254,0374,0330,'"',0300,02,0340,'7',0320,0,01,0301,0371,0312,'A',0200,05,0266,'o',0301,0311,016,0266,0225,0205,0266,0370,'l',0334,0205,0351,'v','8',0336,'?','q',0300,0,0,0,0,0311,'V',032,'u',0271,0306,'r','Y',0374,0276,'n',0265,0265,'.',0256,'j',0265,0,'D',0312,0230,0352,0267,'4',06,'7',0270,'`','1',0372,0340,0,0,01,0354,0254,'}',0215,'#',0301,0375,0271,0240,0345,0205,0260,'v',0,0,0,032,'b','k',0310,0,0313,037,0246,0307,0240,0,014,'9',0371,0222,'t',0200,015,0260,'6',0220,03,0301,'E','W','m',0261,0232,'0',032,0276,0376,017,0253,0327,0272,033,' ',0,0,0,017,0252,'[',',',0317,0316,'%',0273,0234,0247,0272,0355,'{',06,0352,0330,'W',']',0366,'E','J',0220,0352,0267,',',012,'7',0270,'G',0361,0372,0360,0,0,01,0355,0254,'u',0215,'#',0301,0375,0231,0241,'&','%',0252,'}',0,0,0,02,0205,'4',0224,0,017,0321,0222,'v',0,05,'b','~','}',034,0,'r','o',0311,'m',0,016,010,'E',0264,0255,'-',0267,035,0212,'f',011,0245,0332,0360,0366,0372,'0',0,0,0,0,0310,0326,036,'s',0267,0305,0362,0233,036,'g','3','T',0322,0352,0326,0365,0257,'U',0271,'`','Q',0335,0272,'=',0213,0330,0200,0,0,017,'u','c','l','i',036,015,0353,0315,015,'7','-',03,0220,0,0,0,010,'y',0371,0270,'p',0,'7','l',0276,'@',0,0327,0343,'K','N',0,'9','?','M',014,0370,0,03,027,'E','U','m',0261,0353,'o',0211,0351,'u','X',0206,016,0231,0363,'[',0200,0,0,0,037,'T',0262,'M',0177,'7',0230,0310,0362,0376,0354,0272,0334,'S','$',016,'7',0267,'G','q','{',' ',0,0,01,0357,0254,']',0215,'%',0301,0275,'Y','b',047,0245,0224,'r',0,0,0,0,':',017,0314,'c',026,0,'6',0250,0332,0240,0,'5','P',0325,'`',01,0226,'?','N',0216,0300,0,0,0371,'+',0353,'i',']',0333,'n',033,'[',0326,0301,'4',0373,'7',0216,0262,0200,0,0,0,01,0355,'G','L',0367,'y','N',013,'_',0330,0307,'1','{','`',0,0,01,0220,0254,'U',0215,'%',0301,0275,'9','b','l','2',0305,0,0,0,0,0,017,0316,'r',06,0,'6',04,0335,'0',0,'4',0324,0327,'P',01,'9','?','F',0300,0,0,01,035,0242,0254,'S',015,0217,'b',033,037,0325,0243,'X',0372,'/',0315,'n',0,0,0,0,0,0,0,0,'2','5',0210,0261,'d',0270,'7',0253,',',']',0220,'O',0300,0,0,0,0,0,'h','y','M',0200,013,0220,0337,0,0,'4',0214,0241,0300,05,0232,'~',0203,0200,0,0,0,'t',025,0271,07,'0',0332,'~',0232,017,0245,0330,0374,025,0233,0,0,0,0,0,0,0,014,0215,0320,0366,'4',0227,06,0364,0344,0214,0263,0211,0310,0,0,0,0,0,01,0244,0305,010,0,',',0323,0364,034,0,015,027,')','0',01,'o',033,0352,'r',0,0,0,0,'#','e','X','b',0261,0344,0210,'G',0365,'(',0276,036,0225,0327,'v','@',0,0,0,0,0,01,0222,0272,026,0305,0222,0340,0376,0254,0221,0266,0231,'3',0,0,0,0,0,0,06,0233,032,0350,0,',',023,0364,'L',0,015,026,')','@',01,'o',0233,0352,0,0,0,0,0,0363,0225,0241,013,'1','z',0223,0320,']',036,0321,0215,0254,0360,0,0,0,0,0,'2','W','C','X',0322,0134,023,0325,0222,'>',0327,'%',0300,0,0,0,0,0,0,032,'l','k',0240,0,0260,'O',0321,'0',0,'4',0210,0242,0,05,0234,'~',0203,0,0,0,0,0,0,0214,025,'i',0215,0262,0261,'(',0356,0243,024,0303,0323,0272,0356,0310,0,0,0,0,02,'S',0237,0237,0315,0244,'x',0334,0212,0332,'[',0367,'W',0274,0,0,0,0,0,0,03,'J',012,010,0,'Y','g',0350,'H',0,032,'f','k',0270,0,0235,0237,0243,07,' ',0,0,0,0,0,'<',0245,'b','C',0314,'^',0267,0247,0256,0264,';',0267,'K','8',0,0,0,0,'v','1','L','3',0362,0311,'F',0347,'4',0312,'W',035,0243,'}',0322,'j',0324,0,0,0,0,0,0,'h',0211,'L',0200,013,0210,0337,' ',0,'5','H',0325,0200,01,0231,'?','N',017,0260,0,0,0,0,0,02,',','T','G',0315,'+','[',0305,'}',011,0210,0266,'|',0,0,0,0,0,0312,0323,0316,'N',0267,0270,0257,0277,'<','4',0316,0345,0231,'u',0336,0223,0220,0,0,0,0,0,0374,0353,'+',0360,01,0177,033,0254,0,06,0275,0232,'^',0,'9','?','N',014,0330,0,0,0,0,0,010,0271,'Q',0235,'d','J','?',0254,'C',0265,0372,'g',0,0,0,0,0,0,';','-',0301,'0',0317,0312,'%',';',0374,0347,0336,0266,0321,0276,0262,0232,0327,0220,0,0,0,0,':',0217,0314,'s',020,0,'6',0230,0332,0340,0,'*',0303,0363,0374,0340,03,0223,0177,0213,'T',0,0,0,0,0,'"',0345,'F','u',0322,0261,030,0376,0263,017,0301,0322,0270,0,0,0,0,0,0,0,0313,0323,0314,'N','d','8',0317,0277,'<','<',0322,0352,0331,'G',0250,0,0,0,0,'E',017,0315,'`',0,'7',0134,0277,'@',0,0302,037,0231,'g','P',07,'&',0332,0233,'<',0,0,0,0,0,0214,025,031,0325,'J',0303,0343,0372,0354,'G',07,'F',0340,0,0,0,0,0,0,0,016,0333,'u',0346,0233,034,0202,'K','#',0340,0262,025,'Z','D',0230,0344,0,0,0,024,'Y',0243,0340,0,'~',0212,026,0,0,034,037,0233,0344,'0',0,0134,'f',0370,0200,0,0,0,01,030,'*','3',0252,0227,'C','#',0373,04,'O',07,'B',0,0,0,0,0,0,0,0,0,0317,'<','d',0342,'G',0216,'z',0263,0350,0316,0313,034,0355,0,0,0,'4',0344,0327,020,01,0222,'?','N',017,'P',0,034,032,0134,'k',0361,0300,06,'@',0375,'6','=',0300,0,0,0,021,0222,0242,':',0251,'t','*',';',0261,0305,'p',0373,0360,0,0,01,0350,'j',0330,';',0374,'K',037,0216,'v',031,0247,0323,0372,'k',0266,0,0,0,0,0346,0224,0364,0322,'>','o',0267,0306,'s',0333,0336,'K','3','U',0254,'f',016,'@',0,037,07,0346,0361,017,0,026,0311,0277,'`',0,01,'D',0232,'D','p',01,0311,0274,0345,0330,0,0,0,010,0311,'Q',035,'4',0276,023,035,0331,0242,0370,'}',0330,0,0,0,0355,'b',0261,'w',0370,'f','[','g',0311,0360,'y','5',0367,0240,0261,0375,0237,012,0365,0340,0,0,0,016,'i','B',0222,'k',0271,0324,0316,'O',0224,0372,0257,0301,'d',0325,'8','>',0200,0,0257,017,0316,0363,0200,01,0266,0246,0317,0200,0,06,024,0374,0320,'<',0200,02,0353,'7',0240,0344,0,0,04,'d',0250,0216,0232,'d',0203,'F',0366,0210,0326,'/','p',0,0,0,'>',0251,'m',0203,0275,0305,0363,0273,'~',026,0317,'=','e','^','x',0355,'E','#','z','4','?',027,'Z',0370,0256,'@',0,0,0,0,0310,'R',016,'{',0277,0304,'2','[','P',0322,0302,0323,'=',' ',03,'P','M','i',0,037,'G',0350,0271,';',0,0,016,015,017,')',0300,01,0351,'?','I',0211,'(',0,0,'F',0212,0204,0351,0267,'$',022,';',0266,'G','1','{','@',0,0,01,0312,0223,0255,0256,'I','$',0336,0346,0366,021,'c',03,0300,'U','D','l',0306,'i',0316,'A','t',';','^','6',0371,0320,0,0,0,0,0355,0267,'^','g',0237,0217,0311,0244,0274,036,'R',0253,'h',0315,034,0236,03,0363,0134,0301,0,011,0341,0372,',','}',0,0,0,0242,0315,' ','8',0,033,'@','m',0240,0,02,'4','T',047,'E',0271,'`','q',0335,0272,'=',0213,0330,0200,0,0,01,'2',0330,0346,'r',0331,016,'O','4','-','3',0220,017,0222,02,'W','G',0237,036,'H',0134,'g','[',0215,0333,0321,'>','k','P',0,0,0,0,0316,0335,0343,0247,'R',034,'c',0333,0233,'N',0314,'&',0306,0272,0232,'n','p',0,'6',0330,0331,0340,0,0,03,0306,'~','k',0221,0360,01,0224,'?','I','L',0330,0,0215,025,011,0321,'n','x',014,'o','p',0300,'c',0365,0240,0,0,0,'J','s','x',031,0264,0217,032,0223,0326,0226,0361,0366,0,0,0301,025,'9',0214,'R','?',037,0354,0340,0372,0335,0233,0242,0273,0200,0,0,0,01,0354,0266,'&','y',0277,0304,0362,0373,'~','v','h','i',0231,013,0,036,0303,0364,0230,0221,0,0,0,034,032,0252,'j',0271,0300,0,0331,'S','o',0216,'A',033,'*',03,0317,'n',0304,02,'7',0271,'`',0261,0372,0240,0,0,0,'$','9','<','|',0366,'O',0207,'g','k','e',0312,'w',0200,0,0,0363,0225,0201,016,'<',0232,0373,0320,'8',0376,0333,0207,'z',0220,0,0,0,0,0373,0246,031,0216,'~','Q','*',0221,0347,021,0212,0265,0324,0303,034,02,0377,0,'7','T',0,0,0,03,06,'~','m',0230,0260,01,0351,'?','C','I',0361,033,'*',023,0315,'f',0315,'}',033,0335,'0',0226,'z','p',0,0,0,'3','7',0371,0273,016,'O',0203,0345,0256,0327,0272,'O','`',0,0,0,'8','!',0305,'b','y','m',0272,'!',031,0323,0342,0230,0272,0177,0305,0331,0,0,0,0,03,'9','w',0216,0236,'H',0361,'o','.',']',']','y','!','g','i',0372,'*','N','@',0,0,0,'8','5','H',0325,0243,0200,01,'f',033,0274,'T',0347,0226,0315,0272,0366,'7',0272,0341,0254,0364,0200,0,0,0,'d',0356,0205,0261,0344,0370,026,'B',0375,'+',0244,0312,0,0,0,0,01,0213,'*','s',07,'F',027,'O',0326,'A','4',0373,'O',0226,0273,0340,0,0,0,01,0355,0244,'4',0377,0,0177,0212,'{',0266,0274,0375,024,'J',0315,0326,'9',0,0,0,0,030,0263,0363,0210,0216,0,013,04,0330,'s',0213,'7','+',0310,0336,0357,0210,0263,0320,0200,0,0,01,0355,0254,'u',0223,'%',0300,'}',0371,'b',0256,'C','<',0,0,0,0,0,035,'E','n','A','O','.',0276,0334,016,';',0265,0341,'k',0353,0200,0,0,0,037,'T',0267,0272,0315,'i',0266,0347,032,0220,'H','x',0271,0211,'k',037,'@',0,0,0,0,'Q',06,0221,0234,02,0300,'6',034,0342,0315,0352,0356,'3',0273,0342,0255,0237,0,0,0,03,0320,0324,0262,'d',0270,'&','C','4',015,0272,'J','@',0,0,0,0,0,016,010,0251,'V',036,';','Q','(',0316,0221,022,0307,0326,'>','+',0220,0,0,0,01,0315,')','*',0277,0230,0314,0245,'9','l',0272,0353,'-','S',0274,0,0,0,0,'|',032,'&','S','D',0374,0330,0203,0347,034,0205,'w',033,0335,0361,'v',0316,0200,0,0,01,0332,0303,'c','H','p',0274,0256,0307,0225,0264,'I',0260,0,0,0,0,0,0,0,0307,025,'9',0200,'0',0332,'~',0252,011,0245,0332,'<',0225,0222,0,0,0,0,014,0315,'|',0224,0372,'K',0212,'I','2','i',0333,0325,'{',0200,0,0,0,04,'p',0322,0362,0347,'>','1',0310,0327,'Q',0275,0347,031,'l',0320,0,0,0,037,'k','l','-',0336,047,0232,0333,0361,'6','!','b',0,0,0,0,0,0,0,0,':',0312,0344,0201,036,'L',033,0260,'(',0356,0331,0207,'z',0260,0,0,0,0,0310,'Y',011,'?',0221,0341,0262,015,0250,0213,'x',0315,0,0,0,0,'a','J','T',0361,0342,0223,0256,'c',0273,0316,':',0331,0200,0,0,0,'9','R','y',0267,0310,'$','[',0274,0356,'j','Z','G',' ',0,0,0,0,0,0,0,01,0301,030,'*',0223,0307,'m',0360,0350,0316,0241,024,0307,0324,'8',0255,'@',0,0,0,035,0366,0351,'O','w','8','|',0217,'{',0314,'[',04,0234,0344,0,0,07,'I','J',0221,0334,'R',0365,0314,'o','y',0360,'R','P',0,0,0,016,'I',0236,0317,'.',0225,0357,0362,0311,'A','o',037,'@',0,0,0,0,0,0,0,0,0,0307,025,'1',0201,'0','Z',036,0276,011,0253,0332,':','+',0272,0,0,0,0,0373,0245,0223,'L',0374,0206,'U','#',0317,'-',012,0246,0247,' ',0,01,'U',0220,'{','6','k','H',0277,0241,0261,0364,0225,0,0,0,0,'K','3',0363,0331,0234,0207,036,0316,0326,0227,')',0334,0,0,0,0,0,0,0,0,0,01,0362,'k',0311,'W',0226,0205,036,034,022,0320,030,0376,0333,0214,'z',020,0,0,0,07,'*','L','r','r',0211,'t',0247,'3',0264,0311,0240,0,02,'*','T','$',012,'/',0271,'G','q',0373,' ',0,0,0,04,0217,'/',0213,0235,0311,'q',034,0255,'m',0272,017,'`',0,0,0,0,0,0,0,0,0,'8','#','F',0236,024,0250,',',0242,0370,';',0254,0276,025,025,0326,'#',016,0222,0,0,0,0,0372,0245,0266,026,0317,011,0317,0310,'y',';',0254,0314,0200,017,0222,0213,'"','Z',0236,0336,0274,0322,0355,0274,0,0,0,0,'g','/',0362,0366,014,0237,011,0363,0335,0206,0352,'%',0,0,0,0,0,0,0,0,0,07,07,0214,0327,03,'W','L','Q',0300,04,0214,0330,0202,'C','D','f',';',0240,'B',0265,0372,0367,']',0331,0200,0,0,0,0366,'[',031,'g','K','|',0351,'(',0311,0206,0344,'9',0,0210,025,'1',05,0214,0355,0221,0254,'^',0340,0,0,0,014,0255,0320,'6','4',0237,04,0363,0337,0251,0255,0246,'0',0331,'#','b',0314,0331,0310,0,0,0,0,0,0,0,030,0303,'_',0315,'e','#',047,0,0,017,'i',0267,'G','i',0212,0324,0364,'p',015,036,0335,0344,0254,0230,0,0,0,023,'|',0374,'z','S','#',0317,'.',0243,':',01,'W',020,0202,017,033,0332,'c',030,'}',0330,0,0,0,0367,0326,'*',0311,0223,0340,']','y','#','u',0270,0207,0200,'d',013,0264,0277,013,'L',0357,'9',0,0,0,0,0,016,0242,0267,'(','B',0213,'1',07,0,0,01,0357,'7',' ',0276,0310,'Q','Y',0236,034,';',0260,030,0316,0331,0207,0257,0253,0,0,0,031,'[','<',0325,0225,'5',0300,047,0325,'Y','@',020,0342,0250,'<',0270,0245,0253,0210,0336,0371,0341,0244,0220,0,0,'=','m',033,'"','K',0201,0375,'f',0205,0326,0362,032,0,0,0344,0316,026,0311,'k',0226,'A','3','=',0200,0,0,'<',0304,'H',0255,0212,0260,0250,0210,0330,'8',0,0,016,'K',030,0335,'b','l','r','p','`',0312,0224,0306,'Y','|','2','3',0251,'E',0254,0351,0334,'V',0240,0,0,0372,0245,0266,0224,0217,0315,'r','}',0215,033,0260,03,0340,0246,'L',01,0361,'n',0314,'k','O',0242,0306,0265,0275,0367,0236,0335,0336,0372,0352,0374,0262,'t',0323,'?',013,0275,0267,'E',0317,0244,'x',0216,'W','4','.',0275,025,0201,0300,0,0,01,0310,'=','D',0220,0222,0231,0223,0274,0344,0350,'1','$','l',0214,0236,' ','p',0,0,0,'r','d','M',0250,'6','H',0364,0,01,0344,'*',0222,'1','D','r','?',0334,0302,0265,'{',037,'E',0373,0,0,0,0260,0266,0270,0134,0207,'{',0307,0354,' ',0,0370,'+',0242,06,'u',0200,024,012,0134,0134,0255,0231,0262,0334,':',015,0134,'5',0320,0360,0200,0,0,0,0,0,0,0,0,0,01,0311,0336,'_',0246,0325,0222,'3',0220,0,0,0370,'+',0322,0276,'1',':',0236,0216,0277,0321,0356,036,'J',0310,0200,0,023,'<',0374,0232,'Y','#',0315,'6',' ',0,01,0341,'#',0307,0200,0362,035,'G',047,0240,0366,031,'B','F','}',03,0202,'8','k','Q',0257,'f','$',0340,0,0,0,0,0,0,0,0,07,047,0270,0276,0215,0232,'&',07,' ',0,0,0,0340,0213,025,'Q',0214,0301,0277,0,0214,0355,0270,0233,0275,'@',0,011,'N','^','q','6',0223,0344,'[',020,0,0,0,0,0,0,0,'8','1',0245,034,'P','%','d','u',0234,0,0,0,0,0,0,03,0223,0350,0260,'K',0360,0276,014,0331,0310,0,0,0,0,03,024,'T',0206,023,036,'H','<','_',']',0215,0272,030,0,'I','/',0347,0223,0271,'^','=',0261,0,0,0,0,0,0,0,0,01,0301,032,')',0302,0241,'+','2','>',016,0,0,0,016,'A',0301,0232,',',0222,0334,'.','B','`',016,'@',0,0,0,0,0,017,'9','V',0221,012,'"',0261,0235,012,033,0213,0257,0374,0326,0360,'$','w','s',0311,0344,0267,036,0330,0200,0,0,0,0,0,0,0,0,0,'p','|',021,'R',012,'B',0310,0251,0200,'1','g',0234,0340,0364,031,'#','<','J','I',0221,':','%',0307,'q',0310,0,0,0,0,0,0,0,03,0202,04,'V',0346,07,'G',0324,0300,0365,';',0177,'E','w',04,0243,'/',':',0233,0311,0362,015,0210,0,0,0,0,0,0,0,0,0,0,0,016,01,0310,0,0340,0344,0,0,0,0,0,0,0,0,0,0,01,033,'*','c',021,0257,'#',010,0216,0354,030,'G',0262,0237,'l',0360,0311,04,0207,0217,0330,0200,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,'1',0305,'V','G',')','O','.',0276,0367,0253,'c','K',0325,'U',0374,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,0340,0213,021,'`','M','L',0360,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,07,0377,0304,0,'0',020,0,01,04,02,01,02,06,02,0,05,05,01,0,0,0,0,04,01,02,03,05,0,06,07,' ','0',020,021,022,023,024,'@',025,'1','"','2','4','P','`',026,'!','#','%','3',027,0377,0332,0,010,01,01,0,01,05,02,0377,0,047,'&',0334,' ',0360,0316,'H',0240,017,010,0346,'j',0226,'$',0334,0335,0347,0222,'s','U',0233,0261,0374,0305,'t',0354,0177,'-',0337,0273,031,0313,'{',03,'q',0274,0303,'v',0231,037,'4',0332,'7',' ',0346,0347,0340,0334,0321,'Y','"',07,0311,0332,0371,'x','-',0355,'y',0270,0213,0347,0375,0344,0333,'A','+',0231,'i',0313,'t',0240,0345,0237,'3','X',0317,0226,033,0255,0325,0226,'I','3',0345,0356,0262,'G','F',0265,0373,'m',0275,'f','V',0363,025,0260,0313,'W',0314,025,'&','e','u',0330,026,0254,0376,0345,'9',021,0215,035,0337,'*',0324,'U','e',0317,',',0134,'Y','a','g',020,'s',0376,0244,04,'J','3',0351,0371,'B',0356,0257,')','9','v',0256,0303,04,'6',03,0243,0355,0272,'F',0307,0213,'`','2','g',0344,0305,0134,0371,0303,0256,'|',0321,0361,013,0201,'q',0262,0261,0377,0,'r',0302,0320,'Z',0250,'6',016,'d',0212,'%',0270,0331,'l',0257,'d',0373,'U','w',0207,'S','K','A',0314,0256,'n','T',0336,0203,'w',017,'[',0336,0330,0333,'m',0260,0254,0330,0347,0271,0335,'H',0367,'5','[','j','[','r','=',0200,0330,0360,']',0251,0253,0203,0221,031,'Q','}','R',0214,0204,030,'v',0216,'`','d','Y','i','r','m',0314,0377,0,'x',033,02,'k','g',0326,'y',0201,0361,0255,'u',0240,0266,0320,'t','I','#','b','e',0315,0303,0254,037,0217,'{','c','I',0256,0241,0215,']','~',0357,'8',0357,0230,0270,0313,'Q',0237,0215,0231,0217,0351,0254,0262,'}','t',0361,'J',0331,0243,0372,'J',0276,'Y',0266,'r','`',024,011,'}',0264,'X',0354,'S',0367,'a',0250,'8',0224,0207,'G',0275,'!',031,0306,0333,'#',0361,0274,'U',0260,0273,035,0305,';',013,'q',0374,'i',0262,'3','%',0321,'/',0341,0311,'i','l',07,'N',0355,'E',0351,0264,'D','j',0134,0252,'-',0256,'5',0310,0364,0307,0275,0261,0262,0346,0345,0307,0277,010,'!',0203,'F','Y','o','.','N',0204,'_',',','a',0223,'G',0215,0264,'%',0270,'=',0343,0333,0203,027,031,'I',0232,0315,0217,0245,0337,'F',0322,0334,'Z','a','w',016,'P','*',0351,'U','|',0327,0262,'8',0223,0230,0372,0276,'0',0276,0262,0300,'8','J','4',0300,0270,0273,'_',017,03,0241,0256,0257,'j','F',0326,0365,0253,032,0354,'.',0230,023,0230,'o',031,0353,0346,0345,0207,011,0214,0374,0263,0342,0213,0332,0374,'2',0270,0252,0367,'v',0265,036,'E',';',0134,'}','.',0312,05,0360,'w','W','*','s',0360,0202,030,'4','e',0226,0362,0344,0354,0326,0223,0361,0211,0310,'d','X','e',0215,0336,0344,'}',0375,0273,'y',013,'U',0203,'`',0330,0315,0330,0314,0354,'G',023,0346,0222,0223,0213,0256,'m',0362,0233,0210,0252,0,0300,0253,'E',0257,0217,0350,022,034,05,0262,0343,0212,')','l',0262,0357,0211,'m',0353,'p',0221,0246,022,'N',0270,' ',0220,0231,'u',0232,04,0244,0203,010,'!',0203,'F','a',0217,'2','N',0320,'q','{',0304,0370,'U','9','_',']',0336,0337,'9','.',':','|','(',0231,'L',0237,0254,'@',0247,'>','}','s',0207,'I',')',')','u','Z',0312,010,0376,0265,0265,0,027,'q','l','<','4',0255,0313,032,0242,0352,'g',0350,0206,027,0221,'.',0265,0255,0262,0242,',',0236,'v',015,031,0206,'<',0311,';','H',0236,'k','W',']',0361,0274,04,0203,0344,0222,0306,'$','l',0356,'*',0371,047,'!','r','_',0245,0134,0345,'r',0365,'G',033,0246,'~',0257,0304,0205,0330,0345,'6',0273,'_','A',07,0332,0263,0250,016,0336,015,0243,0207,0344,0207,012,022,'P',0246,0310,0242,'|',0362,'k','Z',0323,'*','b',0311,0347,'`',0361,0230,'c',0314,0223,0264,0210,0256,'Z',0332,0304,035,'<','5',0312,0247,0265,0375,0305,'_','$',0344,'n','F','Y',']',0327,0254,'i','v',033,'D',0332,0276,0207,'[',0254,0263,0357,'l','z',0205,'v',0315,06,0321,0307,'V',':',0354,0272,0316,0262,0332,0250,0362,'y',0330,'<','f',0232,0343,'$',0355,'5',0252,0345,0255,0255,'A',0223,0302,0222,0213,0327,0237,0256,0242,010,'`',0261,033,0264,'J',0367,':',0364,0347,'`',0273,01,'p','I','_','o',05,0202,'b',0347,'%',0362,022,0267,0255,0255,'W',0273,'J',0342,0247,026,0202,0213,020,'p',0375,0365,0377,0,'d',0275,0272,0371,'^',023,'L',0321,0343,'4',0327,031,047,'i',0255,'W',0255,'m','j',014,0236,024,0224,']',0215,0256,'u','h',0371,0347,0340,0327,'+',035,'Y',0262,0371,'g','$',0357,0251,'T','+',0225,0134,0275,'!',03,'5',0201,':','?',033,017,'B',0317,0354,037,0254,0274,0273,0367,0327,'&',0231,0260,'F','i',0256,'2','N',0323,'Z',0257,'u','u','j',012,0231,0373,0312,'J','/','o',0263,0266,0377,0,'>','N','C',0320,0261,'.',0361,0217,'l',0215,0313,':','q',0255,0242,0273,0325,0311,0251,'^',0212,0212,0202,'n',0216,0323,'t',0221,'5','a',0177,0260,'~',0262,0362,0363,0335,0360,0232,'f',0301,031,0307,'8',0311,';','M','j',0275,0325,0325,0310,'+','q',021,0134,0264,0264,'H','?','k','m',0376,'l',0233,0377,0,'l',034,0271,05,'p','v',0221,0225,0340,0346,0243,0222,0367,'K',0214,0234,'$','Y','C',0227,'*','j','I',0272,';','O',0324,06,0325,'A',0376,0303,'{','y',0356,'x','K','+','`',0214,0343,0234,'d',0235,0246,'1','d','u','u','r',010,0334,'k','U',0356,0245,0243,'A',023,0265,0266,0377,0,'>',020,0236,'S',0370,0205,'p',0350,0262,')','[','3','2',0316,0234,'k','h',0217,0323,015,034,0275,047,'M',0203,'V',03,0373,015,0355,0347,0253,0302,'Y','[',03,016,'9',0306,'I',0332,'c',035,'#',0253,0353,0232,'#','q',0214,'t',0257,0246,0245,'h','-',0355,0355,0237,0372,0341,0277,0354,'W','@',0344,0310,'3',0203,0264,0214,0257,06,0271,'X',0352,0315,0227,0313,031,'#','e','o',0337,0275,0274,0363,0360,0226,'V',0302,0303,0316,'q',0222,'v',0243,0215,0322,0276,0276,0275,0242,'7','$',0221,0260,0263,'A',0331,0300,0265,0263,0356,'m',0251,0374,'y','a',0375,'g','P','W',016,0213,'"',0231,0223,0267,0,0264,0236,0275,0325,0326,0360,'X','7',0356,0336,0336,'x','I','#','a','a',0347,0270,0307,0366,0243,0215,0322,0274,012,0366,0206,0314,0232,'f',017,026,0313,0263,0276,0331,0365,'v','3','T',0237,'E','q',025,0355,'_','o','m',0375,'e',0217,0365,0335,'p',020,0361,0334,035,0263,047,0360,'k',0225,0216,0254,0331,'U',0271,034,0215,0225,0237,'j',0366,0363,0323,0341,'$',0215,0211,0207,0236,0343,037,0332,0212,047,'L',0360,0,'h','l',0302,010,0214,'H','v','=',0222,'K',0211,'|','8',0213,'f',0370,'V',035,0275,0267,0371,'r',0321,'<',0216,0354,0207,'k',' ',0330,'9','Q',0222,0334,06,0316,'z',0367,0326,0334,0303,'b',0237,'b',0366,0363,0321,0341,'$',0215,0211,0226,026,016,'1',0375,0250,0242,'t',0317,0,06,0206,0314,',',0270,0201,0203,'`',0330,0245,0271,0233,0304,'r',036,',',0372,0265,0343,'6',032,'N',0326,0327,012,0270,'l',0274,0207,0323,'?','j','9',035,023,0203,0271,'G',0342,'/',0232,'1',0356,0215,0365,0233,'#','d',0304,'T','r','}','[',0313,0317,'k',0301,0357,'l','m',0260,0260,'S',037,0332,0206,027,'O',' ',' ',0264,'6','`','a','H','t',0334,0247,0253,'H','=','g','O',017,'l',037,016,0317,0265,'j',0330,0335,'^','9',021,0225,011,'b',0264,0270,0210,035,0343,'I',0333,022,0302,'Q',024,'C','c','-',0271,']','s','5','z',0203,'g',01,0354,0372,'w',0227,'~',0316,'~',0361,0357,'H',0333,'a','`',0245,0273,0265,014,'.',0236,'@','A','h','q',0340,' ','I','a','0',0,'G','_',011,0301,'G','`','&',0303,'O','%',015,0277,'@',06,0311,0134,'m','5',0223,'.','*',0373,'<',0253,'y',0370,0275,'s','U',0331,'?',031,'#',0134,0217,'i','b','0',0270,0310,035,0303,'K',0333,'c',0326,'7',05,'r',0213,0210,0250,0344,0216,'W','B',0372,0315,0221,037,0215,'r','9','>',0205,0345,0337,0307,'E','_','5','{',0322,'6',0330,0330,')','n',0355,'A',03,0210,0220,' ',0230,034,'y',']',']','%',0214,0301,0205,030,'0',0370,'s',026,0273,0357,0207,0323,0303,'7','~',0375,0177,'g',0226,'.',0177,'#',0262,0346,0245,0263,'|','e',0375,0341,0241,'4',0310,0310,031,0343,'?',0270,'%',0204,0202,'(',0246,0306,'[','r',0272,0342,'j',0365,02,0316,033,06,'w',0257,'.',0376,'2','*',0371,0253,0234,0214,'m',0215,0212,0226,0356,0324,020,'<',0231,03,011,0201,0307,0225,0265,0222,'X',0312,'(',0221,0207,017,0215,0230,021,0331,0201,'k',0134,0372,0253,'.',0215,016,0335,'i','v',0217,'?','>',0305,0241,0255,0256,0257,'8',0247,034,'g',0206,0265,0266,0250,0230,0307,0243,0333,'8',0354,'%',0206,0326,'H',047,'u',0256,'V','8','+',0237,'<','E','G','$','r',':',047,0326,'l',0250,0354,'k',0221,0355,0355,0335,0335,0374,'D','U','W','+',0234,0214,'m',0215,0212,0224,0356,0320,0343,0274,0231,03,015,0201,0307,0225,'u','R','X',0310,'8',0321,0213,027,'O','2','R','|','[','N',0204,'r',0265,'u',013,'d',0272,0327,'z',0371,'j',0323,0341,'k',035,032,0346,0323,'%','R',0304,0364,0236,017,'/','<',':',0235,035,0216,'j',0261,0335,0301,017,0220,'E',020,0350,0313,'L',0256,0267,0236,0275,0300,'Z','A','`',0336,0315,0335,0322,06,0327,'9',0134,0256,'r','1',0266,'6','*','S',0273,'C',0216,0362,0244,020,'F',011,036,'T',0324,'>',0306,'H',' ','`',0361,0365,'r',025,'?',0346,'u','~',0236,026,0264,0367,01,0353,0346,'k','?','~',0353,0240,'1',0234,'a','c','T',017,035,']',0236,0277,'(','~',06,01,031,'m','(','9',04,'w','q',0256,'V','8','+',0234,'k',0221,0310,0311,035,023,0253,'6','_','<','k',0321,0355,0352,0272,0272,'@',0232,0347,'+',0334,0347,'#','R',0312,0305,'J','w','h','a',0236,'T',0202,010,0301,'#',0312,'z','g','X','>','(',0233,014,'}','r','1','$','f',0317,'[',0370,0213,0376,0216,',',0263,0370,033,'g','R',0346,0355,'a',0371,'=',0237,0243,0213,0253,'?','%',0267,'x','Z','k',0321,0225,0204,015,' ',0262,'I',033,'e','i',0325,016,0213,0274,'!',0362,010,0242,037,031,'i',0225,0366,0323,0327,0272,0276,0326,013,06,0364,']',0134,0240,'-','s',0225,0356,'s',0221,0251,'e','d',0245,'/','h','a',0236,'T',0202,0212,0301,'#',0312,'j','W',034,0346,'1',0261,'3',0263,0314,0265,0177,036,0357,0242,0244,0265,02,0316,011,0222,'x',':','n',011,0370,'u','s','?',0335,0227,0243,0204,0253,0374,0242,0361,',','(',0216,0216,0316,0212,'`','|',016,0252,'a',031,'4','/',0201,0375,0306,0271,'Z',0241,0134,0343,0134,0217,'F','=',0321,0272,0263,'e',0306,'=',0262,'7','.','n','P',06,'=',0353,'#',0225,'Q',0251,'e','d',0244,0257,'h','Q','^',0134,0202,0212,0301,'#',0312,'Z','5','-','Z',0324,'c','{',0134,0305,'_',0362,'u',0256,0235,' ',0325,'?','V',0351,0344,0203,'>',036,0241,0323,0305,0300,0374,'=','?',0241,'S',0317,'-','5',0306,'O',0223,'B',0370,036,'@',0321,0222,0303,'k','d',021,'{',0242,0235,' ',0212,'%',0204,'E','&','W',0332,0317,'^',0342,'6','x',0376,'#',0336,0351,'^',0252,0215,'K','+','%','%','{','B',010,0362,0344,030,'f',013,036,'R',0321,')',030,0210,0215,'N',0336,0334,027,0344,'u',0276,0236,035,'1',047,0326,'z','y',0230,0217,'F',0273,0323,'@',032,'W',0322,0365,035,']',015,0203,',',0251,0246,0257,'U','O','4',':',0237,0317,034,0325,'j',0367,021,'U',0252,035,0302,0263,'"',0225,0223,'7',025,'|',0222,0312,0313,0344,'/','h','A',036,0134,0203,0214,0301,'c',0312,'J','/','w','?',']',0331,0243,0367,'a',0263,0201,05,0261,0350,0341,022,0272,0271,0272,'n',0232,0230,020,0233,'X',0323,0322,0316,0267,'5',034,0226,0272,0346,'9',0252,0325,':',0275,0245,0264,0201,'d',031,0335,0321,0212,'x',0262,'G','t',';',0222,0316,0317,0344,'v',0303,015,0346,'H','8',0354,032,'<',0244,0242,0372,033,0324,037,033,'m',0350,0341,0222,'}',0275,0213,0247,0232,0244,0365,'^','t','h',0360,0244,0373,'g','j',0312,0226,023,0320,0332,0351,0200,'|',0221,'6','f',0231,'N',0350,0361,'S',0311,'~',0270,'a',0274,0311,' ',035,0203,'G',0373,0312,'J','/','G',0321,0345,0210,0275,0275,0303,0243,0211,0344,0366,0367,036,0236,'b','w',0236,0317,0321,0306,0314,0365,0356,0335,0271,'a','d',0354,0263,0327,035,026,'*','y',')','u',0261,0223,0204,0207,' ',0253,0365,'B',011,0346,'I',04,014,036,'4','O','5',0244,0242,0366,'>',0227,'2',0303,0351,0331,0272,'8',0342,'_','o','r',0351,0345,0327,'y',0355,0275,034,'T',0317,'V',0345,0335,0262,0244,0204,0364,'0',011,0201,0221,0361,0266,'D','6',0231,'S',025,0276,0237,0246,020,'O','2','H',' ','`',0361,0265,0252,0345,0245,0243,'A','S',0351,'s','R',0177,0335,'t','h',013,0345,0270,0364,0362,0343,'|',0266,0356,0216,')','w',0247,'r',0357,'O',04,'d','G','g',0256,0274,'|','T',0302,0353,0343,')',012,06,'A',']',0364,01,015,0306,'K',014,'-',0202,'6','1','d','u','5','"',04,0237,'O',0232,0227,0376,0353,0243,'@','O','=',0307,0247,0230,0233,0345,0263,0364,'q',0253,0375,033,0267,0320,0263,0242,0204,0354,',',')','B',0221,0354,'I',032,'m','?',0226,'+','<',0273,0364,'2',0243,'e',0312,'S',0341,04,0210,'f','d',0354,0372,'|',0313,'7',0253,'f',0350,0343,0230,0375,0315,0313,0247,0232,0243,0364,0336,0364,'h',0262,0373,';','w',0321,' ','h',0312,0216,0317,'_',0220,'_',03,0,0214,0266,'K',033,0241,0223,0272,0307,0254,'O',016,0353,0325,0215,'r','=',02,0260,0230,07,0326,0336,0302,'w',0323,0345,0231,'=',0315,0303,0243,0212,'#',0367,'7',016,0236,'n',0207,0370,0272,')','f',0370,0367,014,'_','S','>',0215,0315,0303,'@','c',0234,0257,'v','Z','=',0257,'7',0276,'%',0204,0202,0250,0306,'F','S',0177,'Y','Y',0261,'H','>','@','L','e','G',0364,'7',0331,0376,'F',0337,0321,0303,'C','{',0233,047,'O','3',0214,0217,0240,0351,0244,'-',017,0250,0372,027,'7','-',01,0222,'H',0351,'_',0226,0226,'~','I',0364,'X',0367,'F',0340,0256,'=','X',0212,0216,'A',015,0230,')','+','o',0241,'7',0277,'+',0375,0270,0255,0210,0371,'v',0235,034,'"','/',0361,0364,0362,'`',0177,'3','P',0351,0343,023,'~','n',0235,0337,0271,0270,'h',014,0222,'G','J',0374,0263,0264,0362,0372,0241,0330,0310,'.',014,'d','e','7',0365,0225,0233,023,0307,0310,010,0214,0230,0373,0233,'I',0277,0216,0327,0272,'x','l','?','g','[',0351,0273,033,0346,'T','J',0317,'j','N',0216,022,0260,0365,013,0336,0270,0270,'m','{','$',0221,0322,0277,',',0355,'>',0274,'r',':',047,03,'n',0222,'b','/',0236,010,'l',0301,'>',0262,0356,'#',0273,0234,0275,'c',0361,'5',0216,0235,014,'%',07,'T',0351,0134,0334,'+',0377,0,027,0262,'t','q','U',0247,0343,0366,0316,0355,0305,0303,'k',0331,'$',0216,0225,0371,'g','i',0352,0373,'@',0331,0274,'u',0204,0206,020,0324,'_','%',0253,0330,0326,'<',0216,'V',0312,0336,0317,'3',0332,'{',0326,0335,025,0242,0374,0333,01,0241,0370,0343,0365,'s','%','g',0307,0276,0350,0257,'-',0300,034,011,'-','4','>',0335,0305,0303,'k',0331,'$',0216,0225,0371,'g','i',0353,0355,0301,03,0210,0226,012,0310,'!',0214,0272,'V','H',0262,0304,0370,']',0335,0204,0227,0300,0360,0255,030,'G',0205,'}',0244,0325,0357,0257,0264,0206,0301,0235,'n','r','1',0273,'m',0237,0345,0366,'.',0216,'1',0255,0374,0206,0333,0327,0313,0325,0177,'3','[',0351,0342,'k',0217,0310,0353,'=',0253,0213,0206,0327,0262,'I',035,'3',0377,0,'Y','g','i',0356,0366,0343,0215,0322,0274,0,'Z',034,'h',0236,'k',0204,014,0302,'Z','m','d',0202,0257,'q',027,0313,021,'|',0260,033,'w','G',0221,0310,0331,'[',034,0216,0205,0365,'[',023,'f',0317,'?','>',0255,0362,0343,0360,0272,0307,'O',012,0326,'z','F',0353,0271,0257,'m',0245,'Y','C',0270,'B','z','8',0242,0363,0361,'{',047,'f',0342,0341,0265,0354,0222,'G','L',0365,'_','$',0262,0263,0367,0273,'h',0212,0345,0255,0257,'A','Y',0224,'4',0336,0303,'m','(','c','3',010,026,'A','$','T','G','!',0325,010,0270,0346,0253,027,0272,')',0262,010,0341,016,0214,0246,0345,'U',0363,0302,0310,010,'a','1',0364,'s','5',0337,0276,'o','G',0227,0236,'i','U',037,0205,0326,0273,034,0247,'O',0370,0315,0243,0240,'y',0336,')',032,0345,0274,'w',0264,0275,'w',027,015,0257,'d',0262,0272,'g',0252,0372,'R',0312,0317,0344,'/','n',0256,0273,0330,'L',0240,0246,0363,0361,',','(',0215,0216,0316,0222,'P',027,013,01,0205,'!','!','8','^',0363,'$','t','n',02,0331,'$',0304,'_','<',06,0306,'Z',0371,'+',0255,'b',0261,'g',0201,0306,'0',01,'.',0354,0337,'s','k',0321,0244,0324,'-',0326,0312,0215,0364,0247,'c',0226,0350,0377,0,'#',0257,0364,0360,0326,0305,0355,0313,0325,'q','n',0332,0370,0345,0225,0323,'=','U',032,0226,'V','j','J',0366,0352,0253,'|',0274,'(',0251,0276,'S',0277,']',012,0210,0251,'i',0256,'#',0361,0354,'X',0335,'$','m',0225,0247,'T',0272,'.',0370,'V',0217,033,'!',0235,0204,'2','9',035,013,0352,'v',06,0221,0341,0314,033,017,0303,0254,0351,0341,0212,'O','l','n',0311,0203,'0',0301,'o',0352,0237,'I','o',0321,'X','|',0225,'v',024,0266,'q',0134,0326,'t',0134,'[',0266,0276,'9','e','t',0322,'9',0310,0306,0330,0331,')','K',0333,0252,0255,0367,'<',')','j',024,0371,'X',0304,'c','z',0254,'j','!',0260,'i',0325,0323,01,'&',035,'V',0322,'2','h','_',03,0373,0243,024,0361,'^',025,0213,012,'L',0253,0330,0134,'+','v',0373,'9',0355,0366,016,0201,05,'y',0244,0320,'U','2',0226,0243,0265,0314,0272,0377,0,'W',020,'m','?',030,0257,033,'{','v',0327,0307,',',0256,0232,'G',0275,030,0333,033,025,'-',0335,0272,0312,0357,0222,0344,'O','$',0252,0254,'}',0214,0360,0302,0301,0342,0354,'O',03,010,0216,0323,'_','x',0276,04,014,0302,032,'m','s',0305,'^',0353,0134,0254,'p',026,0376,0254,'E',0363,0313,0255,'|','{',0230,0254,0352,'H',0251,0237,0307,0210,'h','?','!','s',0333,0272,0253,0216,0346,0262,0314,011,'*',0317,0350,030,0211,04,0237,'L',0331,0243,0331,0351,0262,0336,0335,0265,0321,0313,'+',0247,0221,0357,'H',0333,'a','b',0342,0335,0333,0256,01,'K','{','Z',0214,'h',0,0276,0302,'q',04,0214,'(','{','v',0232,0373,012,0311,0240,0220,'i',034,0324,'r',037,'Q',0216,'j',0265,0335,0320,0255,036,'.','C','3',047,'a',0365,0360,'Y','A','}',0255,'M','N',0374,0212,047,'M','&',0235,'@',0335,'r',0207,0271,0314,':',0317,0223,0272,'t','=',0255,0332,0305,0315,0205,0344,'C',015,',',0256,0236,'I','$','l','L',0260,0260,'q',0216,0355,0202,023,0214,0226,'(',0233,013,05,025,0346,'M','^',03,'+',0340,0356,0235,']',011,0361,0330,0324,0315,0134,0354,'6',0265,0204,0244,0343,0274,'w',0367,'E',')',0342,0274,'3',0230,'c','%',0215,0263,'3','c',0324,0134,036,'q','6',0260,0266,'v',0335,0333,'*',0370,0255,01,0330,')',0245,0241,0266,0350,0326,'u',0227,'Z',0311,033,033,023,'$',0221,0260,0260,0373,07,030,0376,0330,0242,0270,0271,'G',035,0243,'E',024,'N',0236,'J',0232,0266,0327,'C',0337,0222,'6',0310,0313,']','u',0321,'g',0353,047,035,0204,'4',0332,0327,0212,0275,0304,0377,0,'e','l',0276,0205,02,0321,0263,0347,0355,'5',0243,0307,0254,0215,035,0347,0336,0345,'-','K',0363,'5',0276,':',0316,0262,0353,'Y','"',0211,0260,0307,',',0255,0205,0207,0236,0343,037,0333,0202,07,021,' ',0202,'4','H',0232,0325,'{',0251,'j',020,010,0376,0225,0245,024,'f',0341,03,'H',',',0212,0210,0344,'>',0243,034,0325,'k',0273,0265,0366,0336,0234,'k',0221,0351,'S','x',0360,0226,')',0231,'<','}',0307,'"','9','9',047,'P',']','~',0327,'5',0235,'e',0366,0322,'E',023,'`',0216,'i',0233,04,'g',034,0343,037,0333,0216,'7','J',0360,01,'h','q',0345,015,'7',0307,'o',0324,'0',010,0216,0216,0312,0242,'Z',0367,'a',0325,0254,')',047,031,0343,';',0272,015,0213,0204,'X','g','a',014,0255,0265,0226,0272,'A',014,0210,0330,0273,0227,0364,0220,'_',0325,0201,0241,0317,05,0254,'q',0266,'&','M','3','G',0214,0323,0234,'d',0235,0266,0265,0134,0265,0265,0350,'#','2',0202,0227,0353,0275,0210,0366,0332,0353,0252,0334,'T',0362,'Y',0307,'a',',','6',0271,0342,'/','t','s',034,'<',0302,0230,0302,0232,021,0322,0203,'-','m',0244,'V','1',0366,0355,'l',022,0274,'g',0275,'e','|',0363,0260,'x',0315,'5',0346,'I',0333,0375,0345,']','w',0307,'L',0241,0246,0371,'.',0375,'}',0233,'J','8',0316,'B','F',0220,'I',034,0324,'r',037,'Q',0351,0305,'O','.',0354,'3',':',07,0203,'d',0322,'R',031,0336,'<',0225,'7','L','=',';','2',0312,0330,'#',0264,0260,'u',0201,'$',020,0321,0242,',',0307,0226,0376,0345,'U','o',0243,0302,0226,0241,'O',0221,0255,'F','7',0355,032,04,'G','E','e','Q','-','{',0260,0352,0306,021,0222,0302,0370,035,0334,'k',0225,0253,'_','j',0222,'c',0134,0255,'Z','[',0304,047,'<',0373,033,015,0257,0311,0225,0357,'H',0330,'i','n','.','n',0345,'U','o',0253,0302,0252,0261,0326,'3','C',013,'`',0217,0355,0253,0221,0251,0273,0362,'p',0325,0361,0353,0373,0213,014,0317,0336,024,034,'e',0264,0300,'^','#',0273,0265,'v','^','x',0213,0345,0224,'6',0377,0,')',0275,'[',05,0217,0303,033,'-','l',026,'w',0367,'*',0353,0276,'B',0376,0262,0274,07,0330,'N','(',0254,016,037,0267,'w',0261,01,0257,0215,0267,'r','i',0267,0376,':',0376,0337,' ',030,'1','1',0227,013,0330,0222,'4',0372,0245,0213,0272,0213,0344,0265,0246,0241,014,0216,'G','D',0372,0263,0322,0300,'^',0207,'*','5',',',013,'q',0205,'Z',0224,0243,017,0334,0255,0257,'R',0336,0326,0243,'P',0222,0242,016,'-','~','P','d',03,0355,024,'d','!','C',0264,'r',0374,'p','e',0225,0241,'V',0344,0364,'S',0336,0223,'M','-','=',0340,0367,'0',0341,0365,')','.','H',0305,0215,0375,0261,'g','Q',0246,0215,0351,'#','(',0316,0370,'f',0364,'l',0207,'|','q','r',0362,'_','Q',035,0260,01,'q',0222,'G',033,'b','a','e',0304,024,033,06,0301,'-',0321,025,'w','F',0323,'O',0256,0363,'+','|',0253,'.',0301,0271,0213,0353,035,'d','-','l',';',017,'1',012,'2',0134,0354,0226,027,0362,0365,0214,'L',0242,'O','J',015,0241,'t',0330,'`',014,'-',0244,014,0361,0237,0333,0244,'#',0325,036,'S',0227,0363,0,0361,0332,0232,0250,'^','^','A',0351,0233,0264,030,0216,'2','X','!','h',0361,0224,'T','a',0301,0260,0354,022,']','O',0342,031,0344,'W',0315,'G',0313,0366,'`',0345,'?',047,0321,0332,0344,'S',0307,';','~',0203,0344,'l','M',0270,0344,'Z','J','|',0273,0346,'C','J',0313,033,'s','-',0245,0354,04,04,0366,'$',0351,'<','c',05,'.','y','e',0266,0276,0322,'2','H',0335,023,0347,035,0204,'0',0352,0347,0212,0356,0325,'t',0276,0311,'9',0252,0223,0345,047,0216,0314,047,0274,036,021,03,'I',0210,0221,'$',025,0375,0201,0206,'y','R',012,'3','E',0210,0222,'c',022,035,0213,'a',0222,0346,'~',0272,0353,0303,0352,']','W',0313,0367,01,0345,0177,'3',0326,'M',0200,0357,0224,'V',031,021,0220,'N',0235,0211,011,0212,'$','7','t',0244,03,017,0346,'J',0201,0362,0317,0231,'m',011,0313,'-',0226,0322,0337,0267,0252,0350,0326,033,'L',0272,0326,0240,06,0260,'?',0215,0225,'L','V',',','4',011,'@',0225,0315,'G',0241,0365,'>',0216,0322,'/',0222,0212,0377,0,'p','z','Y','}',0233,'?',027,0265,036,0333,'J',0251,'+',0345,0307,0261,'$','i',024,'l','v','M','_','<',012,0202,0314,0271,0370,0362,'1','A',0235,0271,0361,0245,0317,0217,'.',017,'[','9',016,030,'V',013,030,0343,0310,'T',0233,0274,0366,'(','w','r',02,0246,025,'E',0333,0256,'C',0310,'9',';','b',0203,031,0313,0327,0355,0317,0376,0311,'}',0213,0314,0227,0330,0356,'_',0277,'v','O',0312,033,014,0330,'V',0347,'v','b',020,'q',05,0367,'@',0256,'&',0314,0215,'K',0210,0343,037,'!',0201,0203,0307,0322,'H',0261,0227,025,0255,'$',0200,'.',037,'V',0223,'#',0343,'X',0327,0261,'O',047,0254,'H',0336,0261,0277,0241,0354,'l',0215,0264,0326,0325,0270,0366,':','7','v','+',0252,'f',0260,'x','`',0304,014,'V','u',02,0134,017,0263,0360,0374,0260,'a',0200,0317,'_','7',0336,0200,'y',011,0223,'Y',0342,'C',',',026,0227,'^',02,0200,'~',0302,0265,034,0226,0332,0366,'*','+','T',0300,030,'S','H',031,0343,'I',0327,'B',0357,0340,0353,' ','(',013,'G',0353,02,'9','_',0251,0263,035,0251,0277,'?',0322,'s','b','j','r',0347,0372,'O',033,0252,'B',0231,06,0276,034,017,'F',0243,'S',0306,0343,'^',02,0366,035,0203,0206,0346,0213,',','j','L',0251,0227,0355,06,011,026,023,'k',0374,'>','i',0231,'E',0251,0326,0353,0261,'w','-','h',0343,'9',010,036,'A','d',0234,'v',0220,0303,0200,'x',0216,0352,0242,'w',0374,0277,'X',0352,0301,'l',0341,0274,0341,0352,0363,'2',0347,0216,'.',0352,'2','H',0237,013,0376,0243,'X',0257,'u','F',0203,'u','s',0224,'|','4',',',031,'[','H',025,'<',']',0363,0353,0242,0260,0212,0302,0262,'Z',0351,036,0304,0221,0266,025,'k',017,'U',037,0365,037,'f',0317,'Z',0255,0270,'m',0247,014,0327,'O',0226,0134,'I','v',026,033,0257,0331,'W',0273,0274,035,'1',0307,0272,0267,0212,0257,016,'Z',0276,026,022,',',0252,0324,'j','i',0223,0313,0351,0313,03,047,0216,0332,0211,0341,0347,0357,',','*',0275,'x',0250,0255,'_',032,'O',0352,'~',0343,0343,'l',0210,'n',0247,'Q','`',0206,'q','-',021,'K','?',011,016,0271,'?',012,0330,'5','g',0342,013,0330,0361,0334,'[',0260,'7',035,0306,'{',03,'q',0274,'i',0260,';',023,0213,0266,07,'d','<','E','}','"',0305,0302,0266,'N',0301,0370,'F',',',017,0210,'h',0307,'P',0264,0312,'j',0374,0216,06,'B',0337,0257,0345,0226,0332,0367,0257,034,0325,'b',0235,'Z',0322,'R','h','_',03,0274,'(',0223,0376,'o',0360,'[','J','X',0354,032,'H',0262,011,')',02,0306,'K','L',0253,0220,'u',0362,0312,0201,0226,030,0177,0301,0214,06,'#',0243,0261,0244,0230,025,0305,026,'%','v',014,';',0312,0233,0374,033,0313,0317,015,0327,0206,')',']',0252,023,0346,0232,0251,'^','u',0265,021,'W','7',0374,'/',0377,0304,0,'A',021,0,01,03,02,02,07,05,03,012,05,04,03,01,0,0,0,01,02,03,05,0,04,021,'!',06,022,023,'0','1','A','Q','"','@','P','q',0241,020,0321,0341,024,' ','#','2','3','`','a',0201,0261,0301,'B','R',0221,0222,0360,'4','C','b','r','p',0200,0262,0361,0377,0332,0,010,01,03,01,01,'?',01,0377,0,0333,';','{','W',0356,0225,0252,0312,'q',0253,'M',016,0272,'t','k','>',0240,0232,'o','C','-',0200,0355,0270,'M','?',0241,'G',0375,0207,0177,0255,'=',0242,0262,'M','p','N',0267,0225,';',033,'x',0307,0332,'4','h',0202,'2','?','q','#','#','^',0223,'{','d',0327,016,'g',0245,'G',0307,0263,034,0310,'e',0221,0363,'H',0307,0215,'9','c','l',0367,0332,'6',015,'.',012,'5','|','Y',025,'}',0242,026,0257,014,'m',0216,0241,0364,0251,'(','{',0250,0263,0364,0303,'#',0317,0356,04,'l','k',0322,'o','l',0232,0374,0317,'J',0217,0217,'f','5',0220,0313,'C',0343,0272,0232,0260,022,026,'k','k',0237,021,'J',05,047,'T',0370,0364,'t','s',0322,'O',06,0232,036,'g',0245,'G','G','3',032,0310,'i',0241,0361,0335,0337,0334,013,'[','W',036,'<',0205,')','E','j','*','<',0374,'v',':','9',0351,047,0203,'-',017,0205,'F',0306,0263,030,0310,'i',0241,0346,'z',0356,0311,0,'b','k','I',047,0305,0326,'6','v',0377,0,'W',0231,0353,0343,0261,0361,0357,'I','<',031,'d','|','*','6','5',0230,0306,'v','M','~','g',0256,0354,0220,0221,0211,0255,'!',0322,'#','p','M',0255,0251,0354,0363,'=','|','v',0302,0301,0351,027,0203,',',0212,0214,0214,'f','1',0235,0223,0134,'y',0236,0273,0265,'(','$','k','*',0264,0207,'H',0215,0321,'6',0266,0247,0261,0314,0365,0335,0237,022,0260,0260,'z','E',0340,0313,'"',0242,0343,031,0213,'g','f',0337,036,'g',0256,0355,'J',010,032,0312,0341,'Z','A',0244,'&',0354,0233,'k','c',0330,0353,0327,'w',0226,036,0315,0222,0365,'u',0360,0313,0333,0217,0206,0330,0330,0275,' ',0360,'e',0221,'Q','q','l',0305,0263,0263,'o',0217,'3',0273,'R',0222,0204,0225,'(',0345,'Z','A',0244,'*',0275,'&',0332,0330,0366,'?',']',0341,0366,'1','j',0317,0311,020,0302,0223,0212,'p',0251,'M',020,'J',0361,'r',0304,0341,0370,'U',0305,0263,0326,0253,0331,0274,0234,017,0206,0330,0330,0275,' ',0360,'e',0221,0235,'E','E','3',026,0316,0315,0276,'<',0316,0355,'k','K','i','*','Q',0300,012,0322,015,' ','U',0362,0215,0275,0271,0301,0277,0327,'z','i',037,'X','S','?','d',0237,'!',0354,0275,0217,0266,0277,'F',0245,0302,'q',0251,'}',030,'~',0307,027,'X',0355,'#',0324,'x',']',0225,0223,0327,0357,06,'Y',031,0232,0212,0212,'f',')',0235,'D','}','n','g','v',0265,0245,0264,0225,0254,0340,05,'O',0351,02,0257,0324,'X','c','&',0307,0256,0370,0360,0366,'[',0234,'Y','A',0374,07,0314,0227,0321,0206,'/',0261,'v',0337,0262,0277,'C','W',0226,'/',0330,0271,0263,'}','8',037,010,0263,0263,'z',0371,0340,0313,'#',022,'j','&','%',0230,0246,'u',021,0232,0217,023,0273,'q',0304,0264,0222,0265,0234,0,0251,0371,0365,'H','+','b',0306,'M',0217,']',0371,0372,0236,0313,023,0215,0253,'g',0360,0371,0267,0226,'L','_','7',0263,'}','8',0212,0227,0321,0207,0354,'q','v',0337,0264,0217,'Q',0340,0326,'v','n',0337,'<',031,'d','b','M','D','D',0265,024,0316,0252,'s','Q',0342,'w','n',0272,0206,'P',0134,'p',0340,05,'O','O',0256,'E','[',026,'r','l','z',0367,03,0365,'}',0221,'g',033,'&',0217,0341,0363,0345,0364,'a',0213,0354,']','c',0262,0277,'C','W',0266,027,026,016,'l',0337,'N',036,07,'i','h',0355,0353,0241,0226,'F','$',0324,'D','C','Q','L',0352,0247,'5',036,047,'v',0353,0250,'a',05,0307,016,0,'T',0354,0362,0344,0227,0262,'k','&',0307,0257,'q','>',0310,'c',0214,'{',047,0376,'#','q','s','h',0315,0342,'6','o',0247,021,'R',0332,'(',0355,0276,'.',0331,0366,0223,0323,0235,020,'R','p','>',01,'k','j',0355,0353,0241,0226,'F','$',0324,'<',';','Q','M','`','3','Y',0342,'w','o','<',0206,020,0134,'p',0340,05,'N',0316,0256,'M','{','6',0362,'l','z',0367,'#',0354,0201,'8',0306,0261,0345,0272,0225,0321,0373,'Y','!',0255,0206,0252,0372,0324,0214,'E',0324,'b',0260,'y','9','u',0345,0354,012,0353,'D','s',035,0356,0326,0325,0333,0307,'C',',',0214,'I',0250,'h','v',0242,0232,0300,'f',0263,0304,0356,0336,'y',0273,'v',0313,0256,0234,0,0251,0311,0327,'%',027,0250,0214,0233,035,0327,'D','n',0366,0366,';','#',0305,033,0267,'Z','C',0311,'(','p','b','*','[','D',0270,0273,'a',0375,0276,0352,'q',0245,0262,0242,0207,06,07,0275,0333,'[',';','v',0350,'e',0221,0211,'5',015,014,0324,'S',']','V','x',0235,0333,0357,0267,'l',0331,'u',0323,0200,025,'7','8',0344,0243,0232,0251,0311,0261,0300,'w','D',0220,016,'t',0264,0352,0234,'*','"','U',0310,0247,0366,0211,0372,0247,0210,0253,'K',0306,'o',0232,017,'2','q',07,'y','%',017,'k','&',0234,035,031,0365,0347,'R',0320,'W',021,'j',0304,0346,0216,0275,0346,0332,0335,0313,0267,'C','-',014,'I',0250,'X','V',0242,0232,0352,0263,0304,0356,0356,'.',033,0265,'l',0272,0351,0300,012,0233,0233,'r','Q',0314,06,'M',0216,03,0273,0360,0250,0211,'w',0242,0235,0326,'F','i',0346,'*',0322,0355,0253,0326,'C',0354,0234,0216,0361,'h','K',0211,0325,'X',0304,'T',0276,0211,05,'b',0365,0207,0366,0373,0251,0326,0226,0312,0312,034,030,037,'f','=',0322,0336,0335,0313,0247,03,'M',014,'I',0250,'X','V',0342,0332,0304,0346,0263,0304,0356,0356,'n','Z',0264,'h',0274,0361,0300,012,0232,0232,'v','U',0314,'8',' ','p',035,0343,0353,'e',0316,0270,'T','$',0333,0221,'.','`','s','A',0342,'*',0322,0361,0233,0346,0203,0254,'+',021,0275,0222,0207,0265,0223,'F',016,0216,0327,'Z',0225,0202,0272,0214,'V','*',030,0243,0257,'t','a',0207,'.',0134,015,'4','1','&',0241,'!',033,0213,'o',023,0232,0317,023,0273,0272,0272,'j',0315,0242,0363,0307,0,'*','f','e',0331,'W','z',' ','p',035,0353,020,0340,0301,0134,'i','I',')','8',032,0217,0223,0270,0215,'s','h',0311,0374,0252,'&','v',0332,'Q','8',014,0227,0323,'z',0264,'%',0304,0352,0250,'b','*','_','D',0222,0274,'^',0261,0310,0364,0367,'S',0254,0270,0302,0313,'n',0214,017,'q','a',0207,'.',0134,015,'4','1','&',0241,'!',033,0213,'o','Y','Y',0270,'x',0235,0335,0335,0333,'V','M',027,0236,'8',01,'S',023,016,0312,0273,0211,0311,03,0200,0357,0211,'R','V','5',027,'J','N',0251,0244,'-','M',0253,']',07,03,'P',0332,'W',0255,0203,027,0377,0,0335,0357,0244,0251,'+',032,0311,'8',0215,0354,0224,'E',0254,0232,'0','x','g',0327,0235,'J',0300,0335,'F',034,'H',0326,'G',']',0373,',',0271,'p',0340,'i',0241,0211,'5',07,06,0334,'[','z',0313,0315,0303,0273,0274,0274,'f',0305,0242,0363,0307,0,'*','^','a',0351,'W','q','V','I',034,07,0200,0304,'O',0334,'F',035,'S',0332,'G','J',0260,0222,0267,0222,'o','h',0302,0277,'-',0352,0222,0225,0215,'U',014,0252,'_','D',0322,0356,'/','X',0344,'z','S',0314,'9','n',0262,0333,0243,03,0274,'e',0225,0334,'8',033,'l','b','M','A','A',0242,'-',0275,'u',0346,0341,0335,0336,'^','3','`',0311,'y',0343,0225,'K','K',0275,'*',0356,0262,0262,'O','!',0340,'v',0267,'o','Y',0270,035,'a','X',032,0206,0322,'f','o',0260,'j',0343,0262,0277,'C',0276,0221,0211,0266,0223,'F',0253,0303,'>',0274,0352,'V',02,0346,'0',0353,'a',0254,0216,0273,0246,0232,'[',0353,015,0266,'1','&',0240,0240,0221,030,0215,0243,0231,0270,'}','7','w',0267,0254,0330,'2','^','x',0345,'R',0322,0317,'J',0275,0256,0277,0253,0310,'x','/',012,0206,0322,0227,'-','0','f',0357,0264,0216,0274,0305,'1','p',0325,0323,'a',0326,'U',0210,';',0325,'$',',','j',0253,0205,'K',0350,0232,036,0305,0353,034,0217,'J','}',0207,'m',0226,'[','u','8',037,'f','?','5',0246,0226,0372,0303,'m',0214,'I',0250,'(','$','F','#','h',0346,'n',037,'M',0335,0365,0363,'1',0354,0227,0236,'5','+','*',0364,0243,0332,0356,'p',0344,'<','"','6','Z',0346,'1','z',0314,0234,0272,'T','T',0345,0264,0242,'{',047,05,0364,0337,'H','E','[','I',0243,'U',0344,0347,0327,0235,'K',0300,0334,0305,0250,0253,015,'f',0372,0373,0376,'k','M','-',0345,0206,0333,030,0223,'P','0','(',0215,'F',0325,0334,0334,'>',0233,0273,0373,0366,'c',0231,'/','<','j','R','Q',0351,'G',0266,0216,'p',0344,'<',')',0267,026,0322,0202,0320,'p','5',015,0245,'a','x','1','}',0307,0371,0275,0364,0225,05,0215,'d',0357,'T',0224,0254,'j',0250,'b','*','_','D',0222,0351,'/','X','d',0177,0224,0360,0374,0272,'U',0315,0243,0326,'n','l',0337,'N',0251,0366,'6',0332,0335,'X','B',06,'$',0324,014,012,'#','Q',0265,'w','7',017,0246,0356,'B','A',0230,0326,'K',0257,032,0223,0223,'z','M',0355,0243,0274,'9',017,015,0207,0322,07,0343,016,0252,0373,'H',0351,0323,0312,0254,'d',0355,'d','S',0255,'n',0254,0177,']',0365,0355,0203,022,015,0226,0337,'O',0276,0256,'4','>',0365,012,';',022,024,'+','G',0340,04,'j','v',0317,0375,0241,0364,0335,0310,0310,0263,032,0311,'u',0323,0344,':',0324,0224,0223,0322,'o','m',']','>','C',0247,0207,0262,0373,0266,0313,0332,'4',0254,015,'D','i','c','o',0340,0325,0377,0,'e',']','y','|','(',020,0241,0210,0357,022,'R','L',0306,'3',0265,'t',0371,016,0265,'#','"',0364,0223,0305,0327,0217,0303,0304,0242,0347,0356,0343,'p','@','8',0243,',',0216,'y','~',025,033,'/','k','(',0234,'Y','9',0363,034,0373,0264,0234,0233,'1',0214,0355,035,0343,0310,'u',0251,011,07,0244,'^','/','<','~',036,'(',0333,0212,'i','A','m',0234,010,0250,0215,',','I',01,0231,014,0277,0345,0327,0317,0245,'%','Z',0331,0247,0207,'s',0224,0224,'f','-',0235,0243,0234,'y',012,0277,0277,'z','E',0342,0363,0307,0305,0343,'&',0256,0342,0325,0364,'G',024,0364,'<','>',025,033,'3','i','&',0234,'Z','V',012,0350,'x',0367,031,'Y','6',0242,0330,0332,0271,0307,0220,0253,0353,0347,0244,036,'/','<','|','d',022,016,'"',0241,0264,0253,022,031,0221,'8','t','W',0277,0337,'A','a','X','j',0346,016,0377,0,'L','m',0234,'v',0325,016,0243,0202,'N',0177,0237,0263,037,032,0205,0233,'z','-',0300,0222,'q','o',0230,0367,'S','/','"',0341,0260,0353,'|',016,0371,0306,0320,0362,013,'k',030,0203,'S',':','(',0244,'b',0375,0207,016,'i',0367,'R',0320,0244,035,'U',014,017,0215,0,'I',0300,'T',023,'N',0261,034,0322,036,0343,0334,'$',0340,0255,'$',0301,'R',0206,013,0353,0357,0353,'R','1','7','Q',0253,0325,'x','e',0324,'p',0361,0216,'5',0243,0232,'=',0263,0302,0362,0350,'g',0310,'w',047,0230,'n',0341,05,0247,'S',0210,'5','3',0242,0212,'g',0351,0254,'3',034,0323,0323,0312,0224,0222,0203,0202,0206,07,0305,'@',0307,'!','Z','=',0243,0233,',','.',0356,0306,'|',0207,'u',0225,0200,0266,0224,0355,036,0312,0372,0217,0336,0244,0242,'n',0243,027,0252,0370,0313,0257,'/',023,0,0250,0340,'+','G',0264,'t','1',0205,0325,0330,0355,'r',035,';',0273,0354,'7','r',0331,'i',0321,0210,'5','3',0242,0357,'Z',0257,'^',0305,':',0310,0351,0314,'V','c',0304,022,0222,0243,0202,'k','G',0264,'t','Z',0201,'u','t',';','|',0207,'N',0365,'1',0243,'v',0327,0340,0272,0337,'a',0177,0257,0235,'^','Y','=','b',0346,0311,0361,0237,0241,0362,'>',034,0224,0225,0235,'T',0361,0255,037,0321,0341,'f',05,0315,0310,0355,0364,0351,0273,0271,0271,'n',0321,0242,0363,0247,0,'*',0373,'I','/',0256,'^','*','e','e',011,0344,05,'F',0351,'z',0333,01,0273,0321,0255,0370,0325,0265,0323,'7',0215,0355,'X','V',0262,'w',0274,'j',0362,0302,0336,0371,0222,0313,0311,0313,0364,0362,0251,'}',034,0270,0214,0305,0304,'v',0333,0353,0317,0363,0360,0304,'!','N','(','%','#',022,'k','G',0364,'y','6',' ',0134,0134,014,0134,0375,'7','n','8',0206,'P',0134,'Y',0300,012,0236,0233,0134,0233,0272,0210,0373,'1',0353,0355,0264,0276,0271,0261,'^',0322,0335,'x','T','>',0221,'[',0311,0375,032,0373,016,'t',0353,0345,0275,'#',032,' ','(','`','j','o','E',0222,0377,0,0323,'X',014,025,0314,'r','4',0373,016,0333,'/','d',0362,'u','U',0341,'-',0266,0247,'T',020,0201,0211,'5',01,0243,0351,0260,'H','}',0374,0334,0375,'7','j','P','H',0304,0326,0221,'O',033,0345,0374,0235,0203,0364,'c',0327,0346,0343,0206,'b',0241,0264,0251,0326,0224,030,0276,0355,047,0371,0271,0217,'?',0302,0220,0264,0270,0235,'d',034,'F',0372,'N',036,0332,'Q',030,':',';',0134,0217,'1','R',0221,'7',021,'.',06,0336,0314,036,07,0221,0360,'v',0333,'[',0313,015,0266,'1','&',0240,'`',021,034,0235,0263,0331,0270,'}','7',0232,'K','?',0266,'&',0316,0324,0366,'y',0235,0304,'l',0315,0324,'b',0206,0310,0342,0237,0345,0345,'Q',0322,0314,0311,0241,'*','g',0363,0352,'7',0317,0333,0265,'r',0202,0333,0311,0304,'T',0316,0213,0273,'f','v',0226,'@',0251,035,'9',0217,0205,'p',0343,0340,0215,'4',0267,0326,033,'l','b','M','A','@',0242,'5',033,'W','s','p',0372,'o','4',0226,0177,'g',0215,0235,0251,0317,0231,0335,'6',0342,0331,'P','[','G',03,'P',0372,'T',0335,0306,014,'^',0366,'U',0327,0221,0367,'W',0226,0372,'_','F',0255,0244,'q','u',0256,0303,0235,'z',0371,0325,0325,0233,0366,'N','l',0237,'N',07,0300,0231,'e',0313,0207,03,'M',014,'I',0250,'8','&',0343,021,0264,'^','n',037,'M',0346,0221,0317,013,'4',0233,'[','s',0333,'>',0224,'I','Q',0304,0357,'!',0264,0221,0370,0342,032,'{',0264,0337,0250,0253,'[',0266,'o','[',0332,0260,0254,'F',0372,'F','1',0211,'6',0366,'o',0216,034,'*','Z',016,0346,')','X',0253,'6',0371,'+',0337,0323,0300,030,'a',0313,0227,03,'M',014,'I',0250,'H','6',0342,0333,0326,'V','n',036,'{',0311,0371,0304,0306,'7',0263,'o',0355,017,0245,'-','j','u','E','k','8',0223,0276,0265,0276,0271,0261,'^',0275,0272,0365,'j',036,'y',0211,'4',04,0250,0352,0271,0323,0335,0276,'u',0244,'>',0202,0333,0203,020,'j','k','E',0224,0306,'7',026,'9',0247,0371,'z','y','Q',0313,'#',0337,'m',0255,0235,0273,'t','4',0310,0304,0232,0205,0204,'j',')',0274,'N','n',036,047,'y','5','0',0334,'S','=','V','x',012,'}',0367,'.',0134,'.',0272,'q',047,0270,'%','J','A',0326,'I',0300,0324,'.',0225,0341,0205,0275,0377,0,'/',0342,0367,0322,026,0227,022,026,0236,07,'}','/',0243,'v',0362,'8',0272,0337,'a',0316,0275,'|',0375,0365,'u','j',0365,0233,0245,0227,0323,0202,0207,'{',0265,0265,'v',0361,0320,0313,'#',022,'j',032,025,0250,0246,0272,0254,0361,';',0311,'Y','6',0242,0330,'.',0257,0217,'!','W',0227,0216,0337,'<','^','x',0346,'{',0234,'6',0220,'?',032,0240,0332,0316,0263,']',':','y','U',0235,0363,027,0355,07,'X','V','#','}',')',026,0314,0253,';',047,'r',0350,'j','V',026,0342,')','d','(','b',0216,'J',0345,0360,'=',0346,0322,0321,0333,0327,'C',',',0214,'I',0250,'x','v',0242,0232,0300,'f',0263,0304,0357,'/',0357,0232,0217,'`',0274,0351,0251,')',027,'d',0237,'/',';',0371,'~',035,0326,0332,0355,0373,'7','6',0254,'+',03,0376,'q',0250,'m','!','b','O',0350,0227,0331,'s',0365,0362,0336,0221,0210,0302,0235,0267,'K',0311,'-',0273,0232,'O',020,'j','k','G',035,0215,0305,0346,'{','M','z',0217,0363,0257,'w',0263,0263,'z',0371,0340,0313,'#',023,'Q',021,014,0305,'5',0252,0234,0324,'x',0235,0345,0315,0313,'V',0215,027,0236,'8',01,'S',022,0316,0312,0277,0256,0257,0252,'8',016,0357,0303,0205,'C','i','Z',0231,0372,031,03,0210,0344,0256,0236,'t',0332,0322,0352,02,0321,0300,0357,0247,0264,'c',0134,0233,0253,021,0237,'4',0376,0343,0335,'K','B',0233,'Q','B',0306,07,0272,'X',0330,0275,' ',0360,'e',0221,0235,'E','D',0263,024,0316,0242,'>',0267,'3',0274,'u',0324,'0',0202,0343,0207,0,'*','v','i','r',0216,0352,0247,'&',0307,017,0177,'z',0205,0236,'z','-','z',0253,0355,'7',0323,0247,0225,'Y','_',0261,' ',0330,'u',0205,'b','=','F',0372,'o','G',0332,0225,0372,'D',0235,'W',':',0365,0363,0253,0253,'7',0354,0234,'-','>',0234,017,0371,0303,0271,'X','X','=','"',0360,'e',0221,'Q','q','l',0305,0263,0263,'o',0217,'3',0274,'R',0202,06,0262,0270,'V',0220,0316,0231,05,0354,031,'?','F','=','{',0345,0245,0355,0305,0213,0233,'[','u','`','j',036,'}',0211,'4',0206,0325,0331,'w',0247,0273,'}',0177,026,0324,0215,0266,0301,0374,0317,'#',0314,'T',0204,']',0314,'b',0365,'_',031,'r','<',0217,'p',0217,0217,'z','I',0340,0323,'#',0341,'Q',0221,0214,0306,'3',0263,'k',0217,'3',0327,'y',0302,0264,0222,0177,0345,04,0332,'[',036,0317,'3',0327,0277,'!','j','m','A','h','8',021,'P','z','S',0216,0255,0255,0367,0367,'{',0375,0364,010,'9',0215,0355,0345,0233,'7',0314,0226,037,030,0203,'S','0','/','D',0235,'l','u',0220,'y',0364,0363,0337,'F','F',0273,'&',0370,'i',0277,0314,0364,0250,0370,0346,'#','Z',0331,'2','>',';',0335,'%',0237,0343,'e','j','|',0317,0355,0340,'0',0332,'D',0374,'f',014,0271,0332,'o',0324,'y','U',0245,0343,027,0315,0355,'m',0325,0210,0336,0251,')','X',0325,'P',0304,'T',0346,0214,'*',0337,'Z',0346,0313,'4',0377,0,'/','O','-',0345,0265,0273,0227,'n',0245,0226,0206,'f',0243,'c',0332,0216,'a','-','6','3',0347,0275,0322,'I',0377,0,0222,0244,0332,'[',036,0331,0342,'z','Q','8',0346,'|',012,'>','R',0346,'1',0315,'{','u','q',0342,'9',032,0211,0233,0267,0226,'O',0321,0344,0241,0304,'o',0264,0227,'G',0303,'x',0337,'Z',0214,0277,0210,'~',0373,0256,'5',0243,0320,0250,0217,'h','<',0277,0264,'W',0246,0367,'H','g','D','r','6',',',0375,0241,0364,0245,')','K','Q','R',0270,0370,'"',026,0246,0324,026,0203,0201,025,01,0244,0333,'|','-','o',0217,'o',0221,0353,0361,0336,0251,'!','C',05,'T',0374,':',0243,']',0332,0244,'v',024,'r',0374,'?',015,0316,0213,'F',0246,0366,0344,0272,0347,04,'~',0273,0331,0311,0244,'E',0265,0202,'s','p',0360,0247,0236,'[',0353,'.','8','q',047,0301,0341,'4',0235,'v',0201,'6',0327,'y',0243,0257,'1',0360,0246,']','K',0315,0207,023,0300,0357,'$',0254,'[',0221,0266,'U',0273,0234,0351,0346,0226,0303,0212,'i',0301,0230,0313,'q',0242,'6',0333,033,015,0257,'5',035,0344,0274,0253,'Q','L','k',0253,0353,036,02,0256,0256,0235,0274,'t',0274,0361,0304,0237,011,0212,0234,0270,0212,'W','g',0264,0223,0313,0335,'V',022,014,'H',0262,035,'d',0376,0134,0306,0363,'L','l','C','7',011,0272,'@',0311,'y',037,'?',0363,0364,0334,'h',0225,0350,'~',0317,'`','x',0243,0364,0335,0310,0310,0263,032,0301,'y',0337,0377,0,'j',0376,0375,0331,027,0313,0316,0237,013,0263,0275,'~',0301,0335,0265,0272,0260,'?',0347,032,0206,0237,'b','M',01,013,':',0256,0364,0367,'n',0364,0206,0325,'W','q',0356,'!',03,023,0307,0372,'n','#','$',034,0215,0270,017,'#',0363,0253,')',013,'{',0366,0303,0214,0253,'s','y','x',0325,0213,'%',0347,0216,'B',0245,'e',035,0224,0177,'h',0276,034,0207,0206,0241,'j','m','A','h','8',021,'P','z','R',010,026,0362,07,'>','J',0367,0327,035,0311,032,0303,03,'W',0326,0377,0,'$',0271,'q',0214,'0',0300,0237,0351,0313,0323,'q','o','r',0355,0252,0303,0214,0253,03,'V',':','d','R','5','o',021,0217,0342,'*',0326,'Z',0312,0361,':',0315,'8','?','J','7','v',0351,0314,0270,'?',0255,031,'K','!',0305,0321,'I',0221,0264,'W',07,'G',0365,0257,0225,'0',0177,0334,037,0324,'W',0312,031,0376,'q',0375,'j',0366,'f',0312,0305,032,0313,'X',047,0240,0251,'I','W',0345,035,0327,'s',0207,'!',0342,020,'z','F',0355,0222,0303,'7','G','Y',0277,0376,'~',024,0323,0351,'}','!','m','f',0223,0271,0322,0266,'R',0324,0232,0210,0376,' ',017,0355,0373,'n',0370,0373,'q','#',0205,'k',0253,0257,0211,0303,0315,'=',022,0274,0263,'A',0342,'=',0325,'c','~',0304,0203,'!',0366,'N','_',0246,0343,'M',0200,0332,0260,0177,03,0373,'}',0303,0263,0276,0270,0260,'s','h',0302,0260,'>',0237,0230,0250,'I',0266,0345,0233,0300,0344,0340,0342,'?','q',0363,0364,0325,0264,0374,0231,0247,'0',0317,034,'=','>',0342,'!',0305,0264,0255,'f',0316,06,0240,0264,0231,'7','d','[','^','d',0347,'^','G',0343,0363,0264,0323,0375,033,0177,0366,0375,0217,0334,'h','M','(','U',0250,026,0367,0270,0251,'<',0217,'1',0347,'H','Z',0134,'H','R','N',' ',0374,0315,'4',0377,0,'F',0337,0375,0277,'c',0367,036,032,'}',0370,0265,0245,012,':',0315,'t',0351,0345,'V',0267,'l','^',0267,0265,0267,'V',0260,0366,0351,0242,0323,0362,'V',0221,0216,'z',0337,0267,0334,0213,'9',013,0250,0362,'U','l',0275,0134,'j','#','I','m',0357,0322,033,'x',0352,'9',0350,'|',0250,020,'s',025,0244,0362,')',0277,0274,0324,'o',0352,0267,0227,0347,0317,0356,'R','/',0256,0233,'F',0315,016,0250,017,'3',0377,0,0206,0177,0377,0304,0,'1',021,0,02,01,03,03,03,02,05,04,02,02,03,0,0,0,0,01,02,03,0,021,'!',022,'0','1',020,'@','P',04,'"',' ','A','B','a','q',023,'2','Q','`','3',0221,024,'R','p',0200,0201,0377,0332,0,010,01,02,01,01,'?',01,0377,0,0333,'6','`',0274,0321,0365,037,0365,025,0372,0357,'C',0324,037,0230,0241,0352,027,0347,'B','D','?','?',0350,0262,'H',020,'Q','%',0215,0317,0307,0251,0277,0232,'Y',0235,'~',0364,0222,07,0376,0200,0356,020,'Q','%',0215,0316,0322,0266,0223,0253,0317,0273,0204,024,'I','c','s',0267,'k',0342,0206,'<',0353,0270,'A','D',0226,'7',';',0220,0305,0365,037,':',0356,020,0134,0323,'1','c','s',0271,024,'_','S','y',0327,'p',0202,0346,0231,0213,033,0235,0310,0242,0372,0233,'n',0365,'z',0277,0220,'w',010,'.','i',0230,0261,0271,0334,0212,'/',0251,0266,0317,'K',0216,':',0337,0306,0273,0204,027,'4',0314,'X',0334,0356,'E',027,0324,0333,0207,0247,0336,0226,'R','9',0240,0301,0270,0353,0177,024,0356,020,0134,0323,'1','c','s',0271,024,'V',0367,'6',0351,0243,'C',0240,'6',0310,0244,0226,0370,'n',0267,0361,014,0301,05,0315,'3',027,'7',';',0221,'E','o','s','o',036,0203,0340,'Y',012,'R',0260,'n','<','C','0','A','s','L',0305,0315,0316,0344,'Q','[',0334,0333,0347,0236,0203,0341,0343,'"',0222,'o',0223,'u',0277,0203,'f',010,'.','i',0230,0271,0271,0334,0212,'-','>',0346,0354,016,0312,0310,'R',0225,0303,0361,0340,0331,0202,013,0232,'f','.','n','w','"',0213,'N','O','=',0211,0350,'y',';',037,'z','Y',0276,'M',0326,0375,0363,'0','A','s','L',0305,0315,0316,0344,'Q','i',0311,0347,0262,'=',033,0367,035,0245,'b',0234,'R','H',037,0250,'=',0333,'0','Q','s','N',0345,0315,0316,0344,'Q','i',0311,0347,0263,'=','$',026,'}',0305,0230,0217,0335,'@',0203,0221,0322,0375,0313,'0','Q','s','N',0345,0315,0316,0344,'Q','i',0311,0347,0264,'=','$','M','b',0270,0301,0334,04,0256,'E','$',0201,0261,0322,0375,0273,'0','Q','s','N',0345,0315,0316,0344,'Q','h',0311,0347,0266,'=',036,'=','u',0371,0335,'I','H',0303,'P',' ',0344,'t',0277,'h',0314,024,0134,0323,0271,'s','s',0271,034,'Z','2','y',0356,017,'I','#',0325,0221,0134,'`',0356,0202,'W','"',0222,'P',0330,0351,'~',0311,0230,'(',0271,0247,'r',0346,0373,'|',0340,'T','q',0350,0311,0347,0272,'"',0334,'t','t',017,'L',0245,'9',0336,'I','J',0340,0320,' ',0344,'t',0276,0373,'0','Q','s','N',0346,'C',0267,0316,05,'G',036,0217,0317,'x','G',0314,'t','"',0374,0323,0304,'F','W','x',022,0271,024,0222,0206,0301,0351,'}',0322,'B',0213,0232,'w','2',035,0276,'p','*','8',0364,'~','{',0373,'t','x',0203,'d','Q',04,'`',0357,'$',0245,'y',0240,'C','d','t',0276,0321,'!','E',0315,';',0227,';','`','_',02,0243,0217,'G',0347,0300,0333,0243,'(','l',032,'x',0312,'o',02,'W','"',0222,'P',0330,';','D',0205,027,'4',0356,0134,0355,0200,'N',05,'G',030,'A',0341,'-',0321,0341,0371,0256,0372,'J','W',0232,04,'6','G','K',0374,'$',0200,'.','j','G','.','v',0300,'$',0330,'T','q',0204,0360,0326,0350,0361,0207,0246,'R',0234,0357,02,'W','"',0226,'P','y',0370,'I',0,0134,0324,0222,'k',';','`',026,'6',025,034,'a',07,0212,'"',0370,'4',0361,025,0310,0336,'"',0374,0322,'H',0361,0375,0305,'+','+',0345,'z',023,'l',0232,0222,'M',0177,0215,0260,013,033,012,0216,'0',0203,0305,0333,0244,0220,0352,0367,'/','5',0301,0261,0347,'x','`',0334,'P',0365,03,0346,'*','I','5',0237,0266,0330,05,0215,0205,'"',04,036,'=',0343,'Y',07,0270,'S',0306,0321,0375,0307,'r',01,'c','a','H',0201,07,0222,0223,0323,0352,0312,'`',0326,'A',0263,'v',0312,0245,0215,0205,'"',04,026,036,'Q',0321,'d',026,'j','x','Z','>','2','*',0367,0354,0325,'K',033,012,'D',010,',','<',0274,0236,0234,'7',0271,'p','h',0335,'M',0233,0261,'U',',','l',')',020,' ',0260,0363,'.',0212,0342,0315,'O',013,'G',0221,0221,'W',0337,0204,0331,0272,'_',0315,'I',010,'l',0216,'{',01,0352,012,0376,0356,'(',020,0331,'_','6',0306,0354,'H',0354,05,0320,0335,'j','9',0226,'L',034,036,0227,0362,0362,0313,0253,0332,'8',0354,0210,0275,'$',0345,'?','~','E',013,'0',0272,0364,0277,0224,0226,']','x',034,'v',0240,0224,'7','Z',0216,'Q','&','>','t',07,0223,0222,']','x',034,'v',0344,'^',0223,0324,024,0366,0277,037,0315,03,'|',0371,031,'%',0327,0201,0307,'t',0254,'b',0312,0324,'r',0254,0203,036,';',0212,0222,'M','x',034,'m',0376,')','a','P','=',0324,0360,'|',0326,0257,0275,'o',0342,0243,0365,037,'L',0237,0357,0306,023,'n','j','I','5',0376,'7','"',0217,'N','O','=','e',0205,'e',0373,032,'`',0321,0233,'>',0367,'4',0222,'4','<','d','R',':',0270,0270,0361,'$',0333,'&',0244,0223,'_',0343,'r',030,0355,0356,'o',0204,0200,0302,0306,0244,0201,0243,0312,'d','P','7',0336,0310,'7','^','j',')',0303,0373,'[',0237,016,'H',02,0346,0244,0220,0277,0343,'r','(',0257,0356,'m',0211,'}','>',0277,'r',0340,0327,0271,'N',0226,033,0305,'C','s','I',0352,012,'{','d',0343,0371,0240,'o',0221,0341,011,012,'.','j','I',013,0235,0310,0243,0325,0356,'<','m','<','k','(',0263,'S',0243,'E',0316,'F',0372,'1',0214,0373,'j','9',026,'A',0340,0211,012,'.','i',0334,0271,0334,0216,'=','y','<','n',0311,0351,0355,0356,0217,0375,'U',0367,0263,'{',0251,0261,0250,0246,0325,0207,0347,0300,'3',05,027,'4',0356,0134,0356,'F',0237,0250,'h',013,'`','o','K',012,0313,0371,0242,032,'3',0245,0367,0210,0276,015,'G','1','L','?',024,015,0305,0307,'z',0314,024,0134,0323,0271,'s',0270,0210,0134,0330,'R',0250,'Q','a',0330,'2',0207,026,'j','x',0232,',',0214,0212,06,0342,0343,'y',030,0306,'q','I','"',0270,0270,0356,0331,0202,0213,0232,'w','.','n','w',025,'K',033,012,'E',010,',',';','9','=','=',0316,0244,0257,0261,0336,0317,'*','j','9',0265,0373,'O','=',0313,'0','A','s','N',0345,0315,0316,0340,04,0233,012,'D',010,';','Y','a','Y','G',0336,0230,'4','f',0317,0272,'k','I',0376,'j','9',0364,0373,'d',0377,0,'}',0273,'8','A','s','L',0305,0315,0316,0347,'5',034,'z',07,'n',0300,'0',0261,0251,'!','h',0262,0271,024,015,0305,0367,0222,'S',026,'9',024,0244,'0',0270,0355,035,0302,013,0232,'f','.','n','w','b',0217,'F','O','=',0324,0220,0134,0352,'J',0315,0354,'w',0225,0231,015,0326,0243,0220,'H','.',';',047,'p',0202,0346,0231,0213,033,0235,0330,0242,0267,0270,0367,0222,'D','$',037,'z','!',0220,0331,0267,0205,0327,' ',0346,0241,0233,0365,'0',0334,0366,016,0341,05,'3',026,'7',';',0260,0305,0365,'7','|',0312,034,'Y',0251,0342,'h',0270,0343,'x',0213,0324,'S',0375,022,'s',0275,'#',0204,024,'I','c','s',0273,024,'z',0275,0307,0300,0313,07,0325,035,'_','t',0213,0363,'Q','L','S',0332,0374,'n','3',05,027,'4','I','c','s',0273,024,'z',0362,'x',0360,'r','D','$',0374,0321,05,'N',0226,0336,0212,'_',0322,0366,0236,'6',0344,0177,0324,';',0261,0307,0254,0375,0250,013,'x','G','E',0220,'i','j','t','h','y',0310,0335,'"',0365,0351,0244,'?',0343,'}',0231,0336,0303,'H',0335,'D','.','m','@',05,026,036,036,'H','t',0346,'>',')','N',0241,'}',0303,0374,0212,0215,0304,0213,0250,'l','L','n',0373,0212,0245,0315,0205,'*',0205,026,036,'&','X','5','{',0223,0232,0317,015,0316,0347,0247,'m',',','S','b','e',0322,0373,'`',026,'6',024,0210,020,'X','x',0271,'"',022,012,' ',0307,0207,0333,'$',0241,014,'>','[',022,'&',0261,'j',' ',0251,0261,0331,02,0370,025,034,'z',07,0215,'e',016,',',0325,'$','m',016,'y',']',0243,0232,0200,0352,0214,'_','a',0224,'6',015,'4',07,0351,0242,012,0363,0323,'?',0,'R',0334,'T','q',0204,0362,022,'A',0247,0335,037,0372,0240,0327,0343,'g',0322,0236,'W','~',0336,'N','X','5',0373,0227,0232,0374,0354,'z','s',0357,'#',0372,034,0260,0254,0243,'<',0325,0231,016,0227,0370,0341,0377,0,047,0364,'G','@',0342,0315,'N',0215,017,'<','|','Q',0177,0224,0177,'E','"',0370,'5','$','&',',',0247,024,015,0362,'>',010,0377,0,0312,0277,0321,0345,0203,':',0222,0257,0326,034,0311,0375,'"','X','D',0243,0357,'D','4','x','~',0236,0231,'y',0220,0377,0,0363,0372,'W',0374,'x',0257,'{',0177,0341,0237,0377,0304,0,'G',020,0,01,02,03,04,05,012,02,07,07,03,04,03,01,0,0,01,02,03,0,04,021,022,'!','A','Q',020,' ','"','0','1',05,023,'#','2','@','R','a','q',0201,0241,'B',0221,024,'3','S','b','r',0261,0301,'$','P','c',0202,0222,0242,0321,'4','`',0223,'C','s',0203,0262,'5','D',0341,0361,0377,0332,0,010,01,01,0,06,'?',02,0377,0,'s',0364,0363,'l',0265,0340,0245,0210,' ',0316,0207,024,'0','l','V',':','&',037,'s',0314,'R',':','.','M',0247,0343,0134,'l',0311,0313,0244,'z',0305,0311,'e','?',0313,027,':',0322,0177,0361,0210,0332,'u',0245,0177,0343,021,'x','e','_',0313,033,'R',0222,0353,0371,0307,'M',0311,0300,0376,05,'G','M','*',0373,'^','[','P','?','k',0346,'I',0301,0324,0322,':',031,0326,0134,0360,013,025,0375,0365,'n','f','a',0266,'G',0336,'T',020,0301,0134,0342,0376,0340,0273,0347,04,'I',0313,0267,',',0234,012,0266,0214,036,'z','}',0333,047,0341,'I',0240,0215,0265,0251,0177,0210,0327,'{','T',0250,0244,0370,030,037,'G',0237,'y',')',037,015,0252,0210,02,'i',0266,0246,0223,0211,0245,014,01,'2',0227,'%',027,0343,'x',0200,0251,'I',0246,0336,0257,'t',0337,0373,0314,0255,0327,022,0332,06,'*','4',0205,'!',0205,031,0327,'F',015,0360,0371,0302,0222,0301,'L',0223,'_',0303,0343,0363,0202,0271,0207,0226,0362,0216,'+','=',0226,0323,'N',')',0265,'f',0223,'H',01,'o',011,0266,0307,0302,0367,0371,0204,0242,'p','*','I',0314,0315,0351,0216,'r',']',0344,'<',0214,0320,'k',0274,0332,'P','O',0231,0217,0257,'o',0372,0243,0353,0321,0363,0217,0257,'o',0372,0204,'}','{',0177,0326,'"',0347,0233,0376,0250,0271,'@',0371,036,0330,']',0232,'}',014,' ','b',0243,012,'k',0222,0230,0347,'O',0333,'9',0302,012,0247,'&',0226,0347,0334,0340,0221,0332,0303,0222,'s','+','d',0214,0215,0320,0226,0371,'U',0213,'C',0355,0232,0377,0,020,035,0223,0230,'C',0303,' ','o',033,0202,0245,033,')',030,0230,'-','K',033,'(',0305,'y',0305,0352,047,'Z',0241,'D','E',0323,016,'|',0343,0353,'-','y',0210,0243,0355,0323,0357,'"',03,0215,0252,0322,'O','f','S',0263,016,0245,0246,0307,025,'(',0302,0230,0344,0204,'s',0212,0341,0364,0205,0360,0364,0202,0354,0344,0302,0336,'W',0336,'7',016,0336,035,0225,'y','l','8','1','A',0204,0261,0312,0355,0333,'O',016,'}',034,'}','D',07,0245,037,'K',0315,0234,'R','u','J',0224,'l',0244,'c',026,021,0262,0310,0303,'=',025,'Q',0,'x',0305,023,'W','<',0243,'e',0241,'O',023,033,'m',0221,0345,037,'Y','O','8',0331,'X','>',0272,0240,0203,0321,0236,0262,'a','+','A',0252,'U',0303,0262,')',0231,'r',047,047,';',0251,'7',047,0316,012,0347,037,'*','N',015,0216,0250,0337,02,0314,0234,0303,0240,0342,0206,0211,0200,'Q',0311,0217,0337,0336,026,0177,'8',0377,0,0343,025,0352,0342,'?',0314,0177,0245,'B','|',0334,021,0376,0231,0265,'y','9',037,0374,'b',0217,0210,'q',037,0346,'6',0271,'1',0357,'J',030,0351,'d','&','[',0374,'L',0250,'o',0203,0322,'O',0251,0225,'e',0201,0204,'K',0362,0215,'%','&','x','[',0370,025,0,0244,0324,034,'F',0202,0245,032,'$','c',034,0332,'.','`','{',0350,'+','Y',0213,'J',0341,0200,0326,0331,'u','_','8',0372,0312,0371,0307,'J',0233,'C','1',025,'m','U',0360,0321,0364,'U',0233,0215,0350,0354,'J',0230,0234,'y',',',0266,'3',0205,'K','H','Z',0224,0223,0341,'k',0343,'_',0370,0212,0233,0316,0352,0303,014,0270,0372,0262,'m','6',0214,02,'e',0223,'*',0216,0363,0352,0244,'V','w',0224,024,0257,06,'S','O',0316,0260,017,0321,'9',0365,'f',0352,0211,0366,0212,'K','I','0',0310,0373,0210,02,'.','H',036,0232,0367,0200,'`',0246,'b','Q',0227,0222,'p','Z',01,0212,0375,04,'4',0177,0204,'J',0177,'(','&','J','}',0306,0316,'N',0246,0320,0202,'Z','i',023,0210,0315,0245,'_',0357,026,'f','e',0335,'`',0377,0,021,04,'n',0322,0323,0244,0315,'I','}',0232,0215,0351,0362,0217,0244,0312,0276,0222,0232,'m',03,0305,'>','q',0315,0267,'s',03,0337,'A','Z',0314,'Z','W',014,06,0351,047,0341,'7',035,010,'Z','n',')','5',0204,0253,'1','^',0300,'B',0217,'=','6','z',0254,047,0365,0202,0374,0333,0244,0217,0205,0261,0325,'N',0344,'!',0264,027,026,'x','%','"',0244,0300,'S',0215,0211,'&','O',0304,0367,037,0224,05,'M',025,0317,'9',0367,0315,023,0362,0200,0334,0264,0273,'l',0240,'p',010,'M',';',011,'C',0315,'!',0324,0234,024,'+',05,'L',0266,0251,027,'3','g',0207,0312,024,0271,'[','3',0315,'}',0313,0225,0362,0202,0333,0355,'-',0227,07,0302,0261,'C',0270,'K','m',0244,0251,'j',0270,01,05,'J','5',0230,'p','m',0237,0323,'A','Z',0315,0321,'i',0134,'0',033,0266,0323,0343,0245,0202,'x',0331,0337,0256,'G',0223,0224,035,0235,0340,0247,'0','o',0377,0,0330,'[',0317,0270,0247,']','Y',0251,'R',0267,01,0231,'v','V',0373,0247,0341,'@',0254,'%',0356,'U','w',0350,0310,0373,026,0357,'W',0251,0213,'2',0222,0250,'A',0305,'f',0365,037,'^',0317,0315,0316,'K','!',0341,0231,027,0210,'S',0274,0220,0375,0177,0200,0367,0350,'`',0263,'9','.',0271,'w','2','X',0343,0252,0226,0333,'I','R',0325,0300,010,0347,034,0332,0231,'W',023,0335,0320,'V',0263,'t','Z','<','0',033,0272,016,'1',0316,'/',0353,016,031,'h','m',0261,0361,032,'@','H',0270,013,0267,0265,0341,016,'r','o','$',0271,0177,07,'f',07,0344,' ',0222,'j','N',047,0134,'!',011,'+','Y',0340,0224,0212,0223,010,0177,0224,0325,0364,'F','8',0363,'C',0256,'`','5','%','.',0206,0263,'V',047,0327,0265,0226,'g','%',0320,0372,017,'x','B',0237,0344,'u',0363,0210,0343,0364,'u',0233,0375,014,')',0227,0333,'S','N',0247,0212,'V','(','t','%',0264,'&',0322,0325,'p',02,03,0256,0213,'S','*',0376,0335,05,'k','4',021,'S','r','p',033,0272,013,0314,'s',0216,'^',0347,0345,0247,0351,'N',012,012,'l',0215,0355,'a',0316,'K',0344,0307,'(',0201,'s',0257,0247,037,01,0270,0375,0235,034,0333,037,023,0353,033,'"',02,0233,'o',0236,0232,0305,0367,'8',0366,0373,'3','L',0216,'s',0341,'y','=','a',025,'B',014,0334,0252,0216,0313,0250,034,'<',0340,'<',0360,012,0232,'W',0366,0350,'+','Y',0240,0212,0233,0223,0200,0335,0320,'^','b',0332,0357,'s',0362,0322,037,0230,033,'?',012,'5',0324,0343,0206,0211,021,'I','t',0330,'N','j',0343,037,'^','G',0220,0212,0255,'|',0352,'r','T','l',033,'+',0356,035,'.','r','O','&',0271,'C',0301,0367,0223,0371,015,'p',0,0251,'8',010,'D',0347,'+',0202,0206,0270,0246,'_',023,0347,011,'e',0206,0322,0323,'i',0340,0224,0217,0334,025,0202,0303,'?','U',0211,0317,'A','Z',0315,0,0212,0233,0222,'8',047,'v',0,025,'&','-',0256,0367,'?','-','!',0371,0201,0370,'Q',0270,'i',0241,0361,032,0235,'@',0244,0232,021,0210,0200,0334,0327,0374,0221,0364,031,07,01,0232,'x','m','8','>',04,0301,'$',0324,0234,'N',0262,'%',0345,0333,'.',0272,0273,0202,'S',010,0232,0235,01,0371,0357,036,010,0375,0304,'X','`',0364,0177,022,0263,0320,'V',0263,'@','"',0246,0344,016,011,0335,0200,05,'I',0213,'k',0275,0323,0355,0244,'?','0','6',0276,024,'e',0271,'c',0310,0350,'Z',0302,0210,'U','b',0313,0343,0371,0204,'U','&',0243,0303,'E',0207,0321,'S',0202,0261,020,'V',':','f',';',0343,'U',022,0262,0215,0227,034,'W',0264,03,'@',0354,0342,0206,0333,0247,0364,0375,0304,'e',0330,';',037,022,0263,0320,'V',0263,'@','"',0274,020,'8',047,'v',022,0221,'R','b',0322,0257,'t',0373,'h',0240,0274,0300,'y',0361,'W','0','N','[',0251,0177,']',013,0374,'G','E','P',0257,'L','"',0311,0330,'s','-',024,'"',0242,024,0364,0227,'F',0347,0331,0340,'`',0266,0362,012,026,'0',':',033,0225,0225,'E',0267,026,'~','P',020,0200,027,'2',0241,0322,';',0211,0375,0304,'e',0345,0316,0317,0304,0241,0240,0255,'f',0200,'F','H',034,023,0273,011,'H',0251,'1','i','W',0272,'}',0264,0,0221,'R','p',0200,0363,0302,0257,'`',';',0273,0266,'<',0216,0207,'?',021,0324,011,'w','m','9',0343,026,0220,'m',015,026,037,'E','N',012,0304,'B',032,'a','?','H','K',0212,0262,0222,'?','X',027,05,0316,',','t',0216,'~',0237,0270,0214,0274,0271,0273,0342,'X',0320,'V',0263,'D',0210,0311,03,0202,'w','a',')',025,'&','*','o','p',0343,0240,'%','"',0252,'8','@','q',0315,0247,0217,0366,0357,030,0362,0320,0357,0236,0255,0244,032,'x','E',0223,0260,0346,'Z',01,'I',0241,030,0300,'n','k',0376,'H',012,'I',012,'I',0304,'~',0340,'2',0362,0347,0361,',','h','+','Y',0240,021,0223,'c',0200,0335,0204,0244,'T',0230,0251,0275,0303,0304,0350,'+','Y',0262,0221,0304,0230,0232,0226,'J','h',0362,'o','m','J',0370,0206,'4',0336,0313,0237,'=',016,0371,0353,0204,0273,0266,0234,0361,0213,'H','U',0241,0243,'`',0325,030,0240,0360,0215,0223,'e',0314,'P','{','q',0227,0227,'?',0211,'c','A','R',0215,0,0214,0233,034,06,0354,'%','"',0244,0305,'x',0270,'x',0235,012,'q',0305,04,0241,'<','I',0202,0313,'$',0242,'T',0177,'t','1','6',0301,0243,0215,'*',0320,0211,'y',0326,'M','R',0342,'~','G','y','-',0353,0241,0337,'=',0305,0244,'*',0221,'e',0315,0205,0373,'h',05,'&',0204,'b',' ','7','5','x',0373,'H',012,'B',0202,0222,'q',035,0254,0313,0313,0233,0376,'%',0215,05,'J','4',02,'2','l','p',033,0260,0224,012,0223,031,0270,'x',0235,012,'u',0325,04,'!','<','I',0216,'m',025,'D',0260,0340,0234,0364,0253,0222,0336,'W','B',0376,0323,'u',0301,'[',0311,'o','3',0241,0315,0325,025,0266,0210,0252,025,0351,0242,0255,0253,'g',024,0236,021,'A',0260,0357,'p',0366,0223,'.',0301,0332,0370,0224,'4',025,'(',0320,010,0240,0271,0261,0300,'n',0302,020,'*','L','f',0341,0342,'t',')',0327,0225,'a',011,0212,015,0211,'t',0365,'Q',0250,0333,0315,033,'.','6',0253,'I','1','-','8',0216,'*','M',026,'2','V',';',0266,0234,0301,012,0320,0227,'0','P',0335,0332,'A',0262,'`','%',0355,0223,0336,0212,0213,0340,')','&',0212,030,0300,'n','k','e',']',0374,'"',0240,0324,'v','c','.',0301,0333,0370,0225,0226,0202,0245,032,01,024,027,'6','8',015,0330,'B',05,'I',0214,0326,'x',0235,01,0266,0307,0231,0312,'%',0346,0330,'R',0326,0333,'W',':',0237,0327,'Y',0336,'L','q',']',034,0306,0322,'?',026,0355,0376,'t',0331,'@','A','$',0302,']','i','V',0333,'U',0340,0305,0205,'z',030,'(','X',0336,0134,'m','#',0272,'c','f',0343,0335,0321,'J',0333,'k',0270,'b',0255,0253,'k',024,0236,'=',0220,0260,0301,0333,0370,0225,0226,0202,0245,032,01,024,027,'6','0',0335,0204,' ','T',0230,0315,'g',0212,0264,'X','l','y',0253,'(',0260,0330,0363,'9',0303,0262,0356,0246,0323,'n','&',0311,021,'1','&',0340,0352,'+','d',0346,'0',0325,'b','e',0243,'G',032,'P','P',0211,'i',0306,0372,0256,0240,'+','t','X','B',0250,0364,0321,0260,'<',0261,0217,0243,'>',0177,'f','Q',0343,0334,'0',010,'5',07,030,0262,0257,'C',05,012,0336,'U','&',0206,',',0277,'q',0357,'E','E',0342,02,0220,0242,0225,014,'D',06,0346,0266,'O','~','*',015,'G','a',',','0','z','L','U',0226,0202,0245,032,01,026,'S','s','c',0337,'v',020,0201,'S',024,027,0253,023,0242,0312,'.','N','*',0312,03,'m',0217,'3',0236,0226,0271,'U',0244,0355,0265,0260,0345,'2',0326,0230,0344,0327,016,0323,'&',0332,'?',011,0335,')',0204,0252,0255,0312,0213,036,0270,0350,'L',0234,0322,0272,'3',0324,'Y',0303,0303,'E',015,0312,034,014,'Y','X',0246,0366,0355,0244,'w','L','l',0233,0373,0247,'E',01,0266,0337,'p',0305,'[','V',0326,')','<','w',0345,0206,'O','K',0211,0356,0305,'O',030,'*','Q',0240,021,'e','7','6','=',0367,'a',010,025,'1','A','z',0261,':','(',0233,0220,':',0312,0200,0333,'b',0203,'Q',0371,'W','E',0244,':',0222,0223,'X',0231,0224,'s',0254,0312,0312,'u','d',0335,0255,033,'Z',0271,0245,0371,035,0314,0304,0312,0270,'4',0202,0250,'z','a','f',0252,'q','E','W',0351,'L',0264,0342,0255,'3',0301,'.','w','`',')','&',0240,0342,'"',0312,0305,'D','T','m',0267,0236,0366,0251,'4','0',022,0377,0,0365,0305,'E',0342,02,0220,0242,0225,014,'D',06,0346,0256,'?','i',025,'I',0250,0314,'o',013,',',0232,0272,'x',0236,0354,'T',0336,'`',0222,'h',04,'Y','M',0315,0217,'}',0330,'B',05,0361,'D',0361,0304,0350,0356,0264,'8',0252,03,'m',0246,0312,'F',0263,034,0242,0201,0261,'0',',',0253,0361,'j',0202,015,010,0306,'$',0246,0276,'"',0212,'+',0317,'p','X',07,'n','e','V',')',0341,0216,0250,'e',0372,0271,'-',0356,0230,'m',0344,'^',0333,0202,0251,'V','z',012,0330,0270,0367,' ',0202,'(','F',0366,0353,0323,0335,'1',0262,'h',0256,0351,0321,0262,'m','7',0334,'1',0260,'h',0274,'P','x',0356,0213,'-',032,0274,'q',0356,0301,'$',0324,0301,'$',0320,010,0260,0213,0233,036,0373,0260,0204,010,0262,0236,'8',0235,025,';',',',0216,'*',0200,0333,'i',0262,0221,0257,'4',0200,0232,0272,0330,0347,021,0346,'5',0247,'$',024,'o','i','V',0322,'<',016,0342,'^','L',035,0226,'Q','R','<','N',0253,'2',0350,0353,':',0260,0201,0352,'a',0211,'2',0330,0346,0233,'@','H',031,'A','[',']','+','^',0343,'E',0367,'+',0274,'"',0213,027,'`',0255,0355,'A',0241,0200,0207,0377,0,0256,'*',015,'D',05,'$',0224,0250,'b',' ','7','5',0377,0,'$',05,'$',0324,034,'F',0277,'4',0321,0253,0307,0373,'`',0222,'j','L',022,'M',04,'X','E',0315,017,'}',0335,0204,'|',0362,0213,')',0343,0211,0317,'E',0265,0354,0260,'1',0316,02,020,',',0244,'a',0270,'R',025,0300,0212,030,0236,0225,0340,020,0341,0247,0226,0253,010,047,'b','`',026,0310,0334,'O',0275,'Z',0247,0234,0262,0237,'-','Y','r','z',0222,0340,0272,0177,'/',0327,'I','q',0236,0215,0337,'c',05,016,0244,0245,'Q','e','B',0242,012,0331,0332,'F','X',0215,0366,0311,0252,'{',0246,'6','M',025,0335,':','6','M',0246,0373,0206,'6',015,027,0212,016,0257,'6',0335,0357,037,0355,0202,0245,032,0223,0214,'T',0334,'"',0302,'.','h','{',0356,0354,'#',0324,0345,026,'S',0352,'s',0321,0316,'9',0262,0310,0376,0350,011,'H',0262,0221,0206,0352,'^','q','#','e',0366,0350,'|',0306,0254,0254,0300,'6','y',0267,02,0253,0341,015,0270,'8','-',' ',0353,'M','?',0334,'i','G',0332,026,0276,0361,0256,0257,'(',0316,0234,'T',032,036,0227,0376,0272,0226,035,'M','|','r',0202,0244,0364,0215,'f','0',0320,'T',0215,0207,'?','8',0262,0261,'C',0275,0250,'4','0',020,0377,0,0365,0305,'A',0250,0200,0244,0233,'*',030,0210,015,0315,0177,0311,01,'I','6',0201,0304,'h',0346,0333,0275,0363,0355,05,'J','5','Q',0306,'*','n',021,'a',027,'5',0371,0356,0354,0247,0324,0345,026,'Q',0352,'s',0320,036,'x','Q',0234,07,'z',02,'R','(',06,033,0264,'L','c','.',0350,'7','x',0335,0255,0311,0356,0250,0325,'|',0330,012,0363,0326,0235,' ',0321,'K',026,06,0264,0245,'z',0316,0325,0303,0352,'n',0326,'.','K','l','/',0273,0201,0202,0207,022,'R',0241,0201,0213,'+',025,0212,0365,0233,0317,'}',0262,'j',0236,0351,0213,0215,0225,'w','N',0215,0203,'T','b',0203,025,'h',036,'x',0340,'p',0202,0245,033,'J','<','L','T',0334,'#',0233,'E',0315,0376,'{',0273,')',0365,'1','a',03,0327,'@','}',0361,'F',0360,'N','q','A','p',0336,'r',0203,030,0251,0243,'M','e','3','Z',0226,']','#',0347,0254,0303,']',0367,0253,0362,0326,0222,0226,034,033,'i',')',0366,0327,0262,0342,'o',0301,'C',0210,0212,0365,0332,0357,0215,05,'l',0177,'D','P',0212,035,0355,'E',0306,',',0275,'x',0316,'-','!','V',0206,0212,0236,021,0315,0267,0365,0177,0236,0356,0312,'x','b','`','!',03,'@','~','`','l',0374,'(',0317,'|',0264,'w',0222,'D','M','2',05,03,'n',0251,'>',0372,0274,0245,'-',0344,0347,0351,0255,0311,0255,'e','i','Z',0262,'l',0221,'P',0343,0310,'I',036,'f',022,'2',033,0212,021,'Q',05,0331,'^','8',0267,0376,' ',0202,'(','D','w','U',0234,'Q','c',0327,'}','i',07,0323,'8',0332,'%',07,0312,'9',0266,0217,'G',0211,0317,'w','D',0360,0304,0300,'B',06,0200,0374,0300,0374,'(','=',0203,0224,0321,0374,'O',0323,'U',0366,'q','u',0237,0313,'Z','M',025,0270,'3',0372,0352,0362,'b','H',0257,'K','_',0225,0373,0272,0365,035,0357,010,0243,0211,0273,05,016,06,'(',0241,'X',0264,0325,0351,0312,'(','{','E',05,0311,0304,0300,'B',05,06,0200,0374,0300,0332,0370,'Q',0330,']',0373,0315,0245,'_',0236,0253,'>','-',0250,'k',' ','d',0320,0325,0344,0317,0304,0257,0375,016,0360,0241,'i',012,'I',0300,0301,'r','[','m',035,0314,'D','P',0305,'i','e','Y',0306,0320,0273,'>',0315,'A','r','q','T',04,' ','P','E',07,030,017,0314,012,0271,0202,'r',0354,'M','9',0337,'`',017,0226,0257,047,0375,0345,'Y',0326,'X',0311,0264,0376,'Z',0262,0336,011,'Q',0366,0337,025,016,0215,0336,0360,0213,'.',0246,0231,034,014,'Q','B',0242,012,0231,0277,0302,'/',0271,'Y','v',':',013,0222,'8',0252,02,020,'(',' ',0,'*','L',07,0236,025,'w',01,0335,0354,'r','g','6',0216,0257,'%',0177,0335,0375,'5',0234,'9',0266,0237,0313,'V','[',0305,012,033,0362,0207,022,024,0223,0234,027,'%',0366,0333,0356,0342,'4','^','(',0254,0342,0361,'T',0346,';',015,05,0311,034,'L',04,' ','P',010,011,'H',0252,0216,020,035,'t','U',0357,0375,'{','$',0230,0376,021,0325,0344,0257,0373,0277,0246,0262,'N','m',015,'^','M',0361,'*',037,0330,'{',011,'Z','z','7','s',030,0305,0227,'S','L',0216,'q','B','*',' ',0251,0221,'_',010,'5',0270,0214,016,0375,0304,036,'*',0341,0242,0323,0255,0326,0274,027,0335,0200,0266,0324,024,0223,0210,0354,0215,'7',0334,'`',037,0236,0257,047,'}',0325,0327,'Z','M',']',0346,'?',']','^','L','W',0361,'i',0355,0330,0212,034,'H','R','`',0270,0315,0134,'k',0334,'h','7','Q','x','*',012,025,0326,033,0340,0244,0232,021,01,'/',012,034,0342,0240,0324,'E',0246,0225,0346,0234,014,04,0253,0243,'w',0272,'{',033,0277,'u',0244,0217,0317,'U',0217,04,'(',0353,'r','k',0271,0332,'N',0254,0213,0246,0340,0207,0320,0257,0356,020,016,'c',0261,'X','F',0323,0347,0332,011,'<','N',0205,0224,0366,014,0323,0224,']','q',0313,'@','C',0375,'#','y',0342,' ','-',0245,05,047,0260,0362,0232,0353,'^',0222,0236,0332,0256,0275,0366,'l',0237,'}','i','w',0251,'{','n',0323,0347,0255,047,'0',0236,016,0264,0225,'{','v',033,010,0332,'|',0373,'A','R',0215,0245,034,'t',026,'Z','7',0342,0256,0305,'T',0232,030,0262,0367,034,0342,0242,0361,026,0332,'U','<','3',0200,0225,0364,'N',0345,0201,0337,0255,'}',0321,'X',0234,'z',0266,0202,0335,'R',0201,0365,0325,0345,')',0217,0302,0215,'i',0313,0255,026,0350,0261,0255,'%','^',0263,'u','o',0344,'i',0330,',','#','i',0363,0355,05,'J','6',0224,'q',0320,'Z','d',0371,0253,0262,0323,0254,0234,0242,0251,'7',0345,0240,'!',0376,0221,0274,0361,021,'m',0265,05,047,'{','?','1',0334,'h',0353,'8',0377,0,0333,':','}',0256,0326,0234,'g',0276,0322,0200,0371,'B',0220,'x',0244,0323,'W',0224,'$',0217,0300,0260,0350,0365,0377,0,0371,0277,0260,0215,0247,0316,031,'A','Z',0315,0245,034,'t',026,0231,'>','j',0354,0366,0222,'h','`','%',0333,0225,0236,0213,'M','*',0236,020,022,0256,0215,0334,0263,0336,'s',0,0321,'S',016,04,0376,0272,0334,0236,0331,026,'U',0315,0332,'P',0361,0327,0237,'b',0226,'R',034,'%','>','Z',0255,'6','N',0304,0312,'K','~',0274,'w',0326,021,0264,0371,0303,'(','+','Y',0264,0243,0216,0202,0323,'&',0354,'U',0332,0202,'U',0266,0230,0252,'O',0244,'T','@','n','g','i','=',0374,0240,')',04,')',047,021,0272,0225,0222,'J',0256,'e',026,0324,'<','N',0254,0264,0275,'+',0316,'8',023,'w',0234,'4',0320,0340,0204,0204,0353,0263,'4',06,0313,0355,0336,'|','F',0254,0274,0312,'z',0315,'8',027,0362,'0',0313,0350,'6',0222,0342,'B',0201,0336,'X','F',0323,0347,0200,0312,012,0326,'m','(',0343,0240,0264,0321,0331,0305,'[',0260,0204,0361,'0',01,'m','+','9',0250,'A','S','G',0233,'=',0334,'"',0312,0305,0223,0276,0264,0223,026,'U',0262,0275,033,06,0250,0305,06,'6',015,027,0212,'N',0340,0250,0360,027,0304,0364,0316,05,0302,07,0220,0325,0226,'7',0331,'b',0256,035,0300,0230,02,0253,0226,']','}','5',0222,0302,0215,0134,0225,'W','7',0351,0206,0356,0302,'6',0237,'<',06,'P','V',0263,'i','G',035,05,0246,0216,0306,047,'=',0330,'J','E','I',0214,0326,'x',0230,0240,0274,0350,0242,0204,'T','m','#','=',0375,0227,'o','N','q','i','&',0242,02,0220,'J','T','1',020,033,0231,0331,'^',013,0300,0353,0316,'<',015,034,'R','l','#',0314,0353,'N',0317,0251,'=','u','s','i','>',033,0211,0231,'U',012,0207,'P','D',':',0312,0372,0310,'Q','N',0250,0227,'Q',0243,'3','b',0307,0363,'a',0372,0356,0254,0247,'i',0343,0300,'e',05,'k','6',0224,'q',0320,'[','h',0354,'b','s',0335,0320,'^','b',0322,0257,'p',0373,'h',023,017,016,0220,0365,'F','P','V',0337,'F',0357,0261,0213,016,0246,0312,0242,0206,012,0331,0270,0345,024,'P',0241,0361,0337,'l',0233,0262,0213,0256,'V','Z',03,'n',0325,0306,'}',0304,05,0266,0253,'I',':',0262,0334,0232,0205,'l',0264,'9',0305,0371,0353,'I','K',0322,0213,0263,'i','^','g','r',0343,0211,024,'n','d','s',0203,0317,035,'V',0336,'l',0321,'m',0250,'-','>','b','%','g','[',0377,0,0250,0213,0306,'G',035,0305,0224,0355,'<','x',014,0240,0255,'f',0322,0216,'1','S','p',0216,'m',0273,0233,0317,'=',0347,':',0340,0333,'<',06,'Z',04,0313,0343,0360,'$',0351,0260,0352,'k',0343,0224,'Z','O','H',0317,'{','G',012,'+','8','6',0275,'<','w',0325,'I',0241,0200,0207,'n','9',0350,0264,0331,0273,024,0340,'c','d',0331,'^','(',':','^',0230,'p',0321,015,0244,0250,0304,0314,0342,0370,0272,0262,'}','5','d',0230,0245,'R',025,0316,'/',0310,'E',07,015,0317,0322,0220,'*',0354,0251,0265,0374,0272,0317,0362,'K',0252,0271,']','#','U',0367,032,0366,'S',0264,0361,0340,'2',0202,0265,0233,'J','8',0305,'M',0302,',','7','s',0177,0236,0360,'<',0350,0277,0341,032,03,0357,016,0210,'p',031,0352,0320,0336,' ',0271,'+','q',0305,020,'R',0241,'E',014,014,'Q','B',012,0233,0275,'9','o',0354,0253,'m',0270,0264,0203,'Q',01,'h','U',0225,014,'D',06,0246,'6',034,0301,'X',035,015,0362,'k','j',0351,'f','/','_',0341,0326,0231,0345,'5',0213,0334,'<',0333,'~','C',0216,0351,0326,034,025,'C',0211,')','1','3','&',0261,'N','m','W','y','j',0261,'6',0311,0243,0215,'*',0320,0211,'y',0306,'M','P',0352,'k',0253,'e',';','O',036,03,'(','+','Y',0264,0243,0214,022,'M',0,0213,010,0271,0257,0317,'x',036,'p','l',0340,'4','[',']',0314,0247,0217,0214,04,0244,'P',014,'5',0357,026,0134,0301,'b',',',0270,'.',0301,'X',035,026,0221,0262,0270,0262,0261,'C',0276,0264,0230,0247,05,0345,0243,0233,0230,0253,0215,0216,07,030,0232,0230,0230,05,06,0325,022,0223,0202,'p',0325,'i',0206,0205,0134,'q','A','"','%','d',0321,0377,0,'I',0,'z',0356,0330,0345,'V',0323,0374,'7','i',0355,0254,0276,'H','}',']',033,0273,'L',0327,05,'b','5',',',0247,'i',0343,0300,'e',05,'k','6',0224,'q',0202,0245,032,01,026,'S','s','C',0337,'y',0316,'/',0352,0307,0276,0212,'p','l','u',0225,011,'m',02,0211,033,0222,0207,022,024,0223,0234,027,030,0351,032,0313,021,0242,0212,021,'^','(',0317,'}','P','h','`','6',0367,036,0366,0215,0241,'a',0341,0325,'p','G','6',0372,'|',0225,0201,0324,0134,0373,0211,0253,'R',0275,'_',0307,0274,0230,0223,'t','U','.',0246,0220,0364,0253,0242,0213,'i','V','N',0253,'o','4',0253,016,' ',0332,'J',0204,'7','0',010,017,0247,'e',0324,'d',0255,026,'S',0264,0361,0340,'2',0202,0265,0233,'J','8',0301,'R',0215,0,0213,')',0271,0241,0206,'{',0312,0233,0233,034,'L',04,0201,'@',' ','6',0216,030,0234,0240,'6',0330,0240,036,0373,0302,0343,';',016,0345,0201,0202,0207,022,'R',0241,024,'"',012,0332,0371,'A',07,0210,0337,'Y','V',0333,'y','e',01,'H','5',020,'Y','}',026,0222,'}',0240,0250,'t',0222,0307,0202,0362,0363,0320,0206,0320,'-','-','f',0310,031,0230,0227,0225,037,'Y','K','N',034,0325,0275,'o',0225,0331,'M',0335,'G',0251,0354,'u',0222,0245,023,0364,'G','v',']','O',0353,011,'S','J',016,'-',0301,'T',0322,012,0326,'m','(',0343,05,'J','4',02,'(','.','l','p',033,0312,'p','H',0342,'`','!','"',0200,'B','[','l','T',0230,010,'O',034,'U',0236,0372,0313,0211,0277,05,'b','"',0361,'i',0274,026,'4',022,'(',0225,0347,026,'V',')',0276,0264,0237,0224,']','r',0361,'L',024,'-','!','I','<','A',0205,'L','I',0202,0266,'q','F',')',0203,0312,017,047,0366,'y','^',0255,'q','^',0371,0351,'W',0205,0246,0335,'M',0223,017,0311,':','/','l',0334,'s',030,'j',0207,0236,026,'e','G',0367,'B','P',0221,'D',0244,'P',010,'*','Y',0242,'D','d',0330,0340,'7',0201,011,0365,'9','@','B','8','B','P',0201,'U',030,0315,0323,0326,'W','`',')','P',0264,0223,0201,0202,0344,0266,0322,'{',0231,'h',0242,0204,'T','m','#','}','i',';','*',034,010,0200,0205,0354,0257,'G',0321,'y',0264,0264,0331,'U','m',047,'3',027,'o',0276,0235,'.',0212,0315,0313,0213,0351,0361,047,'P','<',0360,0263,'*',0237,0356,0200,0204,'&',0312,'G',0,' ',0255,'f',0200,'F','M',0216,03,'x',020,0201,'|','Y','O',034,'L',04,0201,'R','b',0332,0357,'y','^',0335,0214,0255,0276,0215,0357,'c',05,016,0246,0312,0242,0206,'-',0265,0362,0202,017,021,0276,010,'w',0207,'z','*',015,'D',06,0335,0333,'g',0377,0,'X',013,'A',0264,0223,0210,0336,0320,0336,' ',0314,'2',0237,0330,0246,015,'G',0335,'9','h',017,'<',012,'e','S',0375,0320,0224,'!','!',')','M',0300,010,'+','Y',0240,021,0222,07,01,0274,011,'H',0251,'1',0232,0317,023,0240,'>',0360,0351,'O',01,0227,'e',0262,0350,0256,'G','(',0257,']',0254,024,'4','T','l',0257,'8',0262,0261,'M',0365,'8',0243,'(',0264,0223,'Q',027,'m','6','x',0242,03,0215,0232,0217,0313,'z',0364,0234,0300,0252,'V','.','9',034,0341,0326,0347,0307,'D',0312,0251,0370,0340,'!',0,'%','#',0200,020,'V',0263,'A',027,0334,0201,0300,'o',0,027,0223,026,0225,'{',0247,0333,'@',0231,'|','~',04,0237,0317,0263,0220,0241,'P','p','0',']',0225,0274,'b',0334,'_','q',0213,'+',021,'^','(',0317,'}','i',033,'#',0273,033,'&',0374,0240,'-',0263,0346,'3',0212,0246,0345,0216,')',0336,025,'|','f',0344,0210,'*','Q',0252,0214,025,0254,0320,'E','M',0311,0301,';',0336,'q',0301,0322,037,'m',01,0367,0207,'D','8',014,0373,'Q','Z',':','7',0263,0316,012,035,'M',0225,'E',010,0250,0202,0266,0277,0247,'}','i','&',0206,'(','n',0134,05,0266,0253,'*',021,'a','{',017,'e',0236,0351,'K','Y',0242,'D',025,0374,02,0344,0210,'+','T','U',0134,'0',033,0320,0363,0243,'k',0341,032,'-',0256,0346,023,0357,01,' ','P',016,0327,'a',0321,0134,0216,'"','+',0327,'k',05,0350,0264,0235,0225,0376,'q','e','b',0207,'{','P','h','`','6',0357,'[','8',012,'I',0241,0314,'@','e',0363,'G','p','W','{','s',0314,'6','z','4',0361,0361,'0','T',0243,'@',' ',0250,0235,0234,06,0364,'<',0350,0273,0341,032,'2','h','u',0225,011,'B',05,0224,0216,0330,'I',0270,'C',0262,0134,0235,'f','f','g',0202,0227,0305,011,0204,0261,'9','F',0336,0340,027,0202,0264,'Q','B',0374,0342,0373,0323,0236,0370,'4',0347,0241,0212,0307,'2',0351,0351,'G',03,0236,0275,0204,036,0221,0317,'a',0240,0264,0236,0242,'}',0367,0274,0343,0203,0243,036,0372,03,'h',0341,0212,0262,0204,0266,0330,0240,035,0260,0275,'8',0370,'l','`',0237,0210,0302,0230,0225,0254,0244,0236,'@',0355,'+','J','Y',0232,0253,0254,'w',0261,'L','%',0326,0226,026,0203,0210,0212,'(',']',026,0333,0352,0345,0275,0250,0343,026,'k',0264,0230,013,'I',0242,0204,'%',0177,020,0271,'C',0307,'T',0223,0300,'B',0334,047,033,0274,0243,'g',0254,0253,0267,0266,0225,0365,'c',0336,0,027,01,05,0327,0326,033,'l','q','&',020,0251,047,0220,0372,'M',0345,'i','<','{','Y','q',0367,'R',0322,06,'*','0',0246,'9','!',034,0352,0370,'s',0353,0340,'<',0241,'O',0315,0274,0247,0235,'8',0253,'V',0255,'*',0255,0374,'M',0236,06,'-','4','h',0277,0211,0263,0304,'h','+','j',0345,'e',05,047,0210,0336,05,0217,'X',012,030,0302,'j','z','5',0334,0255,'^','i','=','g','?','-',011,'G','t','o','2','@',0342,'`','%','"',0200,'B',0236,'y','V','P',0230,0356,0313,0247,0252,0210,016,0311,0314,'-',0205,'}',0323,'q',0204,0265,0312,0354,0320,0375,0273,'C',0364,0200,0344,0234,0312,037,'O',0335,'=',0234,0273,'4',0372,030,'@',0305,'f',024,0327,'%',0264,'f',034,0373,'U',0334,0230,'+',0235,0230,'S',0237,'s',0202,'G',0246,0341,'.','2',0242,0207,07,012,'B','&',0346,0345,'y',0245,037,0207,032,'g','M',031,'/','8',0262,0241,0353,0274,'-',0234,'8','h','m','G',0254,'6','N',0243,'g',02,0235,011,'w',05,']',0273,0262,'8','b','`','!',02,0200,'B',0235,'u','V',020,0234,'b',0203,'f',']','=','T','j',07,'e',0236,'[',016,'f',0203,'H','J',047,'P',0231,0326,0373,0334,025,011,012,0177,0350,0216,0237,0201,0373,0275,0342,0323,'k','J',0323,0232,'O','a',0264,0265,04,0214,0314,024,0256,'h','<',0350,0377,0,0246,0316,0321,0202,0216,'N','a','2',0250,0357,0271,'z',0243,0234,0234,0230,'r','a','_','x',0356,'Q','/',',',0322,0236,'y',0134,022,0230,'D',0337,'(',0201,'1',';',0304,'#',0341,'o','A','v','_','e',0314,'S',0201,0202,0225,0213,'*',030,030,0262,0261,025,027,0243,'=',0332,'M','t',':',0311,0307,'h','j',07,'@',0332,'l',0373,'h','(','V','0','B',0205,0335,0354,'7','!',010,036,0260,020,0237,0234,')',0327,'T',020,0204,0361,'&','(','6','e',0223,0325,'N','{',0200,'e','&',0335,'c',0301,'*',0273,0345,01,'3',011,'j','u','?','{','e','P',04,0324,0273,0322,0307,0275,0326,020,0236,'o',0224,'Y',05,0134,022,0263,'d',0374,0242,0255,0272,0205,0371,'+','s','U',0270,0224,0371,0230,'!',0356,'Q','`','(','|','!','W',0307,0354,0315,'=','5',0342,023,'d','{',0301,022,0214,'5','*','3',';','F','?','k',0236,'y',0341,0335,0265,'A',0362,033,0260,'[','O','3','+',0361,'>',0261,'w',0246,'q','b','Y',0272,0272,'z',0317,'+',0254,0255,'K',0366,0134,0301,'Q','e',0321,0344,'s',0212,021,'X',0266,0327,014,0267,'U',0204,'+',0302,030,'>','4',0324,')','U',0340,0301,'4',0253,'G',0202,0264,'Y','P',0250,0212,0264,0253,036,06,'(','[',047,0305,'7',0307,0325,'/',0345,037,'T','c',0352,0225,037,'T',0277,0351,0217,0253,'_',0364,0307,'P',0240,'f',0250,0262,0201,0353,01,015,0246,0322,0240,0313,0315,'0',0344,0253,')',';',')','<',025,0343,0275,0253,'/','-',0223,0233,'j',0244,'t',0134,0245,'1',0374,0313,0265,0371,0305,0363,0334,0357,0343,'@',0216,'2',0352,0363,'o',0377,0,0330,0352,0312,0177,0304,0177,0314,'u','%',07,0376,'3',0376,'c',0377,0,0254,'<',0233,'?',0346,'.',0234,015,'~',04,017,0326,'(',0357,')','?',0374,0252,0263,0371,'G','O','0',0353,0337,0367,026,'U',0275,'K','2',0254,0251,0367,016,011,020,0211,0236,'X','!',0327,'8',0211,'q',0325,036,'p',033,'m',01,010,034,022,0235,'b',0207,'S','i','0','V',0215,0266,'s',0313,'A','S','w','.',010,'U',0312,030,'n','@',0312,022,0241,0304,032,0352,0224,0250,'Z','I',0300,0301,'r','V',0361,0366,'q','e','I',')','9',035,0315,0302,0313,'x',0254,0305,0206,0323,0346,'s',0202,0304,0343,010,'}',0263,0336,020,0247,0271,'!','|',0352,'>',0301,'f',0377,0,'C',05,0251,0226,0226,0313,0203,0341,'X',0247,'o',015,0264,0205,'8',0263,0301,')',025,'0',0227,0271,'M','_','D','c',0217,'6',':',0346,03,'R','L','%',0241,0336,0304,0356,'h','o',020,']',0225,036,'m',0305,015,0306,'2','^',06,',',0250,'n',034,033,0216,0225,0260,0270,0270,0255,'>',0261,0262,0372,0275,'D','l',0276,'=','D','}','z','>','Q','{',0350,0371,'G',0327,0373,'F',0323,0253,'0',025,'d',0250,0216,0361,0212,01,'A',0341,0250,'[',0235,0227,'C',0277,'z',0227,0210,'S',0234,0224,0377,0,':',0237,0261,'w',0217,0316,'9',0271,0271,'u',0260,0257,0274,';','X','j','Y',0225,0274,0341,0301,02,022,0347,')','8','%',033,0373,'4',0336,0250,0263,')','.',0220,0254,0134,'U',0352,';',0322,0264,'l','=',0236,'p','P',0342,'l',0250,'E',0225,010,0373,0231,0353,0254,'x','v','r',0324,0323,010,'}',07,05,0210,'R',0344,035,'T',0233,0235,0336,')',0205,037,0243,'}','!',0241,0361,0263,'|','Y','q','%',012,0311,'B',0235,0224,'%',' ',0250,0234,04,02,0324,0242,0233,'l',0374,'n',0354,0210,'J',0371,'J','`',0314,'+',0354,0333,0271,'0',033,0224,0226,'m',0204,0375,0321,0330,',',0270,'/',0301,'Y','E',026,'*',0214,024,'"',0212,025,0202,0266,0357,'N','Z',0312,0362,0355,'D','M',0311,0264,0357,0215,'/',0202,0251,'9',0207,'%',0216,'G','h','A',',',0206,0346,0323,0367,015,0377,0,'(',0244,0304,0223,0315,0237,0303,0277,011,0227,0224,'u',0322,'r','L',02,0343,'I',0225,'A',0305,0303,'x',0364,0200,'g',0246,0326,0371,0305,'-',0334,'#',0366,'i','&',0322,'{',0304,'T',0366,'B',0207,022,024,0223,0234,027,032,0252,0331,0367,032,'-',0265,0307,021,024,'7',035,'C',0333,'h',0244,0205,014,0214,'t',0374,0236,0302,0277,0226,0221,'T','6',0343,07,0356,'*',0350,'<',0317,'(',0270,'<',024,0230,'<',0334,0353,'+',036,'F','6',03,'.',0217,0307,'H',0377,0,'L',0223,0344,0270,0377,0,'E','_','#',037,0350,0210,0363,'1',0376,0225,'#',0315,'Q',0266,0206,'[',037,0367,'#','n','q',0204,'z',023,035,'7','(',0257,0371,023,0,0270,035,'|',0216,0362,0256,0216,0207,0223,0331,07,'2','+',024,'m',011,'@',0311,'"',0235,0244,0273,'-','r',0261,'D',020,'E',014,'U','7','.',',',0254,'P',0351,'Y',0360,0377,0,'c','Z',033,017,'w',0263,0202,0333,0251,0262,'b',0212,036,0261,'T',0213,'I',0321,'i',0134,'O',0373,036,0303,0251,0256,'G',021,05,'@','s',0215,'w',0206,0212,0330,025,0320,0226,0221,0326,'W',0373,' ',0251,'=',012,0276,0357,010,0331,'q',0242,'<','I',0377,0,021,'{',0215,'S',0314,0377,0,0210,0273,'m',0303,0305,0177,0354,0317,0377,0304,0,'+',020,01,0,02,0,04,04,05,05,01,01,01,0,0,0,0,0,01,0,021,'!','1','A','Q',' ','0','a','q',020,0201,0221,0241,0261,'@',0301,0321,0360,0361,0341,'P','`',0377,0332,0,010,01,01,0,01,'?','!',0377,0,0323,'-','k','R',0376,0303,'`','c',0271,0312,0265,'E',027,0372,05,0177,0230,0337,'u','>','#','N',0326,0316,0374,0304,0274,0274,0264,0315,0243,0242,'O','p','R',0214,0372,0265,'e',027,0231,'S',0357,01,'^',0212,0374,0300,0253,':',0225,0374,' ',0266,'z',0300,0275,0256,'Q',']','9','{','2',016,'F',0373,0177,0330,'c','1',0262,0360,0213,0362,0224,033,014,'0',0237,0232,'&',0364,0331,'?','i',0226,0201,'O',0266,0342,'v',0347,'S',0232,0353,'u',0252,'e','o','Q',013,0314,0235,0265,014,']','*',']','~',0315,'5',0371,0301,'k',0213,017,0205,0237,0375,'&','g','f','C',0211,0225,05,'o',0342,0311,0305,0200,'$',0244,'j',0324,0277,'J','(',0373,033,'j','+',0246,'1','l',0134,013,0376,0254,034,0201,0241,0346,016,0263,0273,023,'3',0364,0220,'V',023,0231,'o',016,0363,'5',035,0214,'B',0237,0356,'}','[',0,'q','^',012,',',0201,0303,047,0312,'C','h','9',07,0260,0257,0253,'N',035,0226,'3',0312,'m','^','9',0235,0330,'V','d',0307,0324,07,' ',0331,0202,0334,0202,'4',0206,'^',0247,'d','V',0330,0352,0360,0335,'C',010,015,'F','Q',0340,0215,047,'F',0215,0211,0202,013,'}',0303,0322,032,'-','A',0364,0254,'*',0217,'t','D',0242,0354,0340,0341,0354,0326,'*','F',0337,0300,037,'_',0222,0224,'*',0177,'f',0334,0241,0340,0201,0234,0313,0304,'p',0200,0360,0332,0264,0226,0221,'^',037,'+',0341,0325,'%',')','N',023,'|',0236,020,05,'@',0236,0252,0262,'}',0265,0324,'<','l',0366,0341,'<','e',':',011,'(','I','-',037,'G','B',0334,010,'k',016,031,0313,0252,0134,0226,'c',0350,0373,'s',0211,0251,'X','-',0364,'%','U','B',0312,027,0242,'%',05,031,0270,047,':',0375,'C',')',0225,'v',04,'e','(',0235,'R','D',0134,'7',0355,0246,'<','C','3','~','`',0347,024,030,0332,037,0134,0230,0273,'8',026,'o','}','!',0325,'5',0211,'c',0340,'k',0211,'j',0322,'0','U',0270,037,'7',0302,0266,01,0221,0253,025,0245,'y',023,0205,025,0215,';',0223,'*',036,0250,0266,'~',0200,'E','(',0273,013,027,0340,031,0254,0317,04,']',0302,'h',0355,0364,',',037,07,0233,0305,0350,021,0365,0304,' ',0320,'w',0321,031,0221,'L','U',0327,0222,'N',0270,'g',0372,04,0266,03,'[',07,'b',0337,'Z',0225,035,015,0353,0347,0211,033,'F',030,'S','_','3','P',0366,0325,'D',0366,0252,0343,'{',0302,023,'3','(',0,0215,0330,0374,0223,'}',020,'A',',','U',0206,0354,'a','R',0241,'>','T',0351,0272,'S',0345,0230,0255,0272,013,0236,0327,0237,'.',0334,'{',033,'E',0325,0366,0224,'R',0354,0252,0350,0210,0261,0326,0377,0,'~',025,0260,014,0215,'X',0355,'(','v','N','U',0210,0306,033,0217,'U',' ','g','M',0356,'y',0206,'T',0370,0314,'{',0354,'%',0272,0226,'3',07,'`',0373,0362,010,0353,'&',0226,0354,02,'z','w','e',0350,'~',0365,')',0272,0343,'X',0207,'f','g','{',0203,0367,'h','@','}',010,'3','*','F',031,'g','G','R',0276,0337,0264,0302,'G',0307,0362,0330,'{',0314,0326,0200,0377,0,'I',0344,'1','f',0200,0244,'H',0241,0300,'<',024,020,032,'j',0304,'8',07,0311,0345,0355,0353,'g',0264,012,'+',0302,0367,0312,'L','y',0313,'D',035,0254,'R',0307,0363,'E',0261,0,0326,0257,'#',')','P',0275,'w',0355,0326,'Y',07,0246,0353,'}',0203,0134,0275,'a',0312,'g',05,0346,026,'>',025,0364,0253,'W','r',0363,0,0302,'(',031,0331,0372,0371,0334,'$',023,'`','v','9','>',0134,'.',0201,'+','U',03,0230,'o',0300,'<','+',' ','=',0342,034,023,0345,0362,0320,0202,0326,'A',')','i',0230,'l','x','6',0216,'`',07,0247,'C',0232,'L',0232,031,0254,0134,024,'^',0237,0277,'_','v','#','e','Z',0226,0257,033,0333,0332,0260,035,011,'h',0315,0270,036,0273,'B',02,'V',01,'o',0273,0231,'~',0257,'A',0305,033,'P','W',013,'b',0374,0236,'q','=',0355,'R',036,016,0311,0232,0223,011,'1',0261,'~',07,0205,'l',017,'y',0226,'s',0313,0345,0231,05,'0',02,020,01,'r','<','`',0365,'R',0315,0353,0315,'&','M',06,'+',027,0332,0227,0361,0334,0377,0,',','x',0210,010,0245,'~',020,0335,0204,0202,0254,'%',0371,'v','>',0275,021,0204,0300,0327,0237,'0',0256,06,'%',0260,':','w',0370,0205,'X','<',0216,0307,0205,010,037,'y',0221,'s',0313,0345,0203,'5','0',02,011,'1','|',']',0367,0223,'^',0254,0,'Q',0201,0305,0251,'W',0262,0206,0217,'B',0324,'B',0373,'`',0230,0252,'Y',0312,0217,0272,0346,0370,'*','.','n',02,'^',047,'_',0345,0343,'`',0316,0240,'-','X',0333,0335,'d',0377,0,017,0244,'>',07,'U',0201,0377,0,01,014,0232,015,'Y','a','X','^',0377,0,0361,0341,0363,0300,'S',0340,0342,0271,'h','[',0,04,06,02,0370,02,0331,'^',0177,0232,0374,0263,'.','6','S',07,0362,'?',0276,024,0272,0274,'v',0360,'|',030,0341,')','"','f','&','@',0373,0314,0327,0232,'l','m',0272,0305,',',0213,'R',0325,0342,'M','}','I','l','@',0274,0260,027,0323,':',0303,0376,02,0201,'V',0203,'X',0365,'h',0300,'=',0275,0274,'|',013,0343,0300,0271,'n',031,'T',04,'"',07,0200,02,0200,'-','t',0202,'o','s',0247,0271,0345,0260,'/','&','X',0365,0200,0325,017,0337,022,010,'+',0344,0257,04,01,0320,'~','H','4',0272,'#',0211,0334,0340,'"',0350,'=','2',033,0275,' ',0243,014,'6','=',0266,037,0360,'T',026,0340,'F','u','c',01,0366,036,'&',015,'f','{',013,0226,0370,035,'@','C',0325,0223,027,0340,'x',031,05,'0',02,022,'z',0342,0337,0274,'y','^',0313,0301,0373,0315,0374,'0',0242,'5','y',0245,'G','v',0344,0366,0360,'F','d',0301,035,'f',012,'3',0337,0327,'Q',0316,0345,'!',010,0357,'k','0',0310,'n',0301,0276,'%',0314,'M',0216,0237,0360,'V',0213,'e',0212,0221,0206,0273,0241,0341,0277,'#','K','3',0373,0253,0345,0245,07,'P',023,06,04,0305,0370,036,017,021,0324,015,'`','`','n',0307,0372,0345,0254,037,02,0247,0372,'_',0210,0323,'1','7',0222,'i','~','`',0342,0256,0247,0203,020,0350,'?','$','O','g','f',0366,0301,'2','D',0261,0215,0354,0351,'+',0376,06,'R',0316,0333,0326,'t','<',016,0306,'q',0227,0346,0377,0,0272,'y','n',0313,014,04,0302,'~','{','g','C',0301,0307,0262,0201,0254,020,0301,'y','s',017,013,0257,0300,'R',0353,0341,0356,0266,0320,0312,0216,0350,0311,0355,0340,0361,035,'`',0314,0215,0236,0231,03,0357,'1',0213,0200,0226,'?',0360,'4',033,0227,0304,'<',03,0206,'y',0232,0273,0373,'7',0226,0201,0262,0301,'0','Y',0345,0216,0207,0201,0331,035,0344,011,'[','F','~',0266,'_',0311,0315,0362,0,0360,025,0305,0306,0234,'&','&',0375,022,031,022,'m',0341,'{',0276,0352,'P',021,0346,'G',0313,0177,0256,0243,0266,0374,'C',0300,0313,'g',0226,'a',';',0376,0305,0345,0272,'l',0260,'K',0202,0274,0243,0320,0360,'<',011,'j',0300,0211,'@','|',0372,0330,0255,'O',0352,'n','y',0230,'C',0346,'2',0236,0240,0366,'y',0207,023,0257,0333,0341,0373,'}','9',026,'t',0366,0321,0225,0364,'{',0311,0234,'x',0230,0341,'1',047,'D',' ','3',0363,0230,0371,020,'K','>',0257,0260,0326,0223,0241,0340,'I',0261,0312,0312,0311,'~','q',0352,0362,0320,0246,'X','%',0241,0257,0344,'O',03,02,'W',02,0345,'O',0362,'_',027,0306,0367,025,0337,'<',0317,0274,0276,'_',0356,'z','x','w',013,'~',0334,0252,0216,0326,0346,'v',0225,0274,0357,0250,0360,0306,011,'n',0224,030,0333,0337,'c',0352,'{',033,'i',0272,021,'m',0200,033,034,0254,0304,07,0236,':',0274,0264,0341,0246,0237,0247,0216,0207,0200,0235,05,0253,031,'2',0256,0347,'W',0201,0276,0200,015,021,0270,0325,025,'6','6',03,0327,0226,016,0314,017,0237,0363,0302,0210,0320,'=',0316,'X',0364,0216,0244,0362,0346,0262,'`',0222,01,0324,0216,0271,0266,015,'&',032,'2',0203,0233,0276,0320,0310,0223,021,'>',0232,0245,0332,0300,'}',0204,'[','m',0305,0206,0330,0326,0254,0306,0217,0236,':',0274,0342,06,0376,0356,0206,0371,03,'v','t',0273,0227,0307,'o',026,030,'e',0216,0344,'s','<',0317,0207,0227,0210,'j','.',0224,0134,05,0241,0247,0251,026,'f','g',0260,0312,0330,':',':','<',0312,06,0341,0221,'-','N',0234,0326,'g',0201,0323,0272,'_',0215,0246,02,0203,0242,'}','!',0233,0367,0200,0373,'{',0305,'R',0255,0254,012,030,0245,'f','?',0325,0206,0356,0257,'3',0300,0250,0307,0200,0212,0341,'5',0262,020,'.','3','_','5',02,0362,'J','7',0212,'s',033,0334,0134,'/',022,0215,0265,0226,0236,'q',0345,0276,0330,0303,0225,0245,0300,'N',';',0221,0217,'D',0277,'f',020,03,012,0301,0254,'B','8',0350,0346,'0',0263,0304,0311,0334,0346,04,'i',0344,0222,0227,0264,'r',0363,0206,020,'M','I',0225,031,022,'`',0323,'$','9','=',0340,'3','6','"','}',010,0331,0257,02,0375,0343,021,025,0265,0325,0201,'C',024,0254,0266,0216,'H',0371,'r',0354,0200,'{','L',0360,'>',0177,0200,0302,0243,'?','!','*',0346,035,0305,0273,0342,'X',0343,0340,0263,'y','>',0134,'X',0262,0327,'_',0323,';',0344,0261,'0',0231,'`',0370,'Y',0252,0324,0314,0373,0272,'A',0,0215,0214,0370,0361,0271,0211,0373,'G','G',0232,'P','[',0237,'b','_','*',0327,0230,'x',017,0334,')',0361,'0','`',0355,'N','x',0134,'K',03,0375,'c',021,0222,0326,'*',0303,0301,0212,'V','c','W','$','r',0327,0220,'=',0246,'p',0317,'?',0302,0277,'k',0234,0217,0366,'U',0277,0327,'U',0335,0340,07,0242,0214,0230,0302,'J',0230,'^',0332,'>',0225,0302,0341,0363,0321,0203,0363,'P',0240,'F',0307,0220,0315,0206,'4',0334,'0',0367,0213,01,'1',0315,0213,0342,0363,031,0203,'>',0356,0220,'8',032,0314,0206,'5',0371,0341,020,'n',0330,0351,0337,0232,'y',0207,0222,'A',0310,0235,07,0336,030,'A','2','I',0223,0221,022,'t',0202,03,'/','8','p',0217,0222,'s',010,'X','X','?',0254,'c',0224,'S',025,'a',0206,0305,'+',035,';',0313,'K',030,',',0335,011,'H',0255,0367,'_',014,'7','h',0377,0,'2',023,0257,'q',0305,0200,0235,0214,0331,0376,'_',013,'6','e',0203,'1',0226,' ','F','c','t','p','N','6',021,'@',036,0240,0307,0354,0217,03,034,0227,0277,'g',0244,0274,014,027,'`','w','"',05,'%',0222,0220,'n','h','{','G',0215,0236,036,'n','.',0357,0345,'N',0355,014,0303,0300,'Q',0271,'d',0371,'K',0337,0226,07,'(','A',03,021,0372,0306,'#','d',0305,'X',01,0261,012,0307,'H',0362,0322,0362,016,0256,0201,015,0205,0256,0353,0341,0216,'$',0367,0272,020,034,016,0200,0343,0363,0316,0243,'2',0245,'p',0343,0342,035,0247,0372,'_','#',022,'>',0217,0177,0207,012,')','W','6',0364,037,'1','v',')',0366,0203,'I',0214,'>',0217,0201,0200,0265,0345,0231,'3',030,0344,'d',0363,'F','8',0362,'I',0354,0200,'}',0340,'1','&','I','2',0213,0202,'c',017,'!','r',07,0336,026,034,0262,'q',0260,'!',0261,0177,'Y',0304,014,0253,'W','X',015,0203,025,'b',0204,'y','`',04,';',0350,020,031,0337,0231,'^',01,01,'F','?',011,03,'X',0350,034,0201,0342,0334,035,030,0324,':',033,'E',0261,'+',0326,0270,'Q',0324,0320,0245,0346,'/',0277,032,0242,'P',0206,0342,033,'0','8','i',025,0340,'~',015,'`','=','m',0345,011,0234,0300,'N','r','D',':',0255,0365,0210,'F',0371,0214,0305,'F',0267,0354,0276,'w','s',0236,'D',0356,'q',0314,0360,'5',0327,'2','f','K','~',0244,0341,'Z',0341,0377,0,0250,0374,035,'j',0326,'#','p','1','V','!','w',0226,'&',0303,0340,020,0311,0343,0346,0257,01,06,0253,0316,014,'8','(',032,'r',0256,0223,021,'i',0376,0226,0372,'p',0342,0221,0260,0352,0307,0332,0346,'2','d','|',0316,'-',016,'I',0357,'j',0212,0256,'k',0353,'o',0207,0342,'E',0251,'o',0217,0247,03,0320,0235,'5','v','D','F',0355,0330,0367,'x','`','/',0330,0356,0212,0236,'{',0353,0315,06,0340,0311,'%','>',0204,'}',0341,0323,'6','I',020,0236,'A','1',047,0266,'A',0367,0202,0317,024,'&',036,015,020,'.',07,0315,0211,0331,0226,0255,'c',0224,03,025,'c','7',0243,0227,022,'x','y',02,01,'/',0221,'x','&',02,0307,'S',0374,'C',0300,'j',06,0234,0260,0,'|',0242,0377,0,'N',',','w',0205,033,'8',0260,'i',0244,0352,0277,0344,'x','n',0340,032,0266,0242,'>',0312,0341,0,0211,'c',0243,'0','I',0236,0376,0312,0231,0274,030,047,'m','3',0251,020,036,0327,'N',0374,0356,0367,0214,0206,'w','X',0246,'>',036,0313,'r',0307,0321,0260,0353,0303,0256,'8',0364,0332,'k',034,' ',030,0253,034,0252,'9',0274,0270,'1',0303,0311,'!',0276,0343,'R',0370,'2',0320,0342,0337,0274,'!',0220,03,0,'9',0224,0276,0266,0253,0246,0263,0225,0303,0212,0363,03,0246,'n','#',0273,0304,0201,0275,'?',0330,0360,023,0354,0252,0336,'A',0250,04,0350,0332,017,0230,014,'%',0216,0214,032,012,'u',0374,'"','7',06,'c',0315,'0',0210,'j','J',0376,0307,0316,013,02,0352,'>',04,0311,'C','5',0216,0311,'G','7',0227,'6',024,';','$',0250,0201,0253,0253,0340,0270,'7',':','{',0230,0,0,0240,0320,0346,0233,'y','z',0211,')','X',031,0260,'3',0204,022,0314,'L','/',0327,'N','+','q',0177,'#',017,0267,011,'*','u','5',04,0235,025,016,'B','3','.','c',0223,011,011,'Y',0267,'!',033,'`',021,0322,'^',0206,0235,06,'s',01,'>',0214,0271,0307,0260,032,0274,0240,033,0251,06,0337,023,'2',016,0323,0227,0240,0324,'|',0231,'C',0,0315,0336,'g','/',0313,0363,0371,'L',012,'9',0365,')','A',0177,'P',0375,0370,'F',0367,020,0372,0277,0336,047,0350,'G',0326,0374,'4','<','V',0275,0217,0331,0312,0250,0336,0273,'E',0237,'x',0332,'`',036,0326,'K',0211,0324,'`',0244,0314,'~',0243,',',0347,0227,'*',0,'{',0300,'U',030,0263,'=',0371,0223,'N',0257,0320,0223,'B',0255,':',0376,0216,034,0323,0367,0272,0342,0351,0306,0341,0250,'U',0202,0274,0307,'8',0232,04,0304,0306,'c',0360,'7',0210,0300,0211,0230,0302,0360,'"','Z',']',0261,0227,0323,'d','%',0362,0245,'(',017,'x',0204,026,0260,02,0,0326,'G',0371,0365,0372,'.',0316,0227,'s',0371,0341,0252,0357,0373,'/',0355,0305,0372,0375,0247,015,0337,0367,0207,0336,034,0323,0,0331,'0','{',0313,0225,032,'?','$',0251,0304,0336,'d',')','8',0342,0344,0346,'>',0217,0343,'B',0245,0,037,'x',0215,0225,'@','k',011,023,0342,0271,0177,0257,0243,0247,0367,04,0341,0263,'~',0361,'q','~',0363,'i',0303,'B',0376,'W',0371,016,'v',0212,024,0214,'H','g','?',0252,0342,012,'%','1','?','`','E',0203,0351,'}',015,'j',0263,033,'^',06,04,0224,031,'@',0326,025,047,'0','4',0377,0,'_','I','n',0313,0344,'8','h',0337,0274,0134,'X','=',0303,037,033,'B',0335,'~',0201,0250,05,035,0273,016,0342,'_',0257,0244,0354,0211,014,0233,0306,'8',0223,033,0346,'v',0211,'_',0257,034,0374,010,010,'|',0227,0371,0360,'m',0242,0203,027,0311,'2','X','"','}','!',0325,0342,0203,0334,0376,'8','Y','&',0247,0265,'>',0374,'X',013,0206,'g',0237,0204,023,'k',0356,'#',0357,017,0241,'b','k','F','o',0264,047,0357,'q','%',0340,'4',0315,0340,0253,'K','O',':',0370,0332,0304,0201,'T',0311,0256,0260,010,0223,'R','Y','H','j','@','5',033,0346,017,'g',0350,0314,027,'|','&',0311,'W',0355,0265,0305,'N',0305,'o','l','~',0374,' ',0322,0317,'v',0244,0235,'3',037,0242,'b',0340,'p','>','l','`',0355,'-','|','*',0305,'0',024,0325,0372,02,0340,0357,0270,'a','}','T',033,'X',0323,'1','_',0224,'~',0353,0216,025,'j','}',016,'T',024,035,'(','p',0364,':','~',0274,0270,0264,0234,047,'j',0177,0234,'O',0365,0225,'{',0375,011,023,0201,0300,0371,0261,07,0246,0325,0257,0201,'Y',013,02,0323,0241,0364,'B',030,032,0302,0256,026,0215,0360,0202,'Y',0264,024,0227,0256,0216,0342,031,'K','u',0354,'K',0347,013,031,'/',0240,0200,06,'3',0213,0261,'u',0355,0303,0334,047,0335,0373,0361,'a',',','-','u',032,0373,0307,0200,0233,'4',0251,'z','0',0366,017,0240,'T',0340,'p','>','l','A',0351,0265,'k',0341,0254,'L',0213,0340,0372,'T','q',';',0266,'w',0233,',',0340,0332,0365,0351,'1','w',0220,'~',0353,0206,0226,0265,'9',0246,0266,0254,'7','k','.','!',';','7','q',030,'3','h',016,0266,0250,0271,0220,'?','.',02,'Z',0306,0354,0216,024,'*',0217,0336,'|',0367,'(',07,017,0225,0210,0345,'6',0257,013,0362,'L',0213,0340,0372,'q','t',0210,032,0214,0254,'Y',0300,026,'6','C','m',0337,0241,0362,0203,0322,0335,0270,'v','K',0345,0324,0244,06,0266,'1','{',017,025,0216,0321,0324,'8',0205,0225,037,05,0210,0352,0304,'x','n','h','N','^',032,013,0350,0236,'p',0346,0271,'@','8','|',0254,'w',')',0265,'E',0251,0332,' ',0265,0350,'}','U',0265,'+','U',0251,'1',0202,0337,'Q',020,0222,0223,'$',0227,'}',0313,'5',0367,'o','2',0272,0202,'g',0312,0362,'$',0343,'C',0357,0302,0244,'+',0331,0261,0305,0355,017,014,'z',0,0256,'&','#',0270,03,'G','"',0275,'#',0301,'`','4',0260,'j',0361,'*',014,'1','S','Q','9',0217,'P',017,0344,0261,0334,0246,0325,026,0213,'p','&','D',0262,026,0275,0271,'e',0275,0373,023,'X','!',0271,'p',021,'Q',0243,023,0366,0212,0322,':','<',0321,0246,0314,031,'w',0267,'x',0227,0234,014,'^',0346,0263,'<','e',0352,0317,0240,'`',0246,0223,0252,'%',0361,0271,0264,'J','v','"','[','-',0346,0364,'0',0351,0205,0371,0360,0253,0302,'%','V',030,025,'O',0257,0264,0256,'<','3',0302,0373,'<',037,0264,'x',011,0210,0353,'3',0327,0355,'C',0226,0325,0,0376,'C',036,0312,'m','Q','@',0253,'A',021,'P','d',036,'Z',0300,0312,0202,'~',0341,'z','D',' ','S',' ',0216,035,0342,0323,0275,'b',02,'v',0232,'s','Q','Y',0234,'E','c','I',0251,'*','_','j',05,0211,0365,031,0213,024,04,0306,'X','#','+',0344,'!','@',0230,0337,025,021,0373,'G',022,0370,'m',0200,'A',032,0215,0274,0357,0220,'O',0201,'G','z',0303,0336,020,010,0242,0315,0236,026,0305,'q',035,030,0257,0326,0320,0317,0222,0235,0301,0376,'C',036,0312,0355,'P',031,'Z',015,'X',0356,0223,'K',0313,033,'5','0',02,'V',0260,'x',0375,0220,'-',0243,'8','8','F','b',0351,0374,0301,0351,0364,'}',0330,0325,0245,0350,0366,0216,02,0311,'J','!','z',0302,0320,'s',0210,0266,'k','p',0322,0267,037,0202,'H',0310,'~',030,021,0265,0207,016,'*',0324,0223,'v','_','~',021,0240,05,0134,0202,023,'"',0235,'}',0347,0220,0361,'6',0340,0134,'!','F',0311,'g',0304,'t','0',06,0353,0331,'=',0236,'B','w',07,0371,014,'K','+',0265,'C','D',0243,'5',0214,0213,'F',0177,0256,0134,0260,0266,0214,'Y','[',0270,0215,036,032,'i',0317,0344,'>','/',0302,'t',0325,011,011,0320,031,0235,0374,032,0330,0247,'N','1',0254,'z',0274,'u',0207,0233,0234,'I',0201,0264,0264,06,'^','(',02,0306,0316,0223,':',036,'l','2',0240,0365,0204,0277,0,0244,0260,'z','E',036,0314,0216,0232,017,'N',034,02,0237,0241,0217,0363,'P',0200,'(',024,034,0232,'=','(',0263,0266,'q',0341,012,0237,'7','k',0372,'>','o',035,0273,07,0371,'L','O','+',0265,'G','n',06,'*',0304,014,0216,'o','3','W','p','.',0235,'|',032,0221,'|','m',0177,0210,0,0,0240,0323,0201,0320,011,0230,0312,0215,0253,0242,0366,0211,017,'9',0230,'G',027,010,0244,'r',0252,0356,0357,0234,0371,'n',0306,0244,' ','6',0332,',',0254,0262,'b','K',030,'d',0376,0215,'2',0354,0203,'K',0256,06,0207,0363,'/',0207,'X',0361,'>','c',0326,0371,'T',0240,01,0321,'"',0316,'N','u','h','x','k',0320,'u','5','{',0236,'e',0222,0226,'3',0332,0352,'p',0340,0340,0177,0224,0304,0332,0273,'T','0',0302,0265,'c',0224,'K',0231,0271,0201,'q','}','z',0370,'Q',0205,'X',0267,'m',03,0201,0250,032,'q','T','f',0325,0365,036,'s','1','6','D','3','1',0306,014,0376,'B','(',0347,032,0300,0367,'7',0230,0234,'W',0213,0360,0301,0,'`',0342,'?','1',0344,0335,0237,'p',0250,0251,'O',0252,0324,02,0260,'A',0336,0230,0274,0246,'b',0365,0340,'z',0242,'W',016,04,'6','2',0303,0356,031,0372,0303,0307,017,03,0374,0246,'&',0365,0332,0240,'`','5',0253,026,'^',0314,0276,'O','1',0300,'i',0262,0220,' ','(','4',0200,0205,0343,0376,0304,'0','g',0240,'9',':',024,022,'*',0202,031,0370,025,'d',0275,0352,'7',07,'M',0247,'8',0343,0203,'$',0205,0220,'e','4','0',05,0215,0214,'d',020,'0',030,0235,0343,0212,0273,'^',0314,0257,034,023,0225,'$',0301,'_',0203,0347,0230,'T',021,0307,0243,0243,037,'s',0266,'|',0360,0241,'q',0363,01,'!',0330,012,0316,'%',0237,0206,034,07,0371,'L','y',0353,0265,'C',0340,'k','V','c','!',0230,'|',0217,'3',027,0253,0356,'t',0207,0210,'T',04,':','+','6',0230,0232,0207,023,0252,0337,0226,0230,'L',',',0347,'0',0351,01,'F','#',0264,'2',0207,0273,0134,04,0251,')',0347,'<','[',0352,0273,' ','5','x',06,'r',0233,0255,0310,']',0254,0300,0366,'E','D',0346,'(',0363,'F',0202,024,0207,0235,0314,'^','c',027,025,0324,03,0210,'m',0312,0357,'`',032,'y','f','>','d',0253,')',0325,0217,'=','v',0250,01,0261,0312,0314,'S',0273,0271,0325,0346,'P',0236,0313,0232,06,0221,'>','*',0210,0336,037,'v',0361,0326,0134,0356,0301,'B',014,'q',0207,'a',0347,0340,')',0321,0321,027,047,0253,'G',0235,'k','s',0317,'C',016,'Z',0203,023,'8','6',0236,0201,0203,'5','P',047,0217,'c',0244,0260,0253,'d','a',0376,'G',0317,'I',0134,0322,'>',0240,'$','A','F','&',0363,0334,'-',0231,'>','o','c',0244,022,'U',0203,'B',031,'L','b',0262,0244,'_',0367,'/','0',0241,0303,0320,'@',0312,0206,0273,0307,0256,0372,02,'Q',0360,0376,'S',0350,01,030,')',014,0345,07,'s',']','}',0233,0304,'R','%','&',0221,015,0356,0261,'`',0266,'f','i',0315,'T','5','u',0243,034,0202,0325,0257,'(','*','O',0222,'!',0221,'c','1',0336,0242,024,'Y','m',0300,'"',0254,'r','N','v','{',011,03,035,'r','>','-',0231,0236,'o','c',0244,015,0307,0240,'`','C',0341,0256,0232,0237,0373,'7',0231,'w',05,0355,013,'c','f',0335,'c',0202,'U',01,0254,':','`',0261,0351,0333,0350,0252,033,'K','p',0367,'c','u','-',0365,0216,02,0311,'e',0340,0357,' ',0225,'%','<',0321,0254,0243,']',0336,0205,0,0336,014,022,'^',0207,0273,0331,015,'^','(',0346,0216,'F',0314,021,0326,'6',0353,'n','e',0257,0340,'B',011,0346,0366,':','@',0214,0324,'X',07,0201,0201,'b',0376,'f',0321,'s',0250,011,'C',0213,013,'h',0305,0231,022,0230,0372,0177,'?','J',0337,0245,'9',0366,'K',0340,0330,'_','>',010,0372,017,0345,030,0241,'^',016,0217,'8',0343,0277,'m',010,0231,'&','2',0252,0306,0373,'M',0366,'a',0252,0331,0346,'0','2',0342,0307,0224,'%','^',037,0203,0322,0366,0203,0345,0350,024,022,0270,017,0274,0273,'s',03,06,0324,'P',022,0206,01,0305,0370,'x','z',0333,0362,0237,'N',031,015,'H','`',0312,'Y',0253,0250,'v',0211,'P','C',012,'s',0216,0,0365,0332,'5',06,0330,0323,0235,0231,0267,'1',0224,0277,0205,'s',0212,033,0372,'#','i','a','5',0336,'g','3',013,0257,'y','2',0371,0306,0325,0225,0240,'=',0346,'@','_','+',0230,012,03,025,0202,'7',013,01,0323,0341,0231,')',0217,0257,0361,0,024,'`','}','E','J',0360,0330,030,'w','E',0352,033,0353,0332,'#',022,'h',0306,0243,'S','6',021,'R','S',0263,0315,03,'X',0227,'~',0254,')',0326,'7',0314,0232,'C',0250,016,'z',';','e',0362,'N',0241,0355,'X',0215,0303,0260,'H',0370,0340,'d','n',0313,0277,'G',047,'#',0233,'S','p','.',0235,'|','*',0372,0214,']',0373,'C',0304,'*',03,'O',0253,'M',011,033,'"',0307,0,0371,0360,0265,'2',0237,'(','b',0236,'l',015,'A',0251,'/',05,'d','7','G','`',030,0211,0224,04,0200,0301,0262,0377,0,0134,0225,0206,'?',0306,'J',0274,0212,0325,0210,'"',0257,'h',0346,0335,0335,'+',0257,'_',012,0376,'?',0312,020,';',0216,0200,0372,0306,' ',02,0325,0310,0226,0340,0205,0247,0372,'Y','f',027,0260,0374,'L',032,'X',0330,0352,'N',0301,0315,'D',0325,0335,0300,0363,'r',0230,0263,0216,0254,'D',06,0223,'$',0224,0370,0177,023,'O',0347,0215,'0',0346,021,0356,'1','o',026,'!','4',0324,0365,'s','i','v',0201,0276,0,'(',0300,0207,0305,'f',0322,023,0347,0350,0235,0376,0256,0345,'l',0246,'m',0364,'B','g','/',0323,0202,'z',0272,'K',0227,023,'V','D','X',0376,'b',06,047,0261,0342,'k',0213,'I','|','7',0253,'g','5',0311,'(','d',0222,0311,0277,0221,'q',035,'6',0304,0230,'U',0362,0207,011,'Z',0240,0265,0210,0371,032,035,0264,'J',0326,05,0243,0264,0317,0231,'@',021,0361,'~',020,033,01,'@','x','<','A',022,'3',0240,'*',0353,'/',0352,'n',024,0357,0266,0261,06,'+',031,'{','S','X',0241,'6',0354,0313,0240,'i','/',0200,015,0311,0304,0377,0,010,022,0213,0,0343,';',0332,'t',0263,'5','r',0236,'b',0211,0205,0372,'#',0271,'`',0270,0344,0241,'j','}',0230,'7',0300,0206,0325,0206,0364,0325,0340,0332,015,0236,0274,0315,'G',0374,0134,0,0306,0240,' ','9','5',0253,020,'b',0263,0375,0230,011,0213,'i',0352,04,'C',022,0303,024,'y',0346,0214,'R','l',0331,0345,'/',0351,0215,0305,'Z','R',020,0245,0205,024,0366,0336,035,'^',0354,017,0220,0205,0343,'i','q',0213,'?','n',0262,0251,0322,0351,0237,0330,'x','<','k','h',0307,0353,'6',0246,017,'2',0375,0343,'!',0246,0343,0262,0277,']','8',034,0355,0325,':','c',0340,0244,'d','[',0277,',','f',011,0362,0311,0362,0330,'P','7',0212,0325,026,0242,0356,0367,'W',0200,0,017,0366,0267,0224,'.',0350,'t',0177,017,0264,0312,'T','`','g','t',0320,0371,'C',0357,'[',0211,0177,'@',0360,017,'V',0211,0225,0316,'d',016,0315,'e','-',0244,0345,0361,'y',023,020,023,'z','g','c','"','_','!',0270,015,012,0331,0337,'2','.',0326,0357,'Y','@',0255,'%','@','3',0240,0256,'T','S',07,0341,'M',0366,0210,0203,'l','i',0313,'5',021,'m','w',0227,'r',0315,'`','h',0352,'g',0301,0210,026,'"',0267,'x',031,0330,'d','v','c',0347,0246,'@',0305,0311,0260,0206,0372,02,016,'=',0367,'0','?',0225,0300,0271,0326,'~','S',0307,'r',0230,'w',0366,'X','A',0303,06,'b',0316,0351,0370,0214,0352,0340,037,016,'>',0320,'-',0333,';',0346,0306,0,014,0355,'2',0345,0361,0246,016,'m',0221,'S','J',0322,0276,0230,'e','%',0320,035,0360,'K',025,0366,'b','}',0252,0226,027,02,0225,'g',0275,04,0276,'M','G','2','n',0300,0200,'q',0203,013,'i',0336,'W',0205,'D',0225,0243,047,'?','8',0221,0241,0243,0224,'9','0','s',030,0311,033,0327,')','M','8','<',0226,'1',0230,0334,0307,0253,0270,0305,032,033,0374,0312,0340,037,')','R','2',0371,']',0205,0360,0370,'$',013,0346,'1',0326,0303,0274,'J',0352,'v',')',021,0243,0324,0301,0347,0235,'y','E',0312,0177,'"',0177,'I',010,033,0211,'T','%',0336,'j','b',0207,'m',011,0207,0234,'W',0325,'d',0304,0256,'U',0313,0217,0335,'s','C','}','%',0275,',','o',0373,'S','H','[','}',0250,'A','i',0352,0232,01,0327,0357,012,'.',0205,')',0231,0305,017,0256,0273,0371,0210,0225,'1',0375,0270,'!',0346,02,0331,0230,'y',0276,027,0312,0250,0201,0257,013,0325,0337,'i',0373,'@',0204,'g',017,'W',0320,'(','8',0202,'#','o',0244,0262,015,0251,0217,'t',0367,0207,0231,0235,'[',0316,0273,0360,'g',0311,0336,07,'S','!',0264,'8','M',0236,01,011,'@',0365,035,'G','h',0350,'G','B',0270,0353,0300,035,0340,0354,010,'x','F',0356,'q',0241,'`','.','N',0322,0373,0263,'r',0337,0223,0316,'f',']','{',017,0256,0251,0231,0355,0311,'#',0370,0352,01,0353,0264,024,0240,0306,0227,0326,'Y',0134,0206,' ','&','c','=','|',0374,021,0210,'Q',0230,0306,0370,0,'d',0313,'&',0275,035,0371,011,0211,0326,0371,025,016,0274,0230,0307,'O','I','-',022,0341,':',04,0373,0246,'O',0352,0245,0334,0207,'E',07,0254,0352,0272,0255,01,015,'x',0363,'8',0364,0225,'$','Z',012,0361,0250,'=','W','%',0346,0206,'V','f','f','@',0355,012,0317,0332,0322,'{','9','J',0372,0232,0233,0240,022,0377,0,'%',0376,0234,'s',023,0256,0320,'f',0215,0257,'Q','+',0227,'R',0200,0366,0231,'w','E','-',0244,'c',0316,0311,0332,'X','j',0326,'[','8',0330,0323,0375,'2',0241,010,0252,'l',0313,0366,'x',0217,'?',0266,0236,'Q','U','W',035,0247,'R','8','/',0315,0210,0362,'~',0222,0246,026,022,02,0326,'7','$','1','Q',0266,'/',0311,'g',012,020,0351,0276,0262,0271,0371,022,'r','3',0214,'x',07,'l',0304,0225,014,0134,';',0240,0313,0211,'}','L',0251,'e','C',']','}','S','1','/','S','X',01,0227,'u','(',0356,0257,0232,'z',0222,0261,0225,0312,0251,'^',03,0302,',',0276,0237,'<',0246,'v',0224,0210,05,0134,'p','^',0376,'p','I',0255,'o','>','l','(','Q',0227,0321,0347,'$','b',024,036,0252,'(',012,'q',' ',0333,012,07,'a','F','c',0300,'}',017,0317,0326,'T',0350,0134,'[','"',0303,0260,0375,0210,0323,0366,'5','Q',0305,'a',0220,0350,0233,'(',0313,'&','7',0337,0225,0207,0375,0260,0315,'I',0342,020,035,036,0374,012,037,'h',0331,'S',0372,'0',0224,014,'V',0264,0375,0347,'@','w','+',0312,'c','Z',0353,022,0365,0235,'-',030,022,0276,0235,0261,'N','0',0353,0365,'4','^',0321,'k',016,'c',0231,027,021,0275,'Q','Z','|','g','k','`',0177,0302,'W',0374,'F',0225,0226,'C',0345,037,0,0372,'=',0245,'A',0251,0225,'2',0213,021,0323,0322,'(','i',')',0332,'*',012,0377,0,0303,0364,0361,0372,02,'7',015,02,0313,0274,'A',0301,'.',0,'u','!',0201,'U',0201,05,0313,'J',0377,0,0303,0240,'S',0211,05,025,'u',0373,020,'/','f',0240,'b',0222,0236,0252,'H',0271,0357,'A',0361,0377,0,0214,0377,0332,0,014,03,01,0,02,0,03,0,0,0,020,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',' ',020,01,04,022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',' ',020,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',0,022,'I','$',0222,'I','$',0222,'I',04,022,'I','$',0222,'H',' ',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I',0,0202,'I','$',0222,'I','$',0222,'I','$',0222,'H','$',0222,'I',0,02,0,04,020,'I','$',0222,'I','$',0222,'I',' ',022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,011,'$',0222,'r',0346,'J','H',04,0222,'I','$',0222,'I','$',0200,'I','$',0222,'I','$',0,'@',04,0200,'I','$',0222,'I','$',0220,'H',04,0222,'w','3',0222,'I','$',0222,'I','$',0222,'@','$',0222,'I',04,0202,'I',' ',0222,'H','$',022,'I','$',0220,011,'&','2','I','$',0222,0240,'$',0222,'I','$',0222,'I',04,0222,'I',0,02,0,'$',0222,'I','$',0,0,'$',0222,'I',0,0213,0311,'$',0222,'I',0134,022,'I','$',0222,'I','$',0222,'I','$',022,0,'$',0222,'I','$',0222,'I',' ',020,'I','$',02,'g','$',0222,'I','"','P',011,'$',0222,'I','$',0220,'I','$',0220,0,'$',0222,'I','$',0222,'I','$',0222,'@',04,0220,010,0134,0222,'I','$',0236,0311,'$',0222,'I','$',0222,'I','$',0220,010,04,0222,'I','$',0222,'I','$',0222,'I','$',0200,'A','$',0362,'I','$',0222,'g','$',0222,'I','>',023,0310,04,0222,'@',' ',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',0,0204,0311,'$',0222,'H',0244,0220,'I','$',0220,0263,'H',022,'I',' ',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'{','$',0222,'I','!',0360,'I','$',0222,'B','$',0205,0331,' ',020,011,'$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'I',0274,0222,'I','$',0222,0301,'$',0222,'I','!','B','@','K',0,01,'$',0222,'I','$',0222,'I','$',0220,'I','$',0222,'@',' ','r','I','$',0222,025,0,0222,'I','$',0221,03,'!','P',0263,04,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',0,0223,'I','$',0222,'I',',',022,'I','$',0222,'H','I',0222,'O','M',0262,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',022,011,'$',0222,'I',' ',0220,'I','$',0222,'I','$','e','I','$','3',030,'d',0220,'I','$',0222,'I','$',0222,'I',04,0220,011,'l',0222,'I','$',0225,0311,04,0222,'I','$',0222,'B','d',0222,'I','^',0252,0311,'$',0222,'I',04,0222,'I','$',0222,'I','#',0222,'I','$',0222,03,0,0222,'I','$',0222,'I','!','r','I','$',0203,'S','<',0220,011,'$',0202,'I','$',0222,'A',' ',0212,0311,'$',0222,'I',034,022,'I',04,0222,'I','$',0220,0311,'$',0222,'I',':',0265,'I',04,0222,'I','$',0222,'I','$',0220,'c','$',0222,'I',' ',020,'I','$',0200,'I','$',0222,'I',0304,0222,'I','$',0222,'L','B',0222,'I','$',0222,'I','$',0222,'@',0344,0222,'I','$',0222,'H','$',0222,'H','$',0222,'I',04,'#',031,'$',0222,'I','#',0274,0351,'$',0222,'I','$',0222,'H','!',0362,'I','$',0222,'m',04,0202,'I','$',0222,'I','$',0220,'J','>',0222,'I','$',0222,'N',0310,0362,'I','$',0222,'I','$',0223,'I','$',0222,'I',0244,02,'H','$',0222,011,'$',0222,'I','$',0254,'i','$',0222,'I','$',0311,0330,'$',0222,'I','$',0220,027,'$',0222,'I','"',0220,'I','$',022,'I',' ',0222,'I',04,0222,'L',0201,'r','I','$',0222,'H','Y',0216,'I','$',0222,010,024,0222,'I','$',0233,'H','$',0222,011,'$',0222,'I','$',0202,'I',' ',0374,0221,'$',0222,'I','$',0217,0243,'d',0222,'H','#',0222,'I','$',0222,'o',0,0222,'I',' ',0222,'H','$',0222,'@','$',0220,'A',0276,'B','I','$',0222,'I','!','#',0311,' ',033,0311,'$',0222,'H','l',022,'I','$',0222,'I','$',0202,'I','$',0222,'H',04,0232,03,'d',0222,'I','$',0223,']','H',0222,'u','$',0222,'I','!','R',011,'$',0222,'H',04,0222,'A','$',0222,011,' ',022,'I',025,0346,'I','$',0222,'I','%','J','p',0214,0222,'I','$',0201,0300,'$',0222,'I','$',0200,'I','$',0222,'I',04,0220,'I','$',0223,023,0364,0222,'I','$',0222,034,'a',022,'I','$',0222,'S',04,0222,'I','$',0222,'H','$',0222,'I','$',0222,'I',04,0222,'I',05,',','I','$',0222,'I','$','S',0311,'$',0222,'H',0204,02,'I','$',0222,'I','$',0222,'H','$',0222,011,'$',0202,'I','$',0200,'C',0213,0222,'I','$',0222,'I','$',0222,'I','#',0340,011,'$',0222,'I','$',0222,'I','$',022,'I',04,0222,01,'$',0222,'I',04,022,'Y','$',0222,'I','$',0222,'I','$',0220,'A','$',0222,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0220,0,'4',0222,'I','$',0222,'I','$',0222,'Y',04,0222,'I','$',0222,'I','$',022,'I',04,0222,'I','$',0220,'I','$',0222,'I',' ',020,07,'$',0222,'I','$',0222,'I','<',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'@','$',0222,'I','$',0222,0,0,022,'I','$',0222,'I','$',0323,'A','$',0222,'I','$',0222,'I',' ',0222,'A','$',0222,'I','$',0222,'I','$',0222,'I','$',0,'H','d',0222,'I','$',0222,'P',0231,022,'I','$',0222,'I','$',0200,'I','$',0222,'H','$',0222,011,'$',0222,'I','$',0222,'@','"',022,'I','$',0222,'I','$','_','Y','$',0222,'I','$',0222,'I','$',0220,'I','$',022,'H',04,0222,'I','$',0222,'I',' ',0226,011,'$',0222,'I','$',0222,'M','^','2','I','$',0222,'I',' ',022,'I','$',0222,01,'$',022,'I','$',0222,'I','$',0222,',','$',0222,'I','$',0222,'I','$',0213,0341,04,0222,'I','$',0200,'I','$',022,'I','$',0222,0,'$',0222,'I','$',0222,0,0320,0222,'I','$',0222,'I','$',0222,'I',0247,02,'I','$',0222,'@','$',0222,011,'$',0200,'I',' ',022,'I','$',0222,'I',02,0222,'I','$',0222,'I','$',0222,'I','$',0220,0350,04,0222,'I',' ',022,'I',04,0222,'H',04,0222,011,'$',0222,'I',' ',016,0311,'$',0222,'I',' ',0262,'I','$',0222,'H',0346,'B','I','$',0220,'I','$',02,'I',' ',0202,'H',' ',0222,'I','$',0200,'A','$',0222,'I','!','r',03,'$',0222,'I','$',0233,0276,0204,0222,'A',04,0222,011,'$',0222,'A','$',0222,'I','$',0222,'A','<',0222,'I','$',0234,011,03,0306,'I','$',0222,'I','$','2','A',' ',022,'H','$',0222,'I','$',0222,'@','$',0222,'H','#',0262,'I','$',0222,027,0,02,'F',0344,0222,'I','$',0222,03,'d',0222,'I','$',0222,'I','$',0202,'I','$',0202,'I','$',0234,0311,'$',0222,'I','%',022,'@','$',0255,'I','$',0222,'I','$',034,'A',04,0222,011,'$',0222,'H','$',0222,01,'$',0222,05,'$',0222,'I','$',0254,'I','$',02,'C',0354,0222,'I','$',0222,'M','`',0222,'H','$',0222,'I','$',0220,'I','$',0222,011,04,0222,'I','$',0221,0321,'$',0222,'H',04,0200,0311,'$',0222,'I','$',0242,0200,'$',0202,'I','$',0222,01,'$',0222,'A',03,'R','I','$',0222,'K',0,0222,'I','$',0202,'@',';',0222,'I','$',0222,'I',0370,0202,'I','$',0222,'I','$',02,'I',0,013,'I','$',0222,'I',011,0202,'I','$',0222,'H',04,012,0211,'$',0222,'I','$',0221,0310,'$',0222,'I','$',0220,'I','$',0202,'Y','$',0222,'I','$',016,'I','$',0222,'I','$',0220,'@',022,0222,'I','$',0222,'C',0204,022,'I','$',0222,'I',04,022,'A','<',0222,'I','$',0223,0231,'$',0222,'I','$',0222,'I',04,0223,0343,'$',0222,'I','$',0217,'9','$',0222,'I','$',0222,'I',06,0362,'I','$',0222,'C',0,0222,'I','$',0222,'I','$',0222,0,04,'2','I','$',0222,'I',05,'@','I','$',0222,'H','$',06,'I','$',0222,'I',03,0202,'I','$',0222,'I','$',0222,'I',' ',0222,'{','$',0222,'I','$',0223,0350,04,0222,'I','$',0200,';','$',0222,'I','$',0256,'I','$',0222,'I','$',0222,'I','$',0222,010,' ',0372,'I','$',0222,'I','%',02,'I','$',0222,'A','4',0222,'I','$',0220,'Y',04,0222,'I','$',0222,'I','$',0222,'I','$',0,07,'d',0222,'I','$',0220,0234,04,0222,'H',07,0222,'I','$',0222,'H',020,022,'I','$',0222,'I','$',0222,'I','$',0222,'@','"',0302,'I','$',0222,'I',010,020,'I','$',027,0311,'$',0222,'I','$',0242,'I','$',0222,'I','$',0222,'I','$',0222,'A','$',0222,02,0344,0222,'I','$',0220,011,'$',0222,014,'$',0222,'I','$',0213,0,'$',0222,'I','$',0222,'I','$',0222,'H','$',0,'I',' ','n','I','$',0222,'I',024,022,'H','&',0222,'I','$',0222,'u','$',0222,011,'$',0222,'I','$',0222,'I',0,0222,'I','$',0220,'M','$',0222,'I','$',0223,011,'$',022,'I','$',0222,'I',0304,022,'@',04,0202,'I','$',0222,'I',0,0222,01,'$',0222,'H','$',07,'I','$',0222,'H',0320,0222,011,014,0222,'I','#',0322,'I','$',0200,01,' ',0,0,04,0,'@','$',0222,'H',0,0222,'H',0253,0222,'I','$','<','I','$',0200,0335,0317,0333,0300,'$',0222,'I',' ',0,01,' ',02,01,'$',0222,'I',04,020,'I',' ',033,')','$',0222,'D','$',0220,'A','%',0265,011,' ',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0200,'I','$',0220,'@',' ',0222,'I','#',0222,'I','$',0,011,'$',0220,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$',0,'I','$',0222,'I','$',0222,')','$',0220,0311,'$',0222,'I','$',0222,'I',' ',0200,010,'$',0222,'I','$',0222,'I','$',020,01,'$',0222,'I','$',0222,010,037,0222,'I','d',0222,'I','$',0222,'I','$',0222,'H',' ',020,01,'$',0222,'I',0,0200,'@','$',0222,'I','$',0222,'I','$',0202,0311,'$',0362,'I','$',0222,'I','$',0222,'I','$',0222,010,' ',02,'@',04,0,'I',04,0222,'I','$',0222,'I','$',0222,'@','%',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,011,0,02,01,'$',0222,'I','$',0222,'I','$',0222,'I','$',02,'o',0244,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','#','h','I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'@','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0237,0377,0304,0,'-',021,01,0,01,03,03,02,05,05,0,03,01,01,01,0,0,0,01,021,0,'!','1','A','Q','a','0','q','P',0201,0221,0261,0321,020,'@',0241,0301,0360,' ','`',0341,0361,'p',0200,0377,0332,0,010,01,03,01,01,'?',020,0377,0,0365,0234,0253,0276,017,0336,012,017,0301,'r',0377,0,0312,0277,0253,0210,012,'$',0276,'H',0370,0212,0274,0220,0345,'z','a',03,0344,0276,0323,'J',0301,017,0372,' ',0260,0374,01,'X','0','e',0325,'w',0177,0304,04,011,'+',0332,0210,0254,'+','x',')','3','6','r',0277,0270,0240,'1','M',0,0303,0376,0200,024,0255,0344,012,0357,0222,'u','[',0275,'(',031,'i',0346,024,0254,'a',030,'{',0236,'=','m',0267,0220,'7','k',0275,0331,0325,'n',0364,0331,034,0317,0342,0263,06,0225,0356,0370,0357,'r',0223,0240,0335,0253,0225,0274,0305,0273,0323,'D',0220,024,032,'d',0275,0301,0241,0307,0216,0367,0350,':',015,0332,'>',027,0363,027,0366,':','n',036,03,'-','@',0230,0330,'?',03,0217,035,0237,0202,0345,0320,'7','h','8','J',0356,'/',0215,0216,0232,'t',0200,0312,0324,020,0205,0203,0360,'8',0351,04,0261,'J',030,'*','Z',0226,0206,'|','>','B',0213,0227,'@',0335,0241,047,'+',0270,0276,'6',':','i','R',05,0325,0322,0243,0354,'l',0352,0377,0,0216,0234,0207,'9',0267,0375,0375,'}',021,'-',0317,'X',0267,0257,0324,0335,0341,0263,0266,0134,0272,06,0355,033,')','}',0305,0370,0330,0351,0306,0230,']',']','*',02,07,'.',0277,0363,0325,04,0261,'N','!',02,0310,'F','=',0371,0253,0263,'7',0343,0311,0323,0317,0326,0225,0270,0364,'O',0244,0305,014,0370,'T',0201,0226,']',03,'v',0201,0204,0276,0342,0374,'l','t',0300,'0','%',0134,05,'*',' ',0313,0257,0374,0365,0220,0271,0271,'_',0324,0330,0372,'@',0350,0321,0324,0354,0325,0354,0361,0376,'C',0366,'R','#',017,0320,'|','"','A',0336,0200,'n',0361,'F',016,'W','q','~','6',0351,0237,0,'J',0272,'S','f',0352,'5',0346,0361,0261,0326,026,'4','0',0315,021,0237,0300,'}','R','l',0321,0320,'?',0262,'M',036,'J','L',0342,0364,'y',035,'~',0203,024,'3',0340,0277,0215,'x',015,0336,'(',0,'y',0201,'v','8',0351,0207,'`','J',0272,'R',0366,'U',0347,0315,0343,'c',0256,'l','y','}',0217,0247,'4',017,'o',0361,0134,'f',0365,'9',035,'*',0374,'?',0262,'M','{',0224,0210,0303,0364,035,0374,017,0360,'O',01,0273,0305,014,'?','4','.',0307,07,'L',0,012,'U',0244,'h',0253,0317,0223,0306,0307,0330,'+',016,'_',0327,0323,0261,0337,0362,'A',0263,'V','3',0307,0371,015,';',0224,0271,'k','G','G',0263,0257,0320,'b',0206,'|',03,0330,0376,0271,'x',0243,0201,0352,0216,016,':','g','H','R',0255,'6','E','V','=',0317,0350,0373,025,'h',0351,034,'5','#','o',0372,0332,0257,0353,'&',0307,'m',0375,0351,0301,0302,'h',0326,'(','F',0221,'3',0367,0276,0335,0225,0313,0305,025,'?',0340,07,035,'0',0376,')','V',0227,0262,0253,036,0347,0364,'}',0243,0263,0211,0322,'U',0304,015,'{',0232,0323,0231,032,'N','_',036,0177,'H','-','q','C',022,'I',0371,0373,0277,0340,'J',0273,0305,011,017,0340,07,035,'3','R',')','V',0230,0272,0253,033,0362,0374,'i',0366,'h','#',0364,031,'+',0221,0344,0334,0370,0351,0217,'t',0310,0222,'T','r',0271,'W',0355,0372,0177,024,0335,'G','"','C',0364,035,0376,0347,0373,'R',0256,0361,'D','H',0376,'@','q',0323,'?',0342,0225,'i',0263,0250,0356,'r',0363,0355,0366,0200,'Q','%','I',0206,'J','?','v',0306,0361,0362,'W',0264,'|','p',0363,0324,'C',017,'H',0260,0371,0250,0263,'6',011,0357,0267,0320,'b',0213,0343,0355,0264,'e',0257,0227,0212,0,0277,0310,0203,0216,0231,0377,0,024,0253,'K',0347,'G','s',0227,0237,'o',0266,0201,0263,'H',0250,'h','K','K',0330,'O',0232,0231,'A','z','p',0362,'u',037,021,'2','7','+',020,034,0253,037,016,0324,0271,0307,'#','o',0241,0273,0355,'4','?',0243,0373,'J','<',037,0310,016,':','`',047,0371,'z',0324,'$',0277,0372,0207,0237,'o',0270,0,0372,034,0361,'H',0250,'s','L','E',0377,0,0336,034,0321,'D','O','S',0204,0321,0352,0272,0203,0240,0344,0371,0245,'[',010,0343,0317,'o',0240,0305,014,0375,0214,0377,0,0324,07,0366,0225,07,0341,'v','8','8',0351,0377,0,022,'U',0216,'i','e',0377,0,0220,0274,0375,0321,',','@',0303,0277,0177,0232,'D','p',0224,'N',031,0256,0204,0344,0241,'O',0274,0377,0,'[',0237,0236,0252,03,'&','G',025,0314,0221,'x',0177,0232,'S','!','<',0217,0320,'z',0350,'%','P',05,033,0,035,0216,016,0237,0271,'m','p','s','O',023,0370,013,0317,0336,'`',',','a',0333,0207,0217,'n',0330,'H',033,0362,'b',0217,' ','0',0231,0243,0220,0207,07,0361,0371,0243,'f','L','&',036,0252,'(',0272,'N',037,'4',0257,'h',037,0336,0337,'A',0212,031,0352,':',0225,'@',024,'@',0200,']',0333,0203,0247,0371,017,0205,0330,0346,0230,0267,0222,016,'^','~',0372,'i','>',0203,0333,'u','i',0333,'j','+','#','}','G','s',0252,0354,'J',0310,0341,0256,'x','.',0227,0266,0335,0251,0240,0236,'G',0350,';',0364,0222,'z',0240,012,030,'`','.',0355,0301,0323,0214,'8',0365,']',0212,'b',0360,0366,03,0347,0300,'R',0261,'I',0200,0266,0327,0275,016,0243,0373,'#','g',0254,0323,0206,030,'|',0323,0336,0,'~',0315,'>',0203,024,'3',0376,'o',0331,'P',05,027,0,'W','}',0207,0355,0351,0306,0230,'`',0325,'v',')',02,0300,0354,07,0317,0202,'%',012,0244,0315,'M','7',01,0374,'$',0242,01,0256,':',0251,'@','V','G',025,0315,015,0322,0366,0332,0224,0261,0344,'~',0206,0357,0361,'B',012,0200,'(',0351,0202,0273,0354,'?','o','N','<','A',0203,'U',0330,0244,0315,07,0260,037,'>',014,0237,'@','w',0254,0254,'4','L',0212,0313,0317,0226,0347,'Y',0257,030,'0',0363,0375,'R','!','h',022,0307,033,032,'D',0315,014,'P',0317,0321,020,'*',0,0240,'`',012,0357,0260,0347,'w',0247,034,0,0301,0252,0354,'R','E',0201,0330,017,0237,010,0315,'%','+',' ',0302,'f',0247,0314,'`','h',0177,0232,0320,'T',0221,0302,'u',']',0231,'2','$',0217,'q',0245,04,'Y','T',0273,0273,0226,0215,0251,'#',0307,'D',0323,'s','s',0237,0243,0246,'T',01,0255,020,'0','^',0215,0216,'w','z','}',0270,0206,0253,0261,'I',0233,0360,03,0347,0302,0322,'i','"',0243,'4',0320,'I',0270,0222,'_','&',0215,0273,'S','3',0303,'&',06,0227,033,0235,'c',0250,0311,03,026,'v','k','b',0203,'x','c',0231,0212,0200,'#',0347,07,0207,'w','~',0235,0376,0336,'b',0330,0244,0226,'^','@',0360,0336,0364,021,'D','^','z',0214,'a',0230,'w',047,'F',0325,'d','W',0255,0263,0332,'o','w',0342,0331,0226,'(',0303,0310,0375,0303,0333,0257,'1','W','c',0241,0240,0330,0361,'%',0245,'v','W',0,0262,'^','E',0260,'c',0212,'[',034,0304,0226,012,'N','5',0356,'I','f',0377,0,'l',0271,0245,'w',027,0306,0355,'K',0203,'c','A',0261,0342,0211,0323,031,030,'O',':',0276,'0',0,0320,0246,',',017,'3',0214,0254,'P',0262,05,0231,037,0263,'X',0262,0373,0213,0361,0273,'S',0302,0134,032,06,0307,0213,0367,06,'L',0345,',','n',0315,0313,'^',0343,'V',0330,'3','h','|',0234,0226,0373,024,'w',0225,0267,037,0215,0352,'X','K',0203,'@',0330,0361,0221,'N',0210,0310,0226,'D',0302,'5',0204,020,0,'g','M',0367,0326,020,'o',031,0251,'G',' ','D','q',0353,0244,'u',0356,0244,0250,'q',0,'|',0243,0363,0343,0205,' ',0215,0311,'c','w','c','L','t',0234,0217,'X',0301,012,021,0302,'T',010,0222,'*','7',0371,0366,'|',0266,0245,'j',013,'"','B','<',0216,'(','b',0206,'|','`',020,'J',0321,0205,04,0303,0220,0320,0373,011,0311,0370,'6','f','-',0301,0303,0345,'W','S',0321,'2',0370,0235,036,037,')',0244,0212,035,0374,'X',025,06,'i','^',0364,'}','9','y',0373,' ',0245,0234,'$',0215,06,0202,0353,0270,'3',0334,033,'7',0333,'j','z',0300,0310,0220,0235,0306,0345,'L','P',0317,0211,0243,02,'V',0210,0315,0346,0272,'r',0363,0366,0272,'~','i',022,0332,0306,0342,0201,'^',0260,'e','^','z','<','>','S','A',036,'$','`',0345,'h','Y',0307,'t',0374,0236,'~',0334,0377,0,0232,021,0251,'<','}',0323,017,'|',0237,0236,0372,'"','"','c',0361,0337,0304,03,0224,0256,02,0244,0204,0256,0237,0223,0317,0335,'@',0230,0312,0244,'B',0217,0354,0346,0254,'p',0211,021,0220,'u',0300,0225,0237,015,'>',022,0254,06,0265,'=',047,0215,037,0365,0323,0213,0363,0227,0342,0247,012,'.','"',0334,0356,0323,'5',0273,034,0207,'&',0264,'P',0351,0251,0271,0246,0343,0337,0252,0200,0207,024,'i',024,'A','k',0354,0226,0221,'W','4','1',0301,';',015,'9','7',0363,0253,'$',0236,026,0201,0254,0,0326,0200,0262,'`',0323,0376,0372,'q',0202,'R',0255,'*','x','[',036,0347,0365,0365,02,0247,0261,0206,0343,011,0204,'`',0232,022,0330,'E',0315,0271,'.',0366,0214,0343,'~',0250,010,'i',0300,0310,0350,0325,0247,0317,0263,'&','S','g',']',0232,'V',0240,0310,0344,0237,011,'J','H',0200,'2',0320,'b',047,0247,023,0236,'z','h',0336,02,0353,'L',0243,'%',0335,0377,0,037,0342,'$','X','O','Y',0336,0231,'Y','V',0355,'L','r',033,0344,'8','(',0361,0323,010,0311,0352,'u',0233,0307,04,017,0360,0234,'5',0260,'H','|',0303,0204,0331,0357,0340,0356,01,'P',06,0264,'l','A','y','p','9',0335,0351,0250,022,0322,'X',025,0213,'W','c',0216,0200,'d','+','*','a',')',036,'[',0333,'R',0263,04,0214,'T',0224,0213,'F','Q',0234,0226,0365,0353,027,'G',0321,047,'6',0266,0317,'5','1',0357,'9','C',0257,'<',0264,0244,'R',010,'O',04,'z',0352,0200,'(',0360,02,0273,0247,03,0366,0365,'!',']','V','-','8','9',0336,0226,'n',0364,'_',0251,0341,030,'s','>','d',0350,0332,0234,0203,'d','5',0230,0276,0345,0362,0275,'J',0303,0326,'X',02,'J',0202,0312,'4','w',0213,0227,0316,'f',0233,',',0367,0302,'n',':',0225,'o',01,'u','*',0200,'(',0330,0202,0273,0354,'?','o','R','F',05,'t',0321,0363,'N',036,'W','=','D',015,'g','V','d',0314,'.','N','=','4','(',0351,0237,'S','G','g','g',0254,'_','X','Q',0221,'D',0237,0314,0306,0250,'M','.','9',0230,015,'v',0206,0255,'/','e',030,0360,07,0376,0250,02,0213,030,013,0354,0340,0371,0327,0250,0225,0344,0354,'l',0335,0375,'T',0364,04,0253,0253,0326,0234,'u',0266,0216,'2','a',0230,0211,0314,'a','(',0266,'C','v',0346,'2',0356,':',0303,0134,0320,0215,0306,0215,'3','4',0271,'#',0334,033,'d','7',0205,0240,0244,'!',0376,0317,0336,0240,0334,' ',0376,0305,021,' ',035,0216,016,'=',0372,0214,031,0376,'B',0360,'T',0357,024,0257,0330,01,'P','a',024,'N',0311,'r',0200,'2',01,'m',0361,0240,0322,0332,0352,0355,'N',0314,0200,0217,017,'[','.','F','P','Y',0306,0216,0361,'e',0363,'#','H',0241,0220,0237,0261,0324,'r',047,0335,0377,0,022,'U',0336,'+','j','/',0370,034,'{',0365,026,031,'v',0324,'_',0215,0352,'m',0236,0200,'l','}',0224,'M','!',0240,0266,0356,'K',0365,0215,0242,0212,'2','z',0234,'&','G',0254,'=',0324,'2',021,'#',021,0251,0215,0313,'L',027,0247,0245,0244,027,'N',07,0330,'|',0244,0373,0237,'o',0372,0345,0330,0250,'s',0374,0,0330,0367,0352,'C',0270,'0','j',0273,024,0230,'[','F',0203,'o',0265,'$',0263,0214,'a',0215,06,023,0206,0205,02,'"','Q',0306,0345,'j','p',0337,0252,0316,030,0223,'&','N','J',0262,0327,0200,'L',0333,0312,'7',0357,0210,0253,0361,0223,0325,'l',';',0237,0372,0254,'[',0355,0247,'N','z',06,0357,024,04,'|',0320,0360,'l','u','#','p',0277,0203,0232,'@',0221,'k','h',0337,0273,0366,0342,0241,0261,0374,0371,'m','B',0310,0267,01,'q',0210,06,'C','p',0235,0347,'4',0243,'H',010,0356,'7',':',0250,'6','i',0256,'Z',0343,020,0356,0212,'G','`',0313,0210,0245,0306,'9',022,023,0270,0343,0355,'$',04,0262,0350,033,0264,'@','e','w',027,0343,0250,'G',05,'*',0324,0255,'S','f',0374,0277,0255,0367,'C','Q','[','3',0227,0224,0361,0333,017,0346,0215,0262,027,'5','6','M',037,0354,'u',0203,'!','[','$',033,017,'g',047,'8',0246,'n','K',0234,'1',0252,0324,0344,0373,')',' ','.',']',03,'v',0217,04,0276,0342,0374,'q',0324,'J',0220,'.',0256,0205,'=',0214,0276,0275,0336,'6','>',0362,'w',0343,0215,0304,0331,033,'?',0321,'z','}',010,'/',0276,'2',0255,'G','1',0222,0373,'O','Y',0342,0241,'-',0231,'4','H',03,0210,0302,'f',0263,0356,'P','t','=',0236,033,0367,'/','Y',0307,'_',0277,021,0320,'n',0320,0342,0225,0334,'_',034,'u',024,022,0342,0222,0333,0360,'j',0330,0343,0337,0357,0220,02,0244,'F',021,0334,'t',0251,'M',0276,06,0347,'c',0372,0322,'u','h',021,'$','z',0277,0221,'J',035,021,0321,'4','h','3',0226,0264,'b','Z',037,0243,0205,0332,0307,'X','#',0267,0220,'(',0314,'-',0335,'V',0357,'V','3',0213,'/','c',0357,0351,0340,'9',010,0267,'4','5',0223,0246,0250,0371,'B',0315,01,'+',0332,'M',023,'D','n','=',0372,0256,0304,0232,'7',0247,0305,0252,0214,0356,'w',034,'d',0323,'B',0213,0343,0247,'9','G',0203,0347,0312,0201,0240,02,'Z',0256,0263,0325,015,0200,015,033,034,0373,'R','%','.',0370,023,'H',04,'$',0274,033,0237,0211,'.','h',0322,'B',0314,'K',0236,0346,0344,0332,'}','N',0252,'M',0232,'6','*',0364,'p','n',0177,'g',0231,'|',0364,'A','P','f',0205,0271,01,']',0216,0207,'U','+','I',0372,'7','y',0330,0247,'N','U',0325,0327,0301,037,015,0300,0214,047,0235,016,'@','c','N','X',035,0271,'k',0337,0252,0234,0244,'r','5','e',07,'@',0325,0233,0271,'%','-','b',0335,023,0216,'b','c','}',036,0225,0213,035,'I',0270,06,0315,0271,'x',0367,0251,'?',')','W',0301,0206,031,'*','d','1',0231,0217,';',0217,'P',0355,'X',027,'D',0306,036,0312,'~','z',0232,'&',',',0352,'&',023,0316,0241,'@',0352,'9','?','N','G','R',0375,0,'D',']','>','E',0216,0242,0206,0237,'0','~',012,0231,0342,0376,016,017,010,0346,0232,030,0251,'k',035,0366,'1','m',0261,'4','k',0331,'%',0227,0220,0235,'H','F',04,0226,0210,'c',0231,'I',0362,035,06,015,'{',0362,0307,0307,'M',0220,0354,'j',0266,'*',0364,0347,06,0201,0261,0341,'a','#','v',0334,'M',0206,0245,020,0315,'M',0361,0227,'q',0306,'z','p','Q',010,04,'L',0251,0264,0366,0276,0257,'C',033,0370,033,0233,'Q','6','d',0304,0334,0341,':','1','m',0365,027,'b',0222,'<',036,0300,'|',0357,0341,0250,'A',022,'&','G','r',0233,0355,0341,0240,0317,0342,0363,0206,0204,02,'6',0350,0232,'b','m','N',0242,06,07,'7','{',0240,0364,022,0241,0352,'4','S',0372,014,0237,025,0345,0232,'Q',036,0264,'t','/',0223,0346,0254,0376,0256,0277,'G','_',0272,'0',0277,0223,0232,037,036,0233,0346,0234,0351,0302,012,0372,'R',026,0203,0330,017,0237,017,'q',024,0351,0326,01,'n',0374,0267,'k',0255,'$',0306,0260,'N',0212,0277,'u','{',0336,0317,'!',0322,0305,0312,'W','&','j','*',012,'2',021,'@',0341,'z',0265,0317,0210,0342,0345,'B','&',0311,0227,']',0366,';',0350,0324,0314,0326,'M','V',0311,0243,0320,020,013,0262,0275,0237,0227,0372,030,0210,0306,0231,'_',0201,0367,0253,'w','?','s',0334,037,0307,0371,0245,'6','X','x','R',0236,'h','z',0177,0242,032,'y','a',030,'}',0177,'X','i',0346,0222,0306,033,07,013,0363,0247,0372,'_',0322,0220,0231,')',0360,'B','j',0311,0352,'C','{',0264,01,0201,'"','a','?',0322,0376,'H',0332,0234,0332,0256,'6',0307,'j',020,036,035,034,0303,0263,0271,0365,'"',04,0345,032,0240,0205,0216,024,0365,0377,0,'H','R','K',',','#',033,0217,0276,'y',0240,0325,'`','F',0311,0213,0235,0366,0317,0244,0320,022,'I','G','V','d',0302,'2',0303,0213,07,0223,0247,0372,'L','o',0134,0,020,0217,'+',0330,0276,'1',0134,0177,0361,0217,0377,0304,0,'-',021,01,0,01,02,04,04,05,04,03,01,01,0,0,0,0,0,01,021,0,'A','!','0','1','Q','P','a','q',0321,020,'@',0221,0241,0360,' ','`',0201,0261,0301,0341,0361,'p',0200,0377,0332,0,010,01,02,01,01,'?',020,0377,0,0326,'c',0313,0212,'-',0316,0264,0246,0220,'P','n','t',0244,0350,'J',0321,'E',010,0342,'}',0211,'"','u',0261,'L','5',0376,0230,032,'0',0323,012,017,'G',0353,'Z',0206,012,0303,0314,037,0260,047,'N',0266,'*',0370,0362,0220,0305,0277,'T','"','I',0307,0247,'N',0266,'*',0370,0362,0304,0301,'z',0,03,0216,0316,0235,'j',0370,0362,0364,0244,0223,0361,0234,'{','E',0305,0345,0254,'T',0360,'=',016,'=',0242,0342,0362,0326,'+','L','z',031,'K',036,031,'P',0250,'G',0215,0210,027,0245,'G',03,0215,0214,0271,0341,0341,0215,0213,037,023,'w',031,0,'/','J',0216,'5',',','g','L','y',0253,015,0306,'{',0321,022,0274,06,'(',0227,027,0,'#',05,0251,'c','l',0356,0206,0264,036,010,0344,0206,0206,0301,0336,0336,'&',0352,0327,0212,'`',0301,0315,0233,'m',0375,0347,'k',0360,0321,0364,'a','Z',0237,'4',0241,0345,'x',014,'P',0317,022,0301,0203,0233,'?','^','D',0321,0364,0212,0244,0206,0201,0260,0357,'o',023,'w',020,0301,0203,0232,'?','^','C','W',0206,0213,0325,0372,0360,0243,023,'n',0324,'T',0257,01,0212,021,0341,0230,'0','r',0257,0203,'G',0223,0210,016,'o',0357,' ',0221,0203,015,'w',0232,021,'$',0360,'7','V',0274,047,06,016,'E','|',':','<',0247,0334,0271,'O','m',0332,0260,'#',07,'o',011,'M','*','L',037,'9',0243,0320,'A',0227,0212,0301,'A',0363,0217,'+',0236,0347,0216,0134,'V',023,0210,0336,0201,0222,'O',02,'Z',0371,0224,'Z','U',0350,' ',0313,05,'`',0326,0200,0377,0,0213,0312,011,' ',0241,0222,0207,03,'S','J','E','A',016,'c',0262,0305,'c',0254,037,0232,'x',020,0241,0237,',',0213,'J',0254,'"',0306,'X','+',06,0264,03,0313,01,'s',0300,0204,0230,'4',0210,0240,0304,0314,'I',0253,0250,'{',0320,0262,'I',0340,'n',0362,0210,0223,012,0260,0213,031,'`',0254,04,0264,'C','S',0314,04,'b','V',0265,0314,0224,0212,0202,034,0327,'e',0254,'E',0203,0340,'"',0206,'|',0212,'$',0302,0245,'M',',','e',0202,0200,0225,0243,032,0236,'h',0230,0264,'P',0211,'%',011,016,0273,0323,0321,0353,0315,'I',0253,0242,'{',0321,0262,'I','Z','Q',0273,'=',02,'a','S',0207,'K',031,'`',0240,'%','h',0314,0270,0257,'8',0343,'@',0315,0,0201,0205,']','B',0206,'s',0134,0226,'*',0302,'>',04,'(','g','1',0302,'a','S',0207,'K',031,'`',0240,'%','h',0314,0270,0257,'<',0223,'L','4',0360,0260,015,'#',04,'9',0251,'5',0202,'c','=',0350,0311,'$',0360,'7','e','8','L','*','t',0351,'c','-',030,022,0264,'f',0134,'W',01,'e','I',024,'<','5',0211,'j','o',0337,'9',0311,'b',0254,03,0340,')','C','?','[',0204,0302,0247,'N',0226,'2',0321,03,026,0267,023,0277,03,'I',0246,036,035,0206,0257,016,0271,0251,'5',0200,'c','=',0350,0311,'$',0360,'7','}','.',0223,012,0344,0253,031,'`',0203,032,07,'w','~',014,0313,'J',0322,0202,0307,07,'z','J','=','y',0314,'K',015,'a',0370,'_','j','D',0326,0205,'(','g',0301,0322,'a','I',0312,0266,'Y',03,0306,0260,026,0267,'x','B',015,'$','P',030,'$',0253,0202,'{',0320,0316,'h',010,022,'R',0201,0370,']','N',0215,0372,'>',0264,'l',0235,0375,'<',0,0251,0205,'#',0313,030,'<','j',04,'k','w',0205,0273,'<',025,0340,0237,0267,0315,0351,'T','8',0330,0347,047,'J','i',0205,'M',021,0243,'.',0370,0352,'4','k','w',0206,0244,0320,'A',015,'E','&',0375,0235,'+',037,'z',0227,':',0237,0311,'B','$',0236,'b',0372,0352,'4','k',0277,021,0351,'E','&',0375,017,0343,0265,',','*',037,0337,'M',0374,0265,0305,0361,'M',032,0353,'P',0202,'~','o','R','l',0207,0324,0357,0326,0211,'0',0323,0354,0261,'b',031,'W',0364,'=','J',0302,0270,'}',0236,0236,'D',027,032,0304,'@',0251,032,0177,020,0177,')',0336,0261,0244,'b','7',0317,'8',0333,0370,'B','x',0311,0206,0225,',','q',0373,'u',0255,'0','s',0364,0274,0356,0271,0370,0275,023,'$',0224,')','B','<','a','c',026,0213,'@','/',0220,'r','8','}',0236,0265,0351,0321,0331,0275,'"','Q',0273,0213,'i','_',012,0237,0353,0311,011,0206,0241,0311,0356,0134,0353,0271,'H',015,'#','B',0224,'K',0211,0254,'b',0322,'|','g',0372,0362,0263,'^','7',',',0326,'&',0303,'o','m',0352,0347,022,'P','%',0246,'_',0356,0376,0274,0270,030,'i',0243,026,0316,0356,0364,0,030,0217,020,'P','%',0246,0177,0350,0376,0274,0324,0262,0341,'q',0323,0372,0375,'T',0371,0343,0265,'C',0303,'T',022,0323,0277,0364,'e',0202,0240,'1','k',014,'%',0244,'1','p',0332,0200,0314,'f',0240,0340,0323,030,'p',0246,0211,'o',0233,'V','1',0202,0332,0307,0256,0315,014,0223,0302,0300,'N',0212,'w',07,0366,0314,0217,'}',0355,0343,0212,'<',0204,0327,0374,0345,'P',0213,0243,'g',0267,'L',0324,022,032,'@','C','M','~','i','s',0247,'j',0225,'}',0352,'g',0204,01,'S',012,'G',06,031,'e',0212,0321,'X',0333,0227,0322,0340,'$','u',0257,'@',0233,0235,'7',0351,0351,0265,0,0221,0316,'1','T','|','k','J',030,'?',0277,'N',016,0211,'0',0244,'s',030,'B',0350,0177,'?','^',0232,'Q','9',0177,'C',0327,'z','P',0300,'~','i',0274,0377,0,0271,0304,'@',0371,0312,0233,'1',',',0270,0353,037,0272,02,'h','<',021,0302,'a',0134,0205,0266,'d',0377,0,0365,'e','D','9',0376,'+',037,0353,'.','u',0357,'S','0',0231,0323,'e',0205,0316,0333,'T',0240,'q',0271,'r',0241,011,0340,'.',023,012,0307,'Z','m',0230,0356,0303,0336,0200,010,'2',0336,'T',0273,'w','[','?',033,'Q',')','4','K','g',' ',021,013,0367,0345,'C',034,'+','v','z','v','x',02,04,0302,0247,'N',0226,'3',026,013,032,0320,023,'C','7',012,023,034,',','M','j',0370,',',0331,0371,0266,'p',032,'1','R','w',0134,0353,0271,0317,0375,0240,'-',07,0316,0310,0212,0221,':','X',0314,0365,020,0320,015,017,'!',04,0244,0347,'X','b',0373,0247,'r',0210,0264,034,0351,0303,0302,0347,'m',0252,'D',0351,0251,'q',0363,0212,'=',04,036,'|','R',015,'*',0320,'7',',',0366,0251,0205,010,'K','g','1','H',011,0362,036,'U','7','D','{',0364,0355,0257,06,0300,0,026,0243,'Q',0243,'[',0371,0134,'U',0200,0321,0332,0240,027,'F',0317,'g','4','H',0223,025,0211,0263,0346,0233,'o','O',05,0344,'Y',0371,0347,0317,'J','1',0323,0201,0300,0300,012,03,'Z',',','m',']','|',0274,';',0223,0235,'`',023,0263,0252,'w',0242,'!',0243,0232,0223,0255,'b','I',0367,'N',0234,0271,'P',0207,0223,0201,0,0303,012,0343,0333,0315,06,0200,0334,0263,0331,0347,'R','!','B','j','_',0347,'<',0351,'?',0324,0263,0331,0347,'^',0247,013,0235,'~','G',0,'P','/',0235,0177,'^','r','=',0245,0215,0350,0321,0364,'l',0377,0,'|',0263,0211,0210,0205,0377,0,0212,022,04,033,'v',0336,0271,'g',0316,0235,'j',0342,0363,'t',013,0241,0347,0240,024,0225,0216,'I',0367,0235,0316,'t','"','I',0233,037,'d',0321,0332,0237,05,0344,'l',0377,0,'t','f',0312,0235,'l','T',0343,0307,'6','u',0233,'s',0340,021,'$','4',0221,0314,0304,0355,0265,022,'R',0346,'h',010,025,012,0223,'k','s',0257,'.','t','3',0215,0262,0321,0324,0343,'[','6','U',0207,0275,04,'a',0300,'`',0243,0244,0303,'u','A',030,'}',0236,0237,047,'9',021,0253,0366,'{','Q',0216,'N',0224,0262,'X',0323,0276,'j','c','h',0371,024,02,015,'8','$',04,0223,0346,0224,0247,0340,0267,':',0367,0365,0315,01,016,0224,0362,0341,0247,'N',0371,',',027,'?','Y',0261,'&',0227,'h',0306,0201,0301,0220,'p',0212,0134,'<',0334,'m',0323,0267,0245,'B','B','3','$','F',0271,0211,0363,0235,011,0322,'~','F','D',0277,',','3','>','f','(',0327,010,'&','(',0236,0227,0265,0353,0336,0260,'1','F',0317,0226,0347,0231,':','h',0222,'u',0276,'D',0203,'g',034,0263,032,0334,'2','D',011,0324,0321,0332,0236,'?',023,'g',0263,0313,0323,',',0316,0325,0355,0177,'j',0233,0375,'c',0276,0265,'@',030,'r','Q',0201,'+','A',0316,'u',0341,0261,'J','J',023,'V',0345,0316,0273,0234,0350,'D',0223,'$','A',032,'u',0331,0207,0246,'@','p',0315,013,025,'=','i',0310,'1',0341,033,037,'J',0307,'g',0322,0246,0244,0246,0340,0320,';',0273,0360,0364,0232,'u','n',0377,0,0310,0355,'X',030,'a','~','Y',' ',033,'L',0372,0345,0230,'i',0343,03,'P',0333,0211,'N',0364,'K','G',0366,0353,'B',0222,030,'M','L',0200,'7',0304,0377,0,037,'a',0330,013,033,0374,0345,'L',05,0216,0366,'y',0235,0276,0270,0205,0272,'?',0303,0366,'"','r',0222,0224,0207,'/','G','n','O',0177,0251,'`',0357,'?','b',0201,'B','J','5','%',0333,'s',0247,'.','T',06,0307,0320,'U',016,0177,0257,0261,0264,0304,0251,'t','m',0313,'=',0232,'$',0245,0317,020,011,'p',0177,0217,0261,0371,0326,'$','b',0304,0326,0237,0207,0362,'h',0366,0374,0320,0211,'%','2',0212,047,016,0213,0276,0277,'d',0240,0220,0322,0230,031,0371,'i',0212,010,'0',0364,0377,0,0214,0177,0377,0304,0,'+',020,01,0,01,03,03,02,05,05,01,01,01,01,0,0,0,0,01,021,0,'!','1','A','Q','a','0','q',020,' ',0201,0221,0241,'@',0261,0301,0321,0360,0361,0341,'P','`',0377,0332,0,010,01,01,0,01,'?',020,0377,0,0351,'Z','1','x','7','Z',026,01,0374,'6',',',0324,0332,'r',0354,'6',024,07,0336,0235,'M',0231,05,0336,'a','S',0327,0232,'~',0230,0253,0305,0313,0226,07,'3','F','(','N',',',0336,0363,'F','#',',','Y',0275,0312,0214,024,0376,'8','(',0327,0244,022,0366,0250,0364,'6','Y','O',0265,011,0221,'j','?',0346,0247,'R',0366,'O',0251,'u','c',023,0211,0243,'g',05,0,'B',0347,0345,03,'?',024,030,0231,'I',025,'"',0177,0354,'(',0244,0,0311,'2',015,0245,'/',0241,'@','$',04,0315,'v',0320,0366,0240,'p',0220,0177,'P','7','T','_','9','$',';','1','A','A',0260,0250,'{',0276,'I',0363,'M','K',0275,'K',0275,'h',0216,'g','{',0303,'Y','0',021,0307,0200,0346,0210,'8','t','?',0260,0236,0365,04,0253,'`',0356,0214,'G',0263,'B',0246,05,'l',0357,0201,0355,'C',0314,0377,0,0350,0250,'(','x',0344,0210,'}','T',0253,0360,0366,0,014,'"',0254,'S','W','5',02,':','2',0270,0306,0230,0254,0231,03,027,'p','l','z','x',0317,0320,'M','M','=','F',04,0300,0134,0230,'o','Y',047,0204,0304,0320,0205,0300,0342,0222,0262,'Z','2',';',0307,023,0265,0350,'L',010,0204,'=','a',0267,0257,'S',0232,0204,'C',0346,0247,'q',0366,0177,0263,'Q','I','|',0202,0212,0230,034,0227,0346,0277,0244,0374,0327,0310,')',0374,0326,0264,'z',01,'|','?','V',0242,0222,0275,0231,0344,031,0203,'/',0245,':','@','O','<','N','v','3','{','%','8','*','d',0300,0344,026,'#',0274,0324,0322,0255,'O',0323,0252,0353,'S',035,0204,0374,0222,0216,'0',0353,'Q',0251,'`',0270,0345,0370,'G',0275,'I',0304,0203,034,'Y','H',0366,0242,0376,'y',016,'I',' ','(',0367,'F',015,0277,030,0371,0245,0310,0331,']',0232,0217,010,0250,0241,'`',0247,'f',0233,025,'H',0261,'(',0360,0,0201,'4',0366,0246,011,0326,0345,0236,0261,'5',0213,0375,'R','O','W',0356,0206,'[','[',' ',0354,0232,'?','K',0205,'>',035,0,' ',0316,'s',0351,'M',0226,'f',0340,0256,'O',0335,0342,034,0324,'G',0374,023,'R',014,'$',014,'o',032,0324,0273,0324,0375,'d',0245,'<',0332,025,'S',033,0230,0365,'Q',0330,0262,'!','h','N',0247,'s',0342,0203,0306,0201,0341,';',0231,'=','|',0251,0332,0216,0300,012,'K',0266,0244,0257,0342,017,05,0207,'D',0260,012,'j','(',0302,'1',0356,'s','H',0261,'n','I',0370,'*','N',0206,010,'?','4',']',0203,0331,0276,0372,',',026,020,'3','C','8',0277,0220,'$',' ','w',0272,'9','7',0242,0242,'.',0264,'?','F','N',0200,']','[',01,'@',0272,0230,0346,'-',0243,0306,0226,'/',0336,0231,'%','J',0223,02,01,0263,0202,0354,0336,'b','*',']',0352,'z','E',0332,' ',0242,03,0201,'1',0270,0254,0224,'l',0177,'0',0342,07,'d',0245,'e',0306,' ',07,':',0250,0362,'g',0373,'e','^',0311,037,0236,024,0206,0325,'D','r',04,'?',025,03,0231,0226,'m',0354,0363,0351,'D','0',0344,'$','7',0221,0240,047,'O','Z','m','$','t',0345,0240,0262,05,0357,06,'7',021,0274,'k','Q',0342,'-','H',0260,010,0324,'v','w',0266,0364,'(','0',' ',016,021,'2','x','"',035,';',0,'+','a',0232,05,0237,06,0307,0201,0260,0260,034,0273,024,0321,0205,0202,'l',0376,0371,0362,0207,'q',0341,'!','(','t',015,0321,'_','t',0324,0202,'>',0340,'}',0250,'k','s',0260,'z','a',0240,0340,0243,022,';',0207,0203,0277,'f','E',0334,0365,'g',0350,'T',026,0251,0242,0262,'8',0272,'d','*',0332,0333,0323,'k',0216,0207,'T',0303,'%',0330,'/','s',011,'K','`','T',0245,'N','U',0326,0225,'z',02,'Z','B','"','J','H','v','V',0245,'Y','P',024,0254,0245,0360,'4',024,'9','=','G',0277,0303,0356,020,'Q','g',')','w',0271,0360,'%',030,030,0315,0310,0356,0301,0232,0370,025,0217,0267,0237,0340,'7','~',0364,'@',0262,025,035,0304,0250,'b','D',015,'N',0354,'=','J','a',0271,02,0306,0313,0376,0252,0275,0351,0206,'"',0301,0331,020,0354,'P',0226,'~',0220,'Y',0231,0,034,0222,'R',021,0321,025,0203,'M',0251,0362,0360,'3',0254,'/',0266,0346,';','b',0215,0306,'w',0325,022,0242,0342,'Z',0264,'4',0202,0313,'5','q',0261,0340,011,0260,0214,0273,024,0215,0225,04,0331,0375,0364,0236,'0','p','t',0207,017,0243,'@',04,'d','n','4',0314,'E','-',021,0243,02,'"',0335,0213,0203,0371,0353,0250,'*',0314,047,0333,'7',015,0241,0231,'v',0265,0320,'g',0330,'*',0206,0217,'u',031,'W','e',0301,'j',0231,0251,'_','0',0226,0246,0325,'d',0226,'`',012,0372,'R','n',0260,0271,'H',0231,'D',0271,0302,'T',0354,'b',0270,'L','.',021,0234,025,'C',0251,0303,0216,' ',0265,'@',0324,'T',023,0323,0202,0240,0332,0240,0245,0367,0241,0341,0263,'%',035,'p','3',034,0322,'B','N',0301,0346,0214,0302,'P',0243,047,'T',0224,032,0222,'t','*',0353,'w',',',0233,0300,'1','f',0375,0,'^',0260,0245,'V',0206,'q',011,0231,0200,'5',016,'|',011,'1','-',0251,0320,')',0,'m',015,0261,0375,0363,0323,'c',0305,015,0211,0262,0354,0373,'P',020,' ',010,017,03,0225,020,05,0340,0261,0360,035,'i',0205,'`','2',0322,'T',02,027,0346,047,0330,014,'k',022,'J',01,'c',0367,0267,']','6',013,04,05,0251,'W','/',0230,0315,'5',0341,010,0203,'!','(',0304,0222,'T',04,0335,'(','U',0,'@',013,'1','s','D',0222,0321,')',032,0357,03,0217,0206,'B',0365,'j',015,0250,06,0224,021,0364,'P','R',05,07,0374,'`',0306,0330,0334,'y','/','Q',0355,0246,0351,0265,0202,0370,0233,011,'.','J','^','"',0202,'`','D',0270,0333,0227,'O',0224,047,0264,0211,'S','B','&',0353,0222,07,0372,'_',03,014,'[',032,0255,0,0336,0234,025,0310,'-',0217,0357,0236,0233,0371,'l',02,'U',0245,033,0361,'d',0263,'i',0313,0340,031,'*',0344,'h','-',0337,'j',')','`',0213,'@',' ',0352,0233,'1','J',' ',015,0352,'{','j',0246,'G','q',':',0216,0301,0202,0363,014,'c','N',020,'e','U',0272,0256,0264,0253,0237,'(','K','R',0305,0227,0220,0300,02,0257,05,020,0205,01,'I','I',0272,0341,'N',0354,'9',032,'>',0354,0,0214,'D',0254,015,'V','j',012,0217,0247,0212,0202,0201,03,'B',0345,'h',0213,0204,0311,'@',',',025,'8',03,017,0360,0226,'r','S','E','K',0224,014,'a',0311,'k','%',0235,'<',014,024,'D',0224,'h',0200,'U','r','B',0374,0333,0276,0,0270,'v','5','Z',01,0275,'2','u','0','-',0217,0357,0236,0233,0257,030,011,'V',0201,0370,'J',0334,037,0277,030,0217,0350,'=',0306,0314,'t','#',035,'S','d','i',014,01,0252,0324,'j',0220,0312,026,03,033,06,'.',027,0271,'l','T',0317,0224,'K',024,0337,'#',0232,'4',020,'[',0264,'Z',0315,0312,0177,032,' ',0315,'i','4',0332,',','F',0371,0250,'(',03,07,0326,'%',0266,0245,0220,0340,0206,0272,0203,'%',0211,033,'1','z','+','q',0332,'H',0300,0267,'W',0302,0326,'W',012,0233,012,'U','%',037,'&',0357,0200,037,017,0252,0320,015,'Z','L',0212,0320,'[',015,0335,0336,0232,031,'8',')','V',0216,'r',0310,'7',016,0307,'<',0370,04,0260,']',0245,'m',0202,017,0276,0321,0333,0212,'0',0,020,01,0,'y',0211,0231,0345,'~',0,0325,0257,0312,'U','C',030,')',',','+',0240,0237,'j',032,0233,'c',0205,0270,'B',0315,0,0202,0222,0330,'=',0267,';','x','I',0340,024,0372,'C','6',013,027,'&',027,'C',05,0213,0334,'[',0355,'J',0271,'|',0243,037,017,022,0300,05,0325,0332,0235,016,010,0303,0310,0255,027,0375,'N','(','4',0224,0221,0316,012,0,0323,0353,0306,021,0225,'H',02,0210,0376,0312,'<','N',016,017,0277,0201,0377,0,047,0252,0320,015,'Z','x',0353,0220,033,015,0335,0336,0233,0326,'h',')','V',0207,0263,0367,016,0307,'<',0370,' ',0,0253,'`','5',0256,037,0215,0306,0303,0366,'(',0,01,01,0200,0363,0204,0202,0365,'^',011,036,0227,'{','x','h','m','W','_',0301,0351,0365,0320,'8','h',0371,0326,0207,0271,0333,0371,'*',0354,0315,0300,01,'V',0257,06,0331,'q',013,0360,0344,0340,031,'U','r',0255,'O',0220,0315,06,013,0244,'E',0325,0330,'7','h',0253,0330,0243,0335,027,';',0232,01,06,0304,'E',0,'i',0365,0346,0330,'R',0246,0,0245,014,0245,'8','V',0243,0371,'>',01,0374,0322,0256,'W','c','v',0232,0242,0304,0222,0303,'w','w',0247,06,'d','4',0253,'E',0301,'.',0344,';',034,0363,0340,0355,0225,0,'%','Z','%','N',04,0311,0260,'7',0342,0261,0320,0376,'&',0347,0200,0317,'l',0342,02,01,0332,0330,0305,'1','<',0300,'V',0376,'5','=',0250,027,'l',0312,017,0201,'P',0243,036,037,'r',0222,0213,0371,03,0342,0307,0177,' ',0226,0201,'i',0213,'&','u',0337,'A','B','m',0327,'@',0353,0264,'q','@',025,027,0237,0243,0236,0243,0204,0,0225,'p',024,0316,024,0277,'w',0252,'m',0273,0257,0201,0317,024,0253,0225,0330,0335,0244,0362,0271,0271,'a',0273,0273,0323,0215,0201,036,'U',0241,'O','p',01,0376,'/',0340,0213,0314,012,'U',0330,0242,'(',0300,'R','s',0177,0221,0322,0376,036,0345,'8','k',0372,0233,0274,047,0331,0231,0274,0356,0237,0234,0321,'l',022,0322,0335,0345,0257,'l',0370,04,0207,0203,0220,'l',0225,'r',036,']','d',0315,0267,'R','b','R','"','y',035,'J',02,0336,0214,'5',04,'&','u',0337,'@',0256,'L',010,01,0246,0203,'B',0240,0231,0372,'h',0216,0220,'2',0,']',']',')',037,'T',0265,'w',0253,'m',0273,0340,'i',0307,'*',0327,0203,'w',0212,0277,0264,'7','1',0313,'w',0355,0323,0217,'q',012,'U',0242,0347,0270,020,0177,027,0360,04,0200,026,'T',0350,'Q',':',031,'[',0207,'M',0352,'c',0344,0246,0221,0314,0237,'q',0342,0200,0212,'%',0304,0322,0255,',',0306,'@',0363,0263,0346,0260,'K',0265,0370,'v','|',02,05,030,0360,0373,0224,033,'u','}',0211,0,'4',0357,'G',0250,0312,'B',031,'t',037,'4',03,026,0377,0,0300,'P','*',0300,'e','i',0232,'@',0254,'z',0233,'m',0337,0,'*','2',0237,'c','v',0256,' ',0362,'c',0356,'?','o',0277,'I',0336,0224,025,0326,0200,030,0134,'G',0370,0277,0201,0202,0320,0262,0252,0235,'=','.','H',':',034,0363,0324,'m',0224,0277,'>','}','#',0353,'Z',0227,'=',0222,0212,'h',0326,0236,0357,'/',0307,0200,'%',0242,0260,0233,0215,']',025,0261,0356,'v',0237,'r',0212,0232,'B',0201,0337,0353,0324,05,'X',012,'u',022,'%',0214,0356,0337,'w',0300,014,0234,0247,0330,0346,0245,'W',034,0277,0303,0366,0351,0272,0222,0201,'Q','3',03,017,0204,'A',0372,'j',0,0325,'h',0134,'0',0342,0325,0240,0310,0237,016,0251,06,0363,0346,037,0277,010,'7','/',0261,0346,'@','R','%',0304,0253,032,'0',032,'_',0311,'Z',0235,')',0134,0341,'4',0360,'6',0224,'J',047,0261,0263,0311,'B',0214,'I','T',036,'v',';','y','R','Q',0333,0352,026,012,0325,'M',0330,0306,0355,0367,'i','e',0227,'4','s',0316,'h','-',022,'y',0363,0371,'>',0335,'4',0376,'Q','@',0240,0205,0203,0374,036,010,'=',0261,' ',')','G',04,01,0204,'>',015,0212,0204,0333,'#',01,033,0274,'H',0273,0320,'r','c',0262,0225,0243,'a',0220,'M','#',0251,0337,01,0361,0340,'0','?',0313,':',03,0365,'D','>',0202,'k','W',0354,'l','+','w',0207,'J',020,'H',0311,0271,'H',0227,05,02,'n','5','y',0366,0307,0263,0267,'^',0345,0373,0320,0356,'8','r',035,0372,0223,'~',0274,')',0227,',','z',0233,'}',0332,'U','U','e','u','h','O',0234,0225,'2','T',0363,0177,0243,0355,0323,'M',0245,037,'p',0361,'G',0340,',','X',0374,036,017,'x','-','@',037,0272,0262,'-',0363,013,'?',0260,0361,'~',0203,0221,' ',013,'2',0330,011,0202,011,026,'Z','9','O','L',0337,0376,'c',0303,0333,0367,0301,0321,0305,'&',0364,'-','=',0236,'_',0212,014,0206,'.','[',0274,'x',02,'J',047,0341,0275,036,'K',0324,'A',022,'S','v','2',0255,'O',0236,0234,023,':',0364,0302,'<','@',0236,0241,'k',0326,0333,0356,0322,'"',0252,0267,'V',0200,'I','I','b',0230,0242,'=','4',';',0222,0200,'}',0335,0212,0224,'X',030,0377,0,0300,0360,'h',0264,'O','<',033,0255,'?','l',0300,0307,0347,0276,'M','>',',',0323,07,0264,0230,0250,024,0260,'2',0334,0217,'C','}','z','w',0373,03,'8',0220,0377,0,'5',0360,'Q',015,0321,0241,0377,0,017,0267,'O',030,0230,'X',0250,' ','`','>','h',0322,0213,011,'H',0222,'4',010,'P',0354,'(',0303,'Z','6','`','B',0360,0325,0316,';','Q',0254,'y','9',023,'q',0361,0217,0243,'#','0','/',0343,0252,'o',0316,0224,0214,0212,'2',0256,'Z',0235,0311,012,0301,'K',031,036,0347,0370,0267,'M','4',0252,0,0323,0227,'b',0206,0200,03,016,'x','6','<',031,0203,']','{',0344,0246,'n',0367,'K',',','"','-',015,0266,013,0276,'l',07,'K',020,033,027,0314,014,033,0225,0337,0245,027,0303,022,'c','y',0350,0205,037,'(',0243,'j',03,0330,026,'y',0336,')',020,05,0307,016,0347,'P',0302,0244,0270,0237,'F',0325,0277,0352,0277,0350,'x','>',0204,'t',0203,0225,0252,0211,0214,022,0230,'^',0332,0234,0237,'H','-',04,0243,' ',0330,0377,0,012,'r',0310,0225,'Y','V',0217,'r','I','@',024,0335,0371,'t',0377,0,0213,'t',0323,'{','4',0300,'n',0354,'P','C',011,'p',0272,0354,'l','x','<',0300,0242,016,0371,0347,'c','Z',0273,'1','q','w',0313,0370,0251,0277,0177,'!',04,'L','p',0337,0322,0214,'a',0230,'a',0325,015,0355,'i',0334,'|',0252,0335,'"',0341,'R',0313,'a','#',0302,0324,'t','e',0264,')',012,'&',0214,0351,0321,'X',0245,0315,0222,0,'7',015,0255,037,'4',0252,'[',0353,'S','^',0375,'v',0315,034,'d','+',' ','p',0215,'A',0224,0337,0324,'"',0240,024,0366,'1',0244,0235,'E',0235,0262,0270,'J',0264,0374,'A',']',0331,0247,'z',02,'a','"','H',0323,0374,')',0200,'J',0323,'A',016,';',']',036,'J',017,'G',047,'"','n','?','B','H',0215,'/','!',0330,0376,'E','"','g','J',0222,0255,0,04,0222,0200,')',0372,033,'e','[',0277,']','4',0346,0277,'A',0273,0305,02,020,0362,0245,0326,0306,0307,0202,'E','X',0223,0376,0247,'b',0212,'e',0362,0367,0311,0340,0342,0247,014,'D','E',0316,'c','v',0256,01,0363,'&','I','8',0234,0211,'|',0301,0303,04,'t',0134,'E','B','Q','d',04,0257,'#',022,'?',017,0202,0255,'$',0314,0254,'&',0355,'(',0313,02,'D','d','J','$',0304,0244,'I','V',0316,0343,0265,'7','F','Q',0270,0356,'=','W',0346,0215,0325,0277,'J',035,07,'/','#',0367,'x','4','5','s','G',0253,'F',0207,0,0211,0134,'z',':',0234,0235,'q',0366,'y',')',03,0241,0374,0212,0177,015,'P',0225,'w',0243,'`',0222,'P',05,'(','e',0266,025,0273,0372,0351,0270,'d',0335,0320,'n',0273,'Q','0',07,'*',']','~',0274,011,'!',0344,'+',';',033,0360,0242,'F',';',0372,0222,'j',0371,07,0205,0325,'6',' ','c',0206,032,'l','Z',0242,'!',0224,0345,'K',0327,0310,'f',0234,0371,0203,013,0204,'-',0357,0355,'4','D',0302,021,'0',0235,011,0355,0243,'p','6',017,'X',036,0264,0302,0272,0311,0270,'A',0354,'A',0342,0241,0242,047,';','C',0327,0226,0224,033,0374,0244,0203,0204,'h','D','6',035,'M',0307,'F',0210,0274,0220,'.','x','~','q',0333,0252,0373,'f','W',011,'V',0207,'h',05,0236,0315,';',0321,0267,011,'D',0211,'L',0210,0246,011,'*',0313,0255,0213,'w','n',0235,0350,026,0314,0310,011,0303,0324,0212,0311,031,' ',0177,0235,0251,07,0212,0224,0252,0352,0320,'f','I','(',02,0233,0263,'X',0302,0367,'x',0343,0246,0341,0263,014,';',0255,021,'!',0245,0313,0277,0256,'<',011,0300,'t',0307,0372,'?','j','%',0207,0,'e','j',0256,0253,0345,'p',0264,':','Q',0260,'B',0247,0253,'"',0360,'y','J',01,035,'@','2','"','a',032,';','G',0331,013,'u',0270,0221,0347,'P','Q','7',010,0230,'p',0216,0324,0323,0344,0210,0205,017,0223,0273,0207,0265,'G','t',030,0304,0222,'#',0222,0231,0211,010,'D',0221,0242,06,0216,'p','~',03,0306,';','R','&',010,034,'#',0325,'*','_',0356,'.',0355,0263,'R','x',0323,'I',0373,0216,'O',04,012,0355,0344,0376,0206,0214,0204,0213,0230,'N','7','9',':','Q',02,'c','$',017,0363,0265,'#',07,'R',0225,']','Z','8',0315,'%',0,'S',0300,'k',030,'^',0357,034,'t',0347,0204,']','}','S','G',0210,'R',0345,0337,0327,036,01,0206,0354,017,0373,037,0265,'A',0343,07,0362,0356,0371,0234,'P','c',0311,0373,01,0322,'b',0374,'Q',')',0355,0345,0207,010,0306,0345,'w',0231,0274,0355,'0','h','z',0333,0261,0367,036,0324,0263,036,'@',0200,0275,022,06,'g',0324,'T','A','f',0301,02,022,0322,')',0322,022,'T',022,'|',0232,0234,0225,0212,']','e','[','Y',0303,0271,'W',0355,'H',0376,'8',0361,0325,'e',0303,'+',0204,'h',0234,026,0300,'g',0263,'N',0345,016,0305,0225,0310,0224,0324,0322,'b',03,'V',015,'h','[','=',0272,'w',0242,0345,0323,' ',047,0177,'<','~',0204,027,03,0253,0366,024,0371,0220,0274,0251,0325,0243,0340,0352,'P',05,',','`',0354,0275,0336,'8',0351,0317,0345,'n',0307,'p',0324,0360,013,0261,0334,'>',030,'"','j',0205,037,0302,0321,0345,0200,0260,07,'B','R',034,0232,0204,047,0263,'K',0211,0244,0221,036,'1',0260,'{',036,']',']',012,03,'=',020,'=',0336,'{',0303,0202,0364,0362,'b','J','I',0340,0362,0314,'|',0350,0232,011,'N',0214,03,0276,0206,'i',0,0211,'#','d','j',0357,'$',0204,0206,0344,0321,0346,0234,012,0340,0330,'n',':',0224,'3',0266,07,'%','E',0202,'K',0227,0261,0263,0347,0275,'"','0',0331,0352,0224,'$','Y','U',0335,0266,'h',0245,0210,0276,0201,0333,'s',0223,0300,031,031,0276,0227,0333,'f',0215,'"','K',0210,'n','7',';','y','t',0337,0222,0340,'u','s',0261,'N',0244,0316,0312,0235,'Z',03,'&',0245,0,'S',020,014,0341,'[',0274,'l','t',0347,0363,0252,0235,0303,0372,0251,0373,0253,0247,0250,'|','%','w','K',0331,015,016,'7','h',0307,'H','X',07,'K',03,'=',0313,'^',0336,0241,'<',0245,033,0252,0260,017,0316,017,'Z','`',04,021,0260,'?',0237,'0',0311,'I','y',0213,023,0345,024,'j',0302,0343,'e','?','/',' ','M',010,'i',0271,'N',010,0363,05,02,'<','c',0204,'-','Y',0267,'Z','T',0315,015,0246,027,037,0315,'f',0215,0224,'I','P',0206,0341,0277,'4',0226,'S',02,0303,'q',0324,0352,0247,0247,0225,0302,'<','4',0331,02,0300,'>',0337,0311,'@',0354,0345,'r','%',':','H',0230,0204,0357,'P','v',0342,0375,0277,0222,0210,'%',0134,010,0357,0341,0277,'S',0,'_',0223,'b',0236,0316,0235,0225,':',0321,0257,025,'(',03,'z','R',0211,0272,'Y','[',0274,'q',0323,0265,035,'u',';',0207,0365,'W',0356,0345,'}','C',0340,0206,0226,'I',011,'@','"',01,'`',06,0207,'I',0305,'+','}',0244,0225,0270,0236,01,'>',0236,'c',0320,0330,0202,010,'O',0267,0231,0257,0344,0374,'0','X',';',0212,0256,0217,' ','R',';',0210,014,0200,0367,0217,'O','(','6','4','!','"','T',02,'d',0246,0317,0306,0357,0212,'G',0251,020,017,0375,0245,'e',032,'6',']',0306,0211,05,0233,035,0306,0303,'N',0370,0353,035,'e','Y','t',0366,0266,'y','(',014,' ','Z',0201,0311,0271,0315,'E',02,'Y',0233,0251,0355,'l',0366,0242,'f','-','a',0325,'8','x',0247,'-','F','e','M',01,0361,'P',0200,')',0225,0234,05,0225,0273,0307,035,'8','"',033,0261,'g',0373,'J',011,0,']',0275,'S',0340,0304,'J',012,036,'o',0362,'h',027,0210,024,01,0261,0324,0267,030,0306,0260,0244,0207,025,0207,0226,'s',0367,':',021,017,'D',0363,'$','I',';','/','"','|',0266,0252,012,020,'t',0345,0210,0227,0233,'y',0330,0215,'&',0211,'8',0177,024,0341,'U',0322,0216,016,0215,014,'c','B',022,'4','`',0321,0316,0203,0370,'v',0244,0360,0360,'8','G',0253,0200,030,'<',047,0255,012,'$',',',022,0213,'k',0377,0,'7',0255,01,0320,0230,0360,036,04,0224,'@',024,0377,0,'_',03,'e','~',0272,'k',0212,0351,0313,'?',0276,'(',0200,01,'w','.',0357,0203,015,012,023,016,0300,0333,0212,'6',0306,0200,' ',016,0251,031,'*',07,0220,0374,0325,0206,0336,0370,'#',0340,'<',0262,0300,'3','h','F',0317,0273,0315,'(',0256,'P',0366,036,'P',0277,033,022,'#',0217,'q',0253,'q',037,02,07,'@',0375,'l',016,'C','d',0247,0376,034,']',0322,0337,0212,'N',014,0207,012,0331,'(',021,0257,0200,'N',0301,0337,'4',0262,'*','`',0270,0275,'z',0317,0264,015,0345,0255,'D',0374,0323,0332,'%',0334,017,'y','P',0270,0202,0360,0251,'m',015,0300,0371,0351,0230,'c',0245,0313,037,0335,030,'#','r','=',0326,0201,'@',022,0270,012,0341,0370,0314,0354,'?','b',0200,0,0,0260,032,'u',0300,'V','.',04,036,'_','$',0220,04,0213,'#','/',0333,0346,022,'%','k',0244,'I','>',0317,0224,0313,'_',0355,0304,'}',022,0372,'Q',0320,'I',0250,'T',013,0307,0273,'6',':',0237,'4',0235,0306,0352,03,0207,0361,'D',035,0310,0224,0271,0332,0215,'f',0266,0343,0325,0177,0276,')',0340,':',01,010,0375,'@',0243,'S','*','X',0376,0370,0242,'&',013,0272,0255,0327,'z','0',012,'0',01,'v',0204,0233,'`',0373,'m',035,0366,'(',' ',0203,037,'@',':',0323,'@',0311,'D',0374,'<',0267,0200,'=','w','G',0343,0314,0254,0262,04,'m','7',0374,0371,'Z','}',0300,0240,0273,0357,024,'2',0275,'$',0232,':','M',022,03,'Q',0270,0322,0213,0227,0330,0371,0247,0202,0310,'(','N',0364,0250,0200,'X','H','=',0342,0234,0254,0226,'?',0226,0337,'L','$',0224,0212,026,';',033,0264,'O',0307,'w','U',0252,0272,0264,0374,'[',01,'*',0354,'P',0304,'@','>','M',0216,0357,0263,0350,0200,0365,0274,'l',0310,0376,0351,0345,0216,0330,0371,0207,0346,016,'r',0346,'}','S',0313,'a',0346,0274,'w','t',0322,'j',')','#','+',0227,0217,035,'{',0346,0237,' ',':',0240,0334,0242,033,'<',0201,0217,0325,'5','-','.',0273,'G','o',0357,'j','b','h',0263,032,0337,'F',' ','W',022,026,033,033,0264,017,0313,0352,0265,'W','V',0203,0262,07,0225,'8',02,0206,'y','C','H','~','~',0317,0242,'h','v',0205,0355,0345,'l',',',0306,0257,'7',0317,0313,0330,0274,0267,'B','?','%',0353,011,'4',')',0202,020,0307,'&',0315,'F','[',0354,0220,0343,'e','"',' ','a',033,047,0245,' ',01,0334,'8',0277,'5','>',01,'e','"','}',016,027,036,0315,0261,0313,024,'z',0311,0203,'+',0273,0273,'G',0375,'F',0312,0235,012,0237,0247,0222,0340,0350,'}',0317,0322,06,0251,0363,0377,0,'O',0226,021,0313,0346,'l',0334,05,0216,0361,'o',0307,0225,0216,'f',0223,'C',011,0356,036,0324,'u',0222,'i',0225,021,0252,047,'"',0342,0373,0346,0237,0271,'[','$',0226,0353,'Z',0313,010,014,016,0316,0364,07,'$',0222,'@','k',0263,0373,'J',015,023,02,'$','W',0207,0333,0256,0233,']',0346,0271,016,0371,'z','>',017,0372,'#',0274,04,0374,0213,0320,0351,'i',0222,'?',0343,0307,0322,04,0226,0323,030,01,0363,0367,0362,0233,0223,';',034,'L',0363,026,'@','H','a','i',02,'>','<',0246,0200,'F','k',027,'.',0202,047,0350,022,'h',0343,0214,'C','q',0334,'r','=',0251,'0',012,'`',0310,'r','h',0347,0342,0220,'Q','=','*',0301,0241,'A',011,0242,'w','(',0316,'D',03,047,'Y',0344,'j',0314,'4',0232,'A',05,0263,0222,'i',0377,0,'h',0243,'$',0232,0205,'H',03,'u','=',0303,0363,0232,'P',010,0206,0351,0371,0273,'f',0206,'~',0205,0242,'D',0314,0361,012,0217,0237,',',0313,0340,0375,'_',0237,'5',0234,0374,01,'B','G',0220,'*',0241,'8',014,'?',025,0253,'W',036,0344,0375,013,'z',0335,0311,04,'/',0311,0261,'J','u',0347,'j',0271,0245,0202,'[',024,0356,0204,0271,0200,'.',0375,0217,'O',0240,'Q','g',02,'4',0342,0247,'F',0222,0333,'~','i',0305,0,0310,0226,'J','^',037,0311,0221,0357,0243,0275,024,07,0313,0207,'d',0321,0341,0241,0235,'#',0350,'/',0342,021,'Y',0,0340,0330,0221,0367,0362,0345,'5',047,'h','q',0370,0371,0220,'a',017,0255,'^',0365,'|',0206,0265,'?','|',0254,0240,047,0337,0350,'w','8','A',03,0362,'l','R','v',0243,0262,0246,0261,'Y','S',05,0365,'&',0374,0322,0313,0364,'8',0336,0260,'~','(',0370,'V',0311,'-',0243,']','h','K',0340,':',0252,'b','x',0275,'%',0266,0245,'2',0360,'"','x','^','_',0206,0211,'G','Z','4','F','k',0262,'/',0332,0261,027,0375,024,'A',0332,'D','q',0345,021,0262,0242,0216,010,'~','l',0274,0330,'Z',016,'%','.',07,'a','P','m',0344,0316,0225,'P',07,0322,0217,'p','Y',0353,0364,033,0274,'!',0201,0376,02,0223,0265,035,0225,'4',0240,'K','b',0262,0246,0345,0361,0272,'~','i','U','U',0225,0325,0372,'C','x',030,0300,0203,'X',0367,0243,0302,'E',0254,03,0332,0230,02,0201,0221,'P',0217,'z','y',0346,0214,0221,0347,'e',012,0345,0262,0341,0331,'4','h','g',0246,0324,0307,')',0353,014,0202,034,0264,0262,'y','K',0346,'|',0277,0326,0207,0230,0343,0357,0341,'2',0376,0342,')',0252,0225,0310,0213,0244,'~','O','&','T',021,'<',031,'.','}',0210,'R',0376,0324,'3',0326,0337,0215,010,037,0304,024,0370,'(',0354,0253,'J',02,0254,06,0265,047,'y','>','w',0375,0224,0262,0375,'3',035,'~','G','<','<','U',0207,'Z','h',013,'L',0377,0,0264,016,'Q','q',031,0232,'V','t',0357,0236,0316,0252,'s',0341,0303,'|','s',0374,'t',0316,'(',0365,'a',0362,0331,'^',020,'y',0201,'(','Y',0245,0327,0277,0230,0235,022,'6','f',0210,04,'$',0260,0277,0270,0273,0344,'-','E','h',0232,0303,017,'D',0211,0315,'p',0352,0356,0306,0204,07,0370,012,'L',024,'v','U','h',02,0250,06,'V',0225,0262,031,'_',0325,0373,'>',0252,030,011,0251,0241,'m',0364,0242,0247,'X','K','!',0221,033,0211,0265,',','7','J','!',035,0312,'L','!',032,'+','N',016,'s','@',0305,0246,'x',0351,031,0361,'`','K',0236,034,0356,01,0365,0362,0352,'#',0231,'$',025,0266,0223,0351,'A',010,034,030,0261,0370,'y',0225,'j','%',020,'-',';',0241,'>',0264,'#',0311,'3','I','X',' ','^',0346,'#',0326,0234,'a',0357,'!',014,0236,0375,'M',0306,020,01,0374,'A','I',0202,0216,0312,0264,014,0200,022,0256,0224,0355,0361,0270,'_',0217,016,'z','r',03,'Y',0320,'j',0274,'P','F','E',0241,0255,'s',0212,0234,'1','2',0226,0202,'?','O','j',0276,0334,'7',015,0304,0263,0325,'B','D',031,023,'%',024,035,'I',0224,'o',0236,'y',0243,'q',011,047,0344,0212,020,02,0374,0237,024,'=',',',0226,0317,'1',0263,0315,05,'b','K',0241,0270,0334,0243,0316,'0',015,0226,0,0225,0366,0250,0255,0371,0220,022,'=',0305,'y','B',0272,026,0331,011,0244,0311,'<',0342,'M',01,0372,'+',0322,0313,0361,0356,0247,'/',036,'L',0350,'g','d','+','8','A',0301,'1',0270,0320,0317,'K','u',0204,020,0377,0,'P','S',0222,0243,0262,0255,031,'`','J',0270,012,'d','@',0313,'_',0201,0307,0337,0246,0212,'#',0205,03,0220,030,0376,07,05,'>',020,0200,'J',0274,024,024,0210,0201,0204,'r','q','O',0211,0321,0222,0215,0134,04,0320,'%',034,0376,0372,0240,0322,06,032,016,0347,'H',0220,0225,0221,'R',0351,'s',0274,'}',0350,0254,0214,0202,'i',0363,0265,0204,036,0364,0303,0302,01,'m',010,0330,0363,0212,'4',0,022,'&',037,'+','B',0272,0366,0211,'v','C','%',0357,0336,0260,0307,0220,0315,'.',',','w',013,'+',0262,0340,0366,0350,07,0304,0346,'I',0311,0372,01,0243,0252,0367,023,'(','L','s',0237,'_',' ',0305,'N',',',0335,0202,'^','5',0241,0312,0323,047,'G','9','j','2',037,0352,015,'i',0337,0301,0331,'V',0202,'1',0245,'H',02,0236,0241,0261,'`',0361,'8',0373,0364,0334,'I',0201,'J',0264,012,0340,0214,0203,'g',0345,0244,' ','T',0300,032,0320,0251,'g',017,'&',0251,0273,0342,0206,'w',0335,'D',047,015,0371,0254,'z',0242,'O','U','j','P',0205,'r','!','-','F',0203,02,0246,01,0364,0374,0377,0,0265,'e',0215,',',023,0323,0254,0301,0345,0326,016,0361,0265,'h',0223,0254,021,0342,0260,0332,0335,0253,025,0244,'V','C','}',0307,024,'~','j','G',0230,0341,0331,0251,0361,'k','2',0302,'l','3',0205,0321,0202,0343,'D','<',0254,0331,0200,022,0256,0305,':',021,026,0263,'t',0365,0231,0365,0350,011,0322,'i',0240,0326,'p','a','V',033,027,0373,'R','G',0220,0306,'=','$',0300,0277,0270,0241,022,0302,0202,'"','!','j',010,0362,'=',014,0344,0250,0310,0177,0250,'5',0244,0177,07,'e','Z',013,'!',0224,'@',024,0263,'U',05,'e',0177,'=','z','h','@',0243,0,027,'Z','!',0244,0246,0343,0376,0336,022,0354,0273,026,'x',0276,0325,026,0250,0232,0210,0200,0305,'{','q',0251,'P',013,037,'D',0351,0337,024,0361,024,0237,'=',0,037,'(',0265,015,0220,'D','-',07,'6','X','M',0234,0365,0237,':','L',0254,0360,0357,'C',0330,0250,0260,':',031,0240,'r',0215,'h',035,0312,'^',0330,0355,0243,0315,015,'b','d',0210,'M',0315,0316,'J',0371,'x','"','T',0262,010,023,036,0255,0251,0255,0310,0223,'4','E',',','@',047,0231,0362,031,0251,0213,'t',032,0202,'O',026,'^',032,013,0305,03,0,'X',':',011,'5',0224,'2',0242,0353,06,0331,0215,016,'i',0313,0237,' ',0305,'=',0204,0242,0221,0210,'Z',032,03,'W','b',0206,'|',0316,0262,')','H',0177,0253,'k','H','~',016,0312,0264,'b','M','J',0,0336,0231,0343,'@','Y','[',0274,'q',0324,0315,'*',0307,0206,0343,0177,06,'I',' ',',','_',0207,0315,031,'`','@',010,03,0305,'$',0241,'r','0',031,023,0232,0214,'k',0315,'{',0234,'^',')','h','d',032,023,0222,0244,'e',0221,'|',0320,0206,0313,'.',0243,0267,0352,0200,0211,0,0200,0215,'y',0353,'!',0226,04,0333,'<',':',0366,'k','|',0350,'.','w',0332,0234,0204,0314,'B','S',0353,'D',0223,011,0317,0360,0320,'d','0',0343,0232,0260,0231,'7','|',0301,0356,0202,'6','g','J',0302,'<',0260,01,'f','S',010,0301,0264,0300,0366,':','@',0261,'v','6',036,0367,0237,'J','@',01,0350,0303,0262,'S',0222,'-','<','y','W','6','>',0200,0345,0206,04,'N',026,0216,'e',0217,0313,04,0206,0210,0350,0371,'U','>','i','H','?',0253,'k','H','.',016,0312,0264,0231,0220,0234,01,'M',0230,0373,'+','w',0215,0216,0246,'L',0310,'L',0367,'q','@',0,026,012,05,'-',0230,']',0257,0345,0240,'^','c','`',06,0236,'W',0300,'y',01,'a',0354,0334,'R','$',0315,0257,015,0307,'~',')',06,0,034,0217,0346,0211,'"',011,'6',0242,'&',034,'N',036,'G',0255,0255,0334,'J',0260,'?',0276,0364,'~',024,026,0375,0267,0364,0242,0321,012,'F',0265,04,030,0270,'L',0261,0303,'C','Z','s',':','.',024,0240,'-',0204,0227,0326,'4',0362,0245,0263,'L','Y','0',0230,0233,023,'+',0240,'5',037,0250,0255,'x',0223,'n',0256,0275,'-',037,'j',0223,'c',0373,0341,0373,'{',0322,'y',03,024,'G',0317,030,01,'q',0227,'D',0200,0333,0215,'%',0323,0305,0363,0346,'T',0203,0355,'q',0255,'>',0230,'+','*',0322,'1',02,0360,05,'8','v','&',013,0373,033,035,'D','G','b','Z',0266,0355,'@',030,0320,02,0,0243,'I',02,035,0203,'g','-',02,'%',015,0362,0363,0320,'I','"',0206,'y','B','S',0352,'m','J','N','B',04,0226,0275,0312,'d',0223,014,0334,0305,'7','>',0204,030,'i','N',0275,0313,0335,0217,0357,0254,0213,0236,'U','r',0247,'f','+','9','6','v',0177,0270,0240,0346,0304,'J',0213,030,0200,'8',0267,024,0316,012,0260,0330,'7','_',0212,'v','x',0353,0242,':',027,'N','V',0377,0,0255,'G','=','$',0232,027,'D',0221,'6',0375,010,'b',0206,'y',0260,0211,0206,0336,0242,037,'_','+',0260,0376,'!','i',037,0371,0255,07,0341,'H',0,'0',0314,'9',035,'D','u',0241,0232,'j',0231,0205,' ',0373,0134,'k','R','Y',0302,0312,0265,'%',0362,024,01,'N','S','`',012,0376,' ',0352,03,'.',0344,';','(',0311,' ','(',02,0236,'V','F','r',0327,0365,'D','|',030,'9',013,0236,0222,'I','@',0254,'G','5',021,0335,'!','!',0273,'h',0363,'N','x',0241,'8',0365,'8',0242,0310,'x','F',0226,'J',0215,0322,0306,0355,'N',0210,03,0236,0266,'!',0221,'q',024,0345,'k','m',035,0213,0224,'!',026,'D',0311,0302,'i','D',0312,0231,047,021,'4','j','n',0320,',',0274,03,011,0275,025,0302,'Q',027,020,'9','T',')',0312,0221,01,015,0353,0274,013,01,0241,'m',':',0232,'7',0251,0303,026,022,'u','>',0317,0252,0322,'F','.','y',06,032,'d',0343,010,024,0352,0353,0257,0205,0314,024,'f',0177,'l',012,0321,'i',0305,'I','f',013,'*',0320,0251,'9','+',024,0305,'6','"',0377,0,'L','i',0324,'(','j',0206,';',015,0216,'Z','.','g',0200,0373,0322,'W','}',0335,'5',0223,0240,'Q',0306,' ',0243,0273,0355,0324,'o','Q',0315,'&','"','K','x','N',037,0305,')','4','a','.',0343,'c','Y',0355,0306,0225,'k',031,02,0307,'i',0246,'F',030,0217,0260,0365,0244,0316,0,'2',0301,';','{',0373,0323,0300,'L','*',0307,'T',0334,0276,'y',0245,0350,'i',0260,0271,'"',0243,0265,')',020,'u','w',017,0212,'V',0261,'B',0341,'-',0334,'i','M',0304,'P',0213,'=','D',0232,010,'k',0271,011,',',0372,'7',0245,0321,'X',0331,'V',035,0344,0267,'q',0244,0217,'$',0365,0367,'r',05,0376,0206,0205,0372,'-',0341,'`','(',0346,0217,0360,'k','W','&',0231,0263,0371,'>',0335,'H',0350,'d',0245,0267,032,0212,'I',0276,0247,0252,0321,0344,'Q',0327,'Z','>',0200,0306,'-','v','p','u',0363,'P',0356,0202,020,'T','b',0275,0321,'}',0216,'3','S','4',020,0242,0345,035,')',020,02,0345,'1','E','`','J','4',0236,0251,0256,012,035,07,0206,0256,023,0304,031,'*','&',0244,'[',0266,0365,035,'#',023,0245,'P',010,024,'#','q','+','_',0235,0340,020,'y','V',0364,']',015,'(',0221,'7',0352,0244,0324,'X',0267,0345,07,'"','d',0354,'`',0232,'V','-',0343,'/',0230,0334,0201,0177,0241,0243,0321,'x',0240,032,024,016,'J','U',0366,'7','k','(','C','/',0372,'?','n',0242,0354,'}',0335,06,0253,0305,037,0322,']',027,0336,0355,0305,06,'$',017,'*','p',025,'y','9','-',0344,0323,0316,0357,0320,0244,0225,012,0265,'n',0224,0241,'8',0357,0311,'J',0322,'p',',','7',035,'J','>','o','d','p',0320,'C',020,0226,'/',']','>',0365,'2','`',016,'N',0252,'1','H',0232,0225,047,0345,'f',0134,0270,023,0375,0245,035,0202,0224,'H',0233,0224,0301,'9',0203,'^','m',0307,024,'A',0366,'R','G',0252,'/','F',0215,' ','K',0211,0265,'>','Y','=','r',0313,0354,'7','O',0134,'Z',0222,032,0230,'9','U',' ','_',0350,'h',0353,026,0,014,01,'C',',',0322,0256,'W','c','v',0247,0251,'E',0227,034,0273,0275,0134,0271,0210,011,0202,0216,0363,0261,0301,'H','@',0243,0,'e',0243,'&','e',037,'6',0275,0337,037,'I',024,'E','`','X','C','n',0251,'s',']',0321,015,0203,0243,0361,'E',0243,0370,0241,0364,';',0211,'e',0241,013,0260,0202,0316,0343,0326,'N','T',0335,0337,'+',0305,'g',026,04,0334,'v','h',0213,'q',02,0311,0276,0306,0215,0233,'Y',0355,0264,'4','j','z','b','J','G',0271,0215,'s',0276,0321,030,'h',026,0236,0212,'-','l',032,'"',027,0332,0211,030,'"',0300,0300,024,'w',0313,0352,0266,'7','i',0243,',',0262,0330,'7','w','z',0205,0305,0201,'J',0256,0224,023,'p',016,033,'?','/',0204,0235,0244,'=',0203,0354,'}',':',0235,0304,0240,';','S',011,0335,0367,07,'3',0212,'|',0361,'P','@','v','J',':','+',0206,']','S',0214,'w','T',0360,'z',0320,010,'h','1',0231,0353,0357,'D','7','3',0303,0332,0221,0272,0302,'_','|','(',021,0204,'O',0273,0271,0271,0315,'O','M',0356,0206,0247,';',0275,0214,0323,0334,'e',0353,0253,'@',0334,'v','5','Z',01,0275,'+','e','0',015,0206,0356,0357,'P',0310,'Q',0,'e','h',0336,'H',033,047,0347,0301,0325,0211,0307,0305,0253,0303,0346,0214,0,04,01,0200,0372,'v',0260,0242,0310,0244,0227,0236,0307,0363,0232,'r',0233,0242,0307,'u',0251,0315,07,0343,'D','$','N','i','m','9',0233,0363,021,'H',0334,'L','!',011,0325,'I',010,0321,0211,'6',0242,0304,0272,'Y',0343,0376,0323,',',0311,0134,'z','s',0332,0201,0365,0302,0261,0311,0372,'R','F',':',',',035,'o','`','*','e','o',023,0353,0367,'s','E',0274,036,']',' ',0244,'s','E',0365,0237,0337,'=','@',0226,0262,0312,' ',0361,0334,'o',0266,0336,06,'n','G','Z','-','<','n',0320,022,'@',0360,03,'C',0352,0264,0240,0202,02,0305,0223,'q',0247,'g',05,'b','8',':','?',015,'D',0333,'G',024,',',0341,'C',0216,0340,'k','F','X',0357,0207,0221,0352,0256,'D',0221,'a','(',0214,'T',0274,'-',0277,0345,'0',021,'#',012,0321,032,'2',0354,'X','8',037,0344,0321,'&',02,0333,0371,0361,'I','"','F',']',0203,0360,'P',010,'i',013,01,'R',0340,01,0333,'h','[','w',0253,0206,0233,07,0236,0356,'6',0254,'Q',0370,0242,'1','i',0367,037,0212,014,0202,';',07,0326,':','s','&',01,0272,0320,0224,']','d',0266,'x',0315,'c',0363,'4','f','t',0214,0215,'&',0203,023,012,'L',011,0244,'4',0204,'h',0271,0331,';',0325,0274,0262,032,0336,0273,'=','Q','P',0212,'%',0304,0247,'C',0270,0263,'4',0354,0335,')',0204,0346,'h',0213,'9','X',0377,0,017,0232,0237,'0',0341,0316,'a',0277,0360,05,'"','R','V',0352,0324,0333,0265,'G',027,0340,0352,0262,0340,0322,0372,037,0212,'0',0,020,06,012,'J',03,012,';',0276,0373,024,'U',0317,'w',']','d',0352,0277,'T',0332,0222,'P',0256,0311,')',030,0230,'w','V','*','k',')','@',0264,0321,0341,0301,0306,'1','X',0304,'Q',024,'K','&',0245,037,0352,0316,'A',0376,'-','C',016,'B',022,0204,'a','a','E','0','u',0364,0255,0350,0352,0247,06,'J','.','5',022,0306,01,'K',021,0267,'y',0366,0240,022,0327,0341,022,0210,0210,0265,0234,06,'{','9',0362,0211,047,031,0200,011,'Z','o','L','C','b','l','*',0345,'V','>',0230,0273,'J',0245,'U','[',0253,0324,'7',0266,'e','-',0237,0232,06,'$',012,0,'4',0246,0322,0344,0254,'K',0241,0253,0305,06,'/',0273,01,0220,0134,0242,'L','}','C','j',0354,0244,0330,'A',0244,027,'s',0232,')',0310,05,015,'{',0344,0323,0307,'4',0315,0300,0236,0205,0354,0205,0213,033,'V',030,0361,0232,'c',0331,0344,'=','c','w','%',014,'s',0222,'a',0373,'j','s','@',020,0302,':','q',0315,'B',033,'r',037,0317,0255,'@','F','1','9',0365,0352,'=',0200,0,032,0312,0364,'m',0204,015,'E',0225,'1',02,0277,03,'P','$',0362,']','v',0320,'n','?',0226,'=',0374,05,0323,0275,'Y',0177,0307,'P',0300,0313,0217,0340,'s',0341,0275,'1','"',0215,0257,0236,015,0326,0240,'%','"',0134,0375,0345,0370,0240,'C','D',032,034,'n','#',023,0315,034,0320,022,026,0331,0276,'=',047,0275,'n',0223,0270,0332,0214,0246,'J',03,'C','?','F',0324,0332,0221,';',0215,0240,'k','z',0234,03,026,'$','a','C','}',0344,'Y',0336,0223,011,0223,'{','1',0213,'F',0262,0363,'R','y',0213,'%',036,'u','K','e','}',032,'8',0250,0316,'4',0204,0215,'f',0311,'.','b','d',0232,0303,0332,0236,0,013,'B','{','4','G',0241,0273,01,0341,0352,'@','d',0323,'u',0343,0372,'}',0251,0,'0',0227,0222,0242,022,'e',0233,0244,023,0352,'#',0353,0344,'{',0220,'#',0250,'R','x',021,'+','<',0320,037,0263,0355,0323,'8',0333,0304,'-',0373,0250,'R',02,'9','Z',0257,'4',0323,0246,0354,'z',033,0264,0360,'6','I',037,0226,0277,036,'#',024,0371,0344,'G','&',031,0,'X','p',0311,'N',0342,0255,'G','S','%',0316,',',0242,'T','(','`',04,0200,'d','N',0211,0243,'d',0222,04,0307,0245,023,'q','C','=','Y',0251,0251,0310,'R',0204,0275,'Z','U',0362,'P','0',023,'$',0216,0366,0325,0210,0344,0200,0204,'h',031,'9',0227,0265,'&','i',0201,'e',0267,030,0364,02,0231,'O','=',02,0324,')','Y',0313,0260,'M',0326,0305,026,047,05,022,'3','c',0356,0275,02,0362,'D',0300,'$','D','Z','6',0244,0337,0362,033,047,033,'4',0207,'|','$','#','L',0261,020,'"',0364,'Y',0257,'{',0207,0203,0373,0351,0337,0270,0320,'m',0302,0200,010,'f','i',0254,0255,'s',0251,020,0364,'O','o','$',0316,0316,'!',0334,0236,0314,'x','O',0370,0260,'_','A','*','R','z',0361,016,0220,0376,':','(','A',',',0261,0335,'5',0202,01,',','_','Y','i',0330,015,0250,03,'n',0364,0251,0267,'z','?','o',0215,'<',0360,0332,0217,'"',0324,']',0313,'+','y',0274,0245,031,0243,022,0232,'j','$',0277,02,0240,0343,0210,0260,'u',01,0257,0331,'P',0330,0344,'R',0235,',',0313,0210,0232,0304,04,0231,'/',0232,02,'I','s','r',0273,032,0232,0232,0232,0232,0233,'T',0305,'g','G',0314,047,0273,'V',0350,010,0313,0265,0226,0247,0217,0314,'p',05,0325,0354,'5',0222,06,025,0232,'#','b',0367,')',022,0206,0215,'W',' ',023,0324,0253,'*','|',0341,'-',',',0242,'+','y','C','p','.',']',0255,0233,0332,'(',0267,'t','"','3',']',06,0301,'b','j','S',0237,06,'Z',0324,'e',036,0336,0316,'7',024,0301,'J',0302,0222,0334,0177,024,020,012,'.','&',0216,'&',0301,021,0332,'1',0366,0244,'`','A',0204,'H','G',0243,0205,'D',047,'r',0202,'1',04,0221,0233,025,'<','X',0326,0220,0303,0345,0370,0362,013,'W',0361,0310,0220,0224,0360,'e','O',' ','-',0266,037,01,0265,0260,'9',022,0221,0272,'^',017,'m',0311,'R','A',0260,0244,0366,047,0334,0243,0357,0256,0344,'{',0245,017,047,0253,07,0346,0206,'X',0247,0362,0212,'r',0217,0277,0353,0244,0362,']',0377,0,'M',']','*',0336,010,'p','7','h',0256,032,0266,']',0326,0260,0322,0260,0261,0312,0350,'S',0203,'a',0216,027,014,0356,04,0332,'n',035,'$','1','X','W','e',031,0353,02,'p',0304,0254,0234,0264,'@',0223,0310,'A',0343,021,0301,'S','B','i','(',037,0323,'4','?',0223,033,0360,'h',0230,'y',0364,'w',0365,033,'D',0347,0255,'S',04,0375,'H',0236,0356,0226,0241,'w','o',0205,'r',0255,04,026,'g','%','|',0320,'i','Q','G',020,0211,'&',0206,0244,0332,0260,0350,0227,'k','*',036,0264,026,0274,0345,'`','r',0301,'H',014,021,'y',0303,023,0327,0306,'8',0326,0240,0364,0244,0237,'`','*','<',0242,'6','p','/',0310,'t','h','H','{',047,0240,0177,'z','I',021,0261,'!',0222,'}','(',0366,0373,0201,03,0347,0367,0245,'K',0274,'h','g','u',0370,0350,0314,0271,020,0343,07,0332,0220,010,'a',0331,031,'<',0240,0232,'.',0201,')',0326,'3',047,0334,0353,0332,0227,0223,'B',0244,'{',0371,0242,'j',033,036,05,'$',0310,0220,034,'n',0323,0313,'b',0312,'[','U',0177,024,'@','N',022,0242,'d','V','D','o','H',0206,0245,0332,'1',0204,0370,0134,0316,'J','J',0240,0213,0330,'b','I',0262,'r','I','Q','o',0255,0270,0246,'8',0360,0270,'p',04,0322,014,'Q',',',0310,'B',0301,'}','[',0344,0241,';','@',0244,0367,'w','^',0201,0305,010,'v',0201,0310,0224,05,0224,0271,0261,0313,0372,0322,0217,'L',016,021,0346,0235,026,0210,04,0213,0275,')',';','"',',','w',':',016,'Z',0210,0201,'q',01,0373,0350,'[','2',0305,0263,0324,0275,'L','Y',0330,016,0323,'K',021,'w','/',0232,',',0311,0333,0365,0274,'5',0303,0376,0353,0363,'V','P',0363,024,'>','b','n',012,'R','/',02,0355,0275,0224,'W',026,010,017,'C',0301,'*','D','E',027,022,0202,07,0304,033,0211,0246,0324,0270,0325,'J','B',0234,026,'`',0300,0212,0356,'U',0273,'T','8',0334,'7','z','4',0302,0222,'>',0244,0326,0320,06,'2','q',':',016,'X',')',030,'w','Q',0306,014,',','<',0211,'~',032,0212,'o',' ',027,0272,0357,'R',0235,036,0240,0331,'9','`',0216,037,0332,0221,0375,0134,',',0233,0216,0245,027,05,'G','w',0221,027,0245,'M',0276,0305,0316,017,0235,0214,0313,'(','l',0315,0376,0337,'J',0370,031,032,0213,'Z',0346,034,0225,'u',0301,0270,0272,'7',03,'h','U',0316,'n','Q',0206,0271,07,0202,'k',0344,0333,0256,'@','%','$','T','[',0350,0211,'4',0264,0212,'^',0255,0200,0273,'Q',037,0366,'(',011,0331,0274,0360,0205,'[',0203,0304,0315,'2','N','M',0233,0243,'E',017,'b','E','w',0234,0250,0202,'F',':',0311,0235,')','@','@',0267,0206,0341,0324,0342,0230,0266,0324,0277,0315,0342,0217,'`',0241,037,0335,'8',0134,0350,'M',0314,0307,0305,0274,0320,026,0377,0,0203,0365,015,'j',0233,0315,'5','B',0370,' ',0357,013,0257,'-',033,'q','%',0310,0270,0225,0270,033,024,0210,0305,'t',0233,012,'W',0336,0254,0372,0225,0215,06,0340,0207,0253,'K',020,0331,',',0215,'N','*',')','#',0241,'*',0272,0242,0245,0327,0246,035,0302,017,0225,036,0254,0222,0370,',',0317,0243,'Q',0207,0213,0324,0353,030,'>','h',0260,020,0207,'a',0205,014,0363,'D','@',0,0200,013,025,037,'D','Z',02,05,'>',0333,'<',0324,0276,0202,0200,0221,0344,0324,0346,0234,0,0204,'C','q',0342,0234,'4','w',022,0316,0337,0355,'8',0364,0300,'!',037,'"','<','S',0370,0372,0262,'M',020,0245,'l',0326,'B',0335,0306,0245,'L',0263,'#',07,'|',')',0255,0302,01,0201,'Y',0346,'E',0342,0241,'$',0255,'=','O',0330,0304,0264,0225,0264,0320,035,0340,021,0354,0315,',',030,0272,0376,'"',0245,'0','6','_',0305,'`',0275,'#',0370,0247,0210,0221,0262,'~','(','<',0230,0314,'G',0331,'[',0310,0353,0217,0225,05,'H','b',017,037,0205,'d','h',02,'7',0223,'%',047,'#',0303,'"','F',0367,037,024,'P',0274,0200,'c','k',0,'T',0246,'j','>',0230,030,'@',0220,0211,'f',0242,0235,'$',0366,0345,0332,0361,'L','_','P','p',0232,0333,'J','?',0214,0261,0312,'?',0261,'C',0134,',','N',036,'G',0305,'C','e',07,0237,0347,0377,0,05,'(',0205,'f',0222,'y',0250,0244,0232,0210,0250,0243,0353,'!',0241,'@',0253,'k','p',':',0367,0246,'S',0366,0234,033,0255,'J',027,'u',010,025,'o',0315,'H',0370,0250,0231,'G',0367,0255,'7','`',0332,'D','5','>',0233,'o',0357,'j',0373,0377,0,0360,0316,0,0203,011,011,0272,0254,0330,0254,0222,'x',0230,0357,0212,'!',0344,010,0237,0212,0237,'$',0221,0210,0370,0240,0,05,0200,0300,'U',0243,'~',0330,0335,'v',02,0377,0,0374,';',0200,020,0204,'I',0223,0232,0272,0,0241,'$',0356,0343,0355,024,'g','(',0271,'C',0220,'_','z','y','M',0211,'<',034,010,0247,'H',012,' ',0230,0330,'h',0177,0361,0237,0377,0331,}; diff --git a/src/embedded_images/redcross.h b/src/embedded_images/redcross.h new file mode 100644 index 0000000..a3a0912 --- /dev/null +++ b/src/embedded_images/redcross.h @@ -0,0 +1,16 @@ +/* Autogenerated by hxtools bin2c */ +#ifndef REDCROSS_H +#define REDCROSS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern const unsigned char bin2c_redcross_jpg[60331]; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* REDCROSS_H */ diff --git a/src/embedded_images/redcross.jpg b/src/embedded_images/redcross.jpg Binary files differnew file mode 100644 index 0000000..88fffe9 --- /dev/null +++ b/src/embedded_images/redcross.jpg diff --git a/src/embedded_images/redcross.xcf b/src/embedded_images/redcross.xcf Binary files differnew file mode 100644 index 0000000..1fb13be --- /dev/null +++ b/src/embedded_images/redcross.xcf diff --git a/src/embedded_images/shred_db.jpg b/src/embedded_images/shred_db.jpg Binary files differnew file mode 100644 index 0000000..8b46302 --- /dev/null +++ b/src/embedded_images/shred_db.jpg diff --git a/src/embedded_images/shred_db.jpg.c b/src/embedded_images/shred_db.jpg.c new file mode 100644 index 0000000..2feee30 --- /dev/null +++ b/src/embedded_images/shred_db.jpg.c @@ -0,0 +1,4 @@ +/* Autogenerated by hxtools bin2c */ +#include "shred_db.jpg.h" +/* Autogenerated from shred_db.jpg */ +const unsigned char bin2c_shred_db_jpg[27063] = {0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,02,0,034,0,034,0,0,0377,0341,032,0266,'E','x','i','f',0,0,'I','I','*',0,010,0,0,0,07,0,022,01,03,0,01,0,0,0,01,0,0,0,032,01,05,0,01,0,0,0,'b',0,0,0,033,01,05,0,01,0,0,0,'j',0,0,0,'(',01,03,0,01,0,0,0,03,0,0,0,'1',01,02,0,015,0,0,0,'r',0,0,0,'2',01,02,0,024,0,0,0,0200,0,0,0,'i',0207,04,0,01,0,0,0,0224,0,0,0,0246,0,0,0,'7',02,0,0,024,0,0,0,'7',02,0,0,024,0,0,0,'G','I','M','P',' ','2','.','1','0','.','3','0',0,0,'2','0','2','3',':','0','2',':','1','2',' ','0','1',':','4','9',':','2','5',0,01,0,01,0240,03,0,01,0,0,0,01,0,0,0,0,0,0,0,011,0,0376,0,04,0,01,0,0,0,01,0,0,0,0,01,04,0,01,0,0,0,0,01,0,0,01,01,04,0,01,0,0,0,0,01,0,0,02,01,03,0,03,0,0,0,030,01,0,0,03,01,03,0,01,0,0,0,06,0,0,0,06,01,03,0,01,0,0,0,06,0,0,0,025,01,03,0,01,0,0,0,03,0,0,0,01,02,04,0,01,0,0,0,036,01,0,0,02,02,04,0,01,0,0,0,0220,031,0,0,0,0,0,0,010,0,010,0,010,0,0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,0,0,01,0,01,0,0,0377,0333,0,'C',0,010,06,06,07,06,05,010,07,07,07,011,011,010,012,014,024,015,014,013,013,014,031,022,023,017,024,035,032,037,036,035,032,034,034,' ','$','.',047,' ','"',',','#',034,034,'(','7',')',',','0','1','4','4','4',037,047,'9','=','8','2','<','.','3','4','2',0377,0333,0,'C',01,011,011,011,014,013,014,030,015,015,030,'2','!',034,'!','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2',0377,0300,0,021,010,01,0,01,0,03,01,'"',0,02,021,01,03,021,01,0377,0304,0,037,0,0,01,05,01,01,01,01,01,01,0,0,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,020,0,02,01,03,03,02,04,03,05,05,04,04,0,0,01,'}',01,02,03,0,04,021,05,022,'!','1','A',06,023,'Q','a',07,'"','q',024,'2',0201,0221,0241,010,'#','B',0261,0301,025,'R',0321,0360,'$','3','b','r',0202,011,012,026,027,030,031,032,'%','&',047,'(',')','*','4','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0341,0342,0343,0344,0345,0346,0347,0350,0351,0352,0361,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0304,0,037,01,0,03,01,01,01,01,01,01,01,01,01,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,021,0,02,01,02,04,04,03,04,07,05,04,04,0,01,02,'w',0,01,02,03,021,04,05,'!','1',06,022,'A','Q',07,'a','q',023,'"','2',0201,010,024,'B',0221,0241,0261,0301,011,'#','3','R',0360,025,'b','r',0321,012,026,'$','4',0341,'%',0361,027,030,031,032,'&',047,'(',')','*','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0202,0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0342,0343,0344,0345,0346,0347,0350,0351,0352,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0332,0,014,03,01,0,02,021,03,021,0,'?',0,0371,0376,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,02,0212,')',0311,033,'9',0340,'~','5','P',0204,0246,0371,'b',0256,0300,'m','*',0253,'1',0340,023,'V',022,05,'^','[',0223,0372,'T',0300,0,'0',06,05,'z',0324,'2',0211,0313,'Z',0256,0337,0231,0233,0250,0272,025,0226,0335,0217,0336,' ','T',0202,04,035,'r','~',0246,0245,0242,0275,'J','Y','~',036,0237,0331,0277,0256,0244,'9',0266,' ','E',07,'!','@','?','J','Z','(',0256,0305,025,035,022,'$',')',012,0206,0352,01,0372,0322,0321,'C','I',0253,'0','!','k','u','#',0345,0340,0325,'v','R',0215,0203,'W',0251,0222,' ','u',0307,'~',0306,0274,0274,'f','[','N',0244,'y',0251,'+','K',0360,'e',0306,'m','n','S',0242,0202,010,'$',036,0242,0212,0371,0266,0255,0243,'6',012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,'(',0242,0200,012,0,'$',0340,014,0232,'z','F',0316,'x',0351,0353,'V','R','5','A',0307,'_','Z',0357,0302,'`','*','b','5','z','G',0277,0371,023,')','$','F',0226,0343,0253,0376,'B',0247,0351,'E',025,0364,'t','0',0324,0350,'F',0320,'F','-',0267,0270,'Q','H','X','(',0311,'8',025,03,0334,'v','A',0370,0232,'U',0361,'T',0250,'/','}',0374,0272,0202,0213,'{',026,':','T','m','2','/','|',0375,'*',0253,'3','1',0344,0223,'I','^','E',0134,0342,'O','J','q',0267,0251,0242,0247,0334,0234,0334,0236,0312,07,0324,0323,014,0362,023,0327,037,0205,'G','E','y',0363,0307,'b',047,0274,0337,0313,'O',0310,0256,'T','I',0347,'I',0375,0357,0322,0244,'K',0202,'X',06,03,0237,'J',0257,'O',0210,026,0221,'q',0330,0346,0264,0303,0342,0361,036,0321,'%','&',0356,0375,'A',0305,'X',0271,'E',024,'W',0325,0230,025,0356,023,0235,0343,0361,0250,'*',0361,01,0206,010,0310,'5','M',0324,0243,020,'k',0347,'3','L','/',0263,0237,0265,0216,0317,0363,0377,0,0202,'m',011,']','X','m',024,'Q','^','I','a','E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'R','G',021,'s',0350,0276,0264,'E',031,'v',0377,0,'d','u',0253,'}','+',0325,0313,0362,0377,0,'m',0373,0312,0237,017,0347,0377,0,0,0211,'J',0332,'!',0,012,'0',06,0,0245,0242,0220,0260,'Q',0222,'p','+',0350,0275,0330,0256,0311,030,0213,'P',0311,'8','^',027,0223,0372,'T','R','L',0317,0300,0341,'j',':',0360,0361,'y',0253,'~',0345,017,0277,0374,0215,'c',016,0342,0226,',','r','N','M','%',024,'W',0212,0333,'n',0354,0320,'(',0242,0212,'@',024,'Q','E',0,025,'j',04,0332,0273,0217,'S',0374,0252,'(','c',0336,'w',037,0272,'?','Z',0265,'^',0346,'U',0204,'w',0366,0363,0371,0177,0231,0234,0345,0320,'(',0242,0233,0274,'y',0201,';',0342,0275,0271,'N','1',0267,'3',0337,'C','!',0325,024,0351,0271,'w',016,0242,0245,0242,0242,0265,'(',0326,0246,0341,'.',0243,'N',0316,0345,012,'*','I','S','c',0361,0320,0364,0250,0353,0343,0252,'S',0225,'9',0270,'K','t','n',0235,0302,0212,'(',0250,030,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'S',0221,013,0260,'Q','M',0253,'p',0246,0304,0347,0251,0353,']',0230,034,'/',0326,'*',0331,0354,0267,'&','R',0262,036,0240,'*',0200,':',012,'Z',')',011,012,'2','N',0,0257,0253,0322,'1',0354,0221,0200,'3',04,0134,0232,0246,0356,'d','l',0237,0300,'R',0310,0345,0333,'=',0273,012,'e','|',0326,'?',034,0353,0276,'H',0374,'+',0361,'6',0214,'l',024,'Q','E','y',0245,0205,024,'Q','@',05,024,'Q','@',05,'I',034,'f','C',0350,0275,0315,':','(','K','a',0233,0205,0364,0365,0253,'=','+',0327,0300,0345,0256,0245,0252,'U',0321,'v',0356,'g',')',0333,'D',' ',01,'F',0,0300,024,0264,'R','3',04,0134,0232,0372,06,0343,010,0335,0350,0221,0220,0331,034,'"',0347,0277,'a','U','2','I',0316,'y',0353,'J',0356,']',0262,'i',0265,0362,0330,0354,'c',0304,'T',0367,'~',025,0267,0371,0233,0306,'6','E',0330,0337,'z',03,0371,0323,0252,0255,0273,021,'&',';',036,0265,'j',0276,0203,05,0210,0366,0364,'T',0236,0373,'3',')','+','1',0222,'&',0364,0307,'~',0325,'O',0241,0253,0365,'^','x',0360,'w',0201,0301,0353,0134,'9',0256,027,0232,'>',0332,';',0255,0375,012,0204,0272,020,'Q','E',025,0363,0346,0241,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',03,0342,']',0322,0,'z',016,'M',0134,0252,0366,0300,'e',0217,'z',0261,'_','M',0225,'S','Q',0303,0363,'w',0377,0,0206,'1',0233,0324,'*',0264,0362,'d',0354,035,07,'Z',0260,0347,'j',023,0350,'*',0217,'S','Y','f',0330,0207,010,'*','Q',0353,0277,0240,0340,0272,0205,024,'Q','_','<','j',024,'Q','E',0,024,'R',0252,0263,0234,'(',0315,'L',0226,0375,0334,0376,02,0272,'(','a','+','W',0370,026,0235,0372,011,0311,'"',025,'V','s',0205,031,0253,'1',0302,023,0223,0311,0376,'U',' ','P',0243,0,'`','R',0327,0275,0205,0313,'i',0321,0367,0247,0254,0277,03,')','M',0260,0242,0212,'c',0312,0251,0356,'}',05,'z',025,'*','B',0234,'y',0246,0354,0211,'J',0343,0231,0202,'.','M','S','w','2','6','O',0340,')',031,0213,0266,'M','%','|',0316,'7',037,',','C',0345,0216,0221,0374,0315,'c',033,05,024,'S',0221,'K',0260,02,0270,'c',027,'&',0243,035,0331,'d',0266,0352,'y','c',0364,025,'b',0221,'@','U',0,'t',024,0265,0365,0370,'Z',036,0302,0222,0201,0317,047,'w','p',0244,'`',031,'H','=',015,'-',025,0273,'I',0253,'1',024,'Y','J',0261,'S',0324,'R','U',0231,0323,'+',0270,'u',037,0312,0253,'W',0310,0343,'0',0357,017,'U',0303,0247,'O','C','x',0273,0240,0242,0212,'+',0224,0240,0242,0212,'(',0,0242,0212,'(',0,0242,0212,'(',02,'{','o',0342,0374,'*',0305,'S',0211,0366,'>','{','t','5','r',0276,0233,'*',0253,031,'P','P','[',0257,0327,'S',031,0255,'D','e',016,0245,'O','z',0252,0320,0272,0366,0317,0322,0255,0321,'[',0342,0260,'T',0361,026,'r',0321,0241,'F','M',024,0266,'?',0367,033,0362,0245,021,'H',0177,0204,0376,'5','r',0212,0343,'Y','=','+',0353,'&','W',0264,'e','a','n',0307,0251,02,0244,'X',021,'z',0362,'}',0352,'Z','+',0256,0226,'_',0207,0247,0252,0215,0375,'u','%',0315,0260,0,01,0200,'0','(',0242,0202,'@',031,047,02,0273,'4','H',0220,0240,0220,06,'I',0300,0250,'^',0341,'G',0335,0344,0324,014,0354,0347,'$',0327,0233,0211,0314,0351,'R',0322,036,0363,0374,'>',0362,0324,033,0334,0225,0356,';',047,0347,'P','u','4','Q','^',05,'|','M','J',0356,0363,'f',0251,'%',0260,'Q','E','(',05,0216,0,0311,'5',0212,'M',0273,'!',0210,01,'$',01,0324,0325,0270,0343,021,0217,'V',0356,'i','"',0204,047,047,0226,0376,'U','-','}',026,']',0200,0366,'K',0332,'T','^',0367,0345,0377,0,04,0306,'r',0276,0210,'(','$',0,'I',0350,'(',0252,0323,0311,0270,0355,035,07,'Z',0355,0305,'b','c',0207,0246,0346,0367,0350,'L','U',0331,'$','R',0357,'r',017,0341,'R',0325,0,'H',' ',0216,0242,0256,0243,0207,'P',0302,0270,0362,0334,'c',0254,0234,'&',0375,0345,0375,'~',05,'N','6',0325,016,0252,'r',0246,0307,0366,'=','*',0345,'E',':',0346,'<',0372,'V',0271,0225,05,'V',0213,0227,'X',0353,0376,'a',07,'f','U',0242,0212,'+',0345,0215,0202,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,02,0254,0301,'&','F',0303,0324,'t',0252,0324,0240,0225,'9',07,04,'W','N',023,020,0360,0365,024,0326,0335,'}',05,'%','t','^',0242,0232,0216,035,'C',012,'u','}','t','d',0247,025,'(',0354,0316,'p',0242,0243,0230,035,0231,'R','A',034,0360,'j',0266,0366,'?',0304,0177,':',0341,0305,'c',0326,036,'|',0262,0215,0313,0214,'n',0134,'$',016,0244,017,0255,'1',0246,'E',0357,0237,0245,'T',0242,0274,0352,0231,0305,'G',0360,'E','/',0307,0374,0212,'T',0321,';',0134,023,0367,'F','>',0265,013,'3','1',0344,0223,'I','E','y',0325,0261,'U','k','|','r',0271,'j',')','l',024,'Q','E','`','0',0242,0200,011,'8',03,'&',0247,'K','s',0325,0377,0,'!','[',0320,0303,'T',0256,0355,05,0376,'B','m','-',0310,0222,'6','s',0300,0374,'j',0322,'F',0261,0216,':',0367,'4',0360,0,030,03,02,0212,0372,'<','&',02,0236,037,0336,'z',0313,0277,0371,030,0312,'M',0205,024,'T',022,0317,0325,'S',0363,0256,0214,'F','"',0235,010,0363,'M',0211,'&',0302,'i',0261,0362,0251,0347,0271,0364,0252,0364,'Q','_','+',0211,0304,0317,021,'>','i','|',0227,'c','t',0254,025,'b',0333,'8','o','J',0257,0324,0325,0310,0327,'d','`','w',0357,']',0231,'M',047,'*',0374,0375,021,'3','z',017,0250,0346,0377,0,'R',0325,'%','C','p',0330,'@','=','M','{',0230,0311,'(',0341,0346,0337,'g',0370,0231,'G','r',0265,024,'Q','_',036,'t',05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',05,024,'Q','@',022,'E','&',0306,0347,0241,0353,'V',0352,0205,'Y',0202,'L',0215,0207,0250,0351,'^',0326,'U',0213,0345,'~',0302,'{','=',0277,0310,0316,'q',0352,'M','U','&','M',0217,0307,'C',0322,0255,0322,'2',0207,0134,032,0364,0361,0270,'U',0210,0247,0312,0267,'[',021,031,'Y',0224,'h',0253,06,0330,'g',0206,0343,0351,'H','-',0217,'v',03,0351,'^',03,0313,'q',')',0333,0227,0361,'F',0274,0350,0202,0212,0260,'-',0206,'y','b','~',0202,0236,0260,0242,0366,0317,0326,0264,0206,'U',0210,0227,0305,'e',0375,'y',011,0315,025,'U','Y',0217,0,0232,0231,'m',0317,0361,034,'{',012,0261,0322,0212,0364,0250,0345,'4',0241,0254,0337,'7',0344,'C',0233,0350,'"',0252,0240,0302,0214,'R',0321,'E','z',0221,0212,0212,0264,'U',0221,01,'H','X','(',0311,'8',025,033,0316,0253,0302,0362,0177,'J',0256,0316,0316,'r','M','y',0270,0254,0316,0235,'/','v',032,0277,0300,0270,0301,0275,0307,0311,'1','~',07,03,0371,0324,'T','Q','_','=','V',0264,0353,'K',0232,'n',0354,0325,'$',0266,012,'(',0251,'b',0213,'y',0311,0373,0277,0316,0212,'4','g','Z','j',020,'Z',0203,'v',035,04,'y',';',0317,'N',0325,'b',0216,0224,'W',0326,'a',0260,0361,0303,0323,'P','_','3',06,0356,0302,0252,'L',0373,0337,0216,0203,0201,'S','M','&',0305,0300,0352,0177,'J',0253,'^','N','m',0211,'O',0367,'1',0371,0232,'A','u',012,'(',0242,0274,'C','@',0242,0212,'(',0,0242,0212,0222,010,'$',0271,0231,'b',0211,'w',';','t',031,0305,015,0333,'V','8',0305,0311,0250,0305,']',0262,':','+','C',0373,023,'Q',0377,0,0237,0177,0374,'}',0177,0306,0217,0354,'M','G',0376,'}',0377,0,0361,0365,0377,0,032,0317,0333,'S',0376,'e',0367,0235,0177,0331,0370,0317,0371,0365,'/',0374,05,0377,0,0221,0237,'E','h',0177,'b','j','?',0363,0357,0377,0,0217,0257,0370,0321,0375,0211,0250,0377,0,0317,0277,0376,'>',0277,0343,'G',0266,0247,0374,0313,0357,017,0354,0374,'g',0374,0372,0227,0376,02,0377,0,0310,0317,0245,04,0251,0310,'8','"',0257,0377,0,'b','j','?',0363,0357,0377,0,0217,0257,0370,0321,0375,0211,0250,0377,0,0317,0277,0376,'>',0277,0343,'M','V',0202,'w','R','_','x',0177,'g','c','?',0347,0324,0277,0360,027,0376,'C',021,0303,0250,'a','N',0251,'a',0322,'5',010,0333,0233,'~',017,'_',0235,0177,0306,0235,0366,';',0237,0371,0367,0227,0376,0371,'5',0365,'x',',',0306,0215,'z','I',0312,'j',0353,'}','Q',0315,'S',01,0211,0246,0375,0352,'r','_','&','A','E','O',0366,';',0237,0371,0367,0227,0376,0371,'4',013,'+',0243,0377,0,'.',0362,0177,0337,'5',0325,0365,0232,'?',0316,0276,0364,'g',0365,'J',0377,0,0310,0376,0346,'A','E','[',032,'e',0343,014,0210,'O',0342,0300,0177,'Z','C',0246,'_',016,0226,0304,0377,0,0300,0327,0374,'k',031,0346,'8','H','o','V','?','z','5','Y','n','1',0355,'J','_',0370,013,0377,0,'"',0255,035,'*','f',0323,'5','3',0322,0330,017,0370,032,0377,0,0215,'F',0332,'6',0244,0307,0230,011,0377,0,0266,0213,0376,'5',0305,'W','=',0303,'G',0370,'n',0377,0,';',024,0262,0274,'g','Z','R',0377,0,0300,'_',0371,020,'4',0352,0274,016,'M','@',0362,0263,0365,'<','z',012,0273,0375,0211,0250,0377,0,0317,0277,0376,'>',0277,0343,'G',0366,'&',0243,0377,0,'>',0377,0,0370,0372,0377,0,0215,'y',030,0214,0322,'U',0364,0224,0322,']',0223,'4','Y','f','-',0177,0313,0251,0177,0340,'/',0374,0214,0372,'+','C',0373,023,'Q',0377,0,0237,0177,0374,'}',0177,0306,0217,0354,'M','G',0376,'}',0377,0,0361,0365,0377,0,032,0343,0366,0324,0377,0,0231,'}',0345,0177,'g',0343,'?',0347,0324,0277,0360,027,0376,'F','}',025,0241,0375,0211,0250,0377,0,0317,0277,0376,'>',0277,0343,'I',036,0227,'r','9','{','y',011,0364,0332,'k','|','<',025,'y','r',0306,'K',0357,'3',0236,017,023,'O',0342,0247,'%',0362,'e','X',0241,',','r',0303,013,0374,0352,0327,'J',0237,0354,'w','?',0363,0357,'/',0375,0362,'h',0373,035,0317,0374,0373,0313,0377,0,'|',0232,0372,'l',',','p',0330,'x',0332,'3','W',0352,0356,0216,'y','a',0361,017,0354,'?',0271,0220,'S',']',0304,'k',0223,0370,012,0266,0272,'}',0343,0203,0266,0335,0362,';','7',0313,0374,0352,06,0321,0265,047,'l',0233,0177,0374,'}',0177,0306,0261,0307,'f',0264,'h',0307,0226,022,'N','^',0253,'C','J','y','v','.','j',0352,0224,0255,0376,027,0376,'F','{',022,0314,'I',0352,'i','+','C',0373,023,'Q',0377,0,0237,0177,0374,'}',0177,0306,0217,0354,'M','G',0376,'}',0377,0,0361,0365,0377,0,032,0371,0227,'^',015,0335,0311,'}',0347,'G',0366,'v','/',0376,'}','K',0377,0,01,0177,0344,'g',0321,'Z',037,0330,0232,0217,0374,0373,0377,0,0343,0353,0376,'4',0177,'b','j','?',0363,0357,0377,0,0217,0257,0370,0322,0366,0324,0377,0,0231,'}',0341,0375,0237,0214,0377,0,0237,'R',0377,0,0300,'_',0371,031,0364,'T',0223,0301,'%',0264,0315,024,0253,0265,0327,0250,0316,'j',':',0321,';',0352,0216,'I','E',0305,0270,0311,'Y',0240,0255,015,023,0376,'B',0360,0177,0300,0277,0364,023,'Y',0365,0241,0242,0177,0310,'^',017,0370,027,0376,0202,'k',':',0337,0303,0227,0243,':',0362,0357,0367,0312,'_',0342,0217,0346,0216,0276,0212,'(',0257,014,0375,'H','(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,0344,'5',0277,0371,013,0317,0377,0,01,0377,0,0320,'E','g',0326,0206,0267,0377,0,'!','y',0377,0,0340,'?',0372,010,0254,0372,0367,'(',0377,0,016,'>',0210,0374,0267,'0',0377,0,'|',0253,0376,')','~','l','*',0346,0227,'<','v',0332,0224,'R',0312,0333,'Q','s',0223,0214,0366,'"',0251,0321,'U','(',0363,047,027,0324,0347,0243,'U',0321,0251,032,0221,0336,'-','?',0270,0353,0377,0,0266,0364,0357,0371,0370,0377,0,0307,033,0374,'(',0376,0333,0323,0277,0347,0343,0377,0,034,'o',0360,0256,'B',0212,0345,0372,0225,'>',0354,0367,0377,0,0326,'|','g',0362,0307,0356,0177,0346,'u',0377,0,0333,'z','w',0374,0374,0177,0343,0215,0376,024,0177,'m',0351,0337,0363,0361,0377,0,0216,'7',0370,'W','!','E',037,'R',0247,0335,0207,0372,0317,0214,0376,'X',0375,0317,0374,0316,0277,0373,'o','N',0377,0,0237,0217,0374,'q',0277,0302,0217,0355,0275,';',0376,'~','?',0361,0306,0377,0,012,0344,'(',0243,0352,'T',0373,0260,0377,0,'Y',0361,0237,0313,037,0271,0377,0,0231,0327,0377,0,'m',0351,0337,0363,0361,0377,0,0216,'7',0370,'Q',0375,0267,0247,0177,0317,0307,0376,'8',0337,0341,0134,0205,024,'}','J',0237,'v',037,0353,'>','3',0371,'c',0367,'?',0363,':',0377,0,0355,0275,';',0376,'~','?',0361,0306,0377,0,012,'?',0266,0364,0357,0371,0370,0377,0,0307,033,0374,'+',0220,0242,0217,0251,'S',0356,0303,0375,'g',0306,0177,',','~',0347,0376,'g','_',0375,0267,0247,0177,0317,0307,0376,'8',0337,0341,'G',0366,0336,0235,0377,0,'?',037,0370,0343,0177,0205,'r',024,'Q',0365,'*','}',0330,0177,0254,0370,0317,0345,0217,0334,0377,0,0314,0353,0377,0,0266,0364,0357,0371,0370,0377,0,0307,033,0374,'(',0376,0333,0323,0277,0347,0343,0377,0,034,'o',0360,0256,'B',0212,'>',0245,'O',0273,017,0365,0237,031,0374,0261,0373,0237,0371,0235,0177,0366,0336,0235,0377,0,'?',037,0370,0343,0177,0205,037,0333,'z','w',0374,0374,0177,0343,0215,0376,025,0310,'Q','G',0324,0251,0367,'a',0376,0263,0343,'?',0226,'?','s',0377,0,'3',0257,0376,0333,0323,0277,0347,0343,0377,0,034,'o',0360,0243,0373,'o','N',0377,0,0237,0217,0374,'q',0277,0302,0271,012,'(',0372,0225,'>',0354,'?',0326,'|','g',0362,0307,0356,0177,0346,'u',0377,0,0333,'z','w',0374,0374,0177,0343,0215,0376,024,0177,'m',0351,0337,0363,0361,0377,0,0216,'7',0370,'W','!','E',037,'R',0247,0335,0207,0372,0317,0214,0376,'X',0375,0317,0374,0316,0277,0373,'o','N',0377,0,0237,0217,0374,'q',0277,0302,0217,0355,0275,';',0376,'~','?',0361,0306,0377,0,012,0344,'(',0243,0352,'T',0373,0260,0377,0,'Y',0361,0237,0313,037,0271,0377,0,0231,0327,0377,0,'m',0351,0337,0363,0361,0377,0,0216,'7',0370,'Q',0375,0267,0247,0177,0317,0307,0376,'8',0337,0341,0134,0205,024,'}','J',0237,'v',037,0353,'>','3',0371,'c',0367,'?',0363,':',0377,0,0355,0275,';',0376,'~','?',0361,0306,0377,0,012,'?',0266,0364,0357,0371,0370,0377,0,0307,033,0374,'+',0220,0242,0217,0251,'S',0356,0303,0375,'g',0306,0177,',','~',0347,0376,'g','_',0375,0267,0247,0177,0317,0307,0376,'8',0337,0341,'G',0366,0336,0235,0377,0,'?',037,0370,0343,0177,0205,'r',024,'Q',0365,'*','}',0330,0177,0254,0370,0317,0345,0217,0334,0377,0,0314,0271,0252,'O',035,0316,0245,',',0261,'6',0344,'l','`',0343,035,0200,0252,'t','Q',']','Q',0217,'*','Q',']',017,02,0265,'W','Z',0244,0252,'K','y','6',0376,0360,0242,0212,'*',0214,0302,0212,'+','b',0313,'B',0373,'e',0234,'w',037,'i',0331,0277,'?','.',0314,0343,04,0217,'_','j',0211,0324,0215,'5','y','3',0247,013,0204,0255,0212,0233,0205,025,'v',0225,0372,'/',0314,0307,0242,0267,0377,0,0341,031,0377,0,0247,0277,0374,0207,0377,0,0327,0243,0376,021,0237,0372,'{',0377,0,0310,0177,0375,'z',0313,0353,'T','{',0376,'g',0177,0366,016,'a',0377,0,'>',0377,0,030,0377,0,0231,0201,'E','I','<','^','E',0304,0261,'g','v',0307,'+',0234,'c','8','8',0250,0353,'t',0357,0251,0344,'J','.','-',0305,0356,0202,0212,0222,010,0274,0373,0210,0242,0316,0335,0356,027,'8',0316,'2','q','[',0177,0360,0214,0377,0,0323,0337,0376,'C',0377,0,0353,0326,'s',0255,012,'z','I',0235,0230,0134,0273,023,0213,'N','T','#','t',0274,0322,0374,0331,0201,'E','o',0377,0,0302,'3',0377,0,'O',0177,0371,017,0377,0,0257,'L',0237,0303,0336,'E',0274,0262,0375,0253,'v',0304,'-',0217,'/',031,0300,0317,0255,'B',0305,'R','z','_',0363,':','e',0221,0343,0342,0234,0235,'=',027,0234,0177,0314,0303,0242,0212,'+',0240,0362,'B',0212,0320,0323,'4',0317,0355,037,'7',0367,0336,'_',0227,0217,0341,0316,'s',0237,0177,'j',0277,0377,0,010,0317,0375,'=',0377,0,0344,'?',0376,0275,'c','<','E','8','>','Y','=','O','K',017,0224,'c','1',024,0325,'Z','P',0274,'_',0232,0364,0352,0314,012,'+',0177,0376,021,0237,0372,'{',0377,0,0310,0177,0375,'z',0241,0251,0351,0237,0331,0336,'W',0357,0274,0317,'3','?',0303,0214,'c',036,0376,0364,'C',021,'N','o',0226,'/','P',0304,'e',030,0314,'=','7','V',0254,'-',025,0346,0275,':','3','>',0212,'(',0255,0217,'4','(',0255,0310,'<','=',0347,0333,0305,'/',0332,0266,0357,'@',0330,0362,0363,0214,0214,0372,0323,0377,0,0341,031,0377,0,0247,0277,0374,0207,0377,0,0327,0256,'w',0212,0244,0264,0277,0346,'z',0321,0310,0361,0362,'J','J',0236,0217,0316,'?',0346,'`','Q','[',0377,0,0360,0214,0377,0,0323,0337,0376,'C',0377,0,0353,0326,'$',0361,'y',027,022,0305,0235,0333,034,0256,'q',0214,0340,0342,0256,025,0241,'S','H',0263,0233,025,0227,'b','p',0211,'J',0274,'l',0237,0232,0177,0223,'#',0242,0212,0222,010,0274,0373,0210,0242,0316,0335,0356,027,'8',0316,'2','q','Z','7','m','N','8',0305,0311,0250,0255,0331,035,025,0277,0377,0,010,0317,0375,'=',0377,0,0344,'?',0376,0275,037,0360,0214,0377,0,0323,0337,0376,'C',0377,0,0353,0326,037,'Z',0243,0337,0363,'=',0177,0354,034,0303,0376,'}',0376,'1',0377,0,'3',02,0212,0330,0275,0320,0276,0307,'g','%',0307,0332,'w',0354,0307,0313,0263,031,0311,03,0327,0336,0261,0353,'X','T',0215,'E','x',0263,0203,025,0204,0255,0205,0232,0205,'e','f',0325,0372,'?',0310,'(',0242,0212,0263,0230,'(',0242,0212,0,'+',0257,0321,'?',0344,021,07,0374,013,0377,0,'B','5',0310,'W','_',0242,0177,0310,'"',017,0370,027,0376,0204,'k',0217,033,0374,'5',0352,'}',037,014,0177,0276,'K',0374,'/',0363,'F',0205,024,'Q','^','Y',0367,'g',021,0177,0377,0,'!',013,0237,0372,0352,0337,0314,0325,'z',0261,0177,0377,0,'!',013,0237,0372,0352,0337,0314,0325,'z',0367,0241,0360,0243,0362,'|','G',0361,0247,0352,0377,0,'2',0305,0207,0374,0204,'-',0277,0353,0252,0377,0,'1',']',0275,'q',026,037,0362,020,0266,0377,0,0256,0253,0374,0305,'v',0365,0347,0343,0276,'$','}',0177,013,0177,06,0247,0252,0374,0202,0253,0337,0177,0310,'>',0347,0376,0271,'?',0362,'5','b',0253,0337,0177,0310,'>',0347,0376,0271,'?',0362,'5',0307,017,0211,037,'G',0210,0376,014,0375,037,0344,'q',024,'Q','E','{',0307,0344,0346,0377,0,0206,0177,0345,0353,0376,01,0375,'k',0240,0256,0177,0303,'?',0362,0365,0377,0,0,0376,0265,0320,'W',0217,0212,0376,'3',0376,0272,037,0243,0344,'?',0362,'/',0247,0363,0377,0,0322,0230,'W','?',0342,'o',0371,'u',0377,0,0201,0377,0,'J',0350,'+',0237,0361,'7',0374,0272,0377,0,0300,0377,0,0245,030,'_',0343,'/',0353,0240,'g',0337,0362,'/',0251,0362,0377,0,0322,0221,0201,'E',024,'W',0260,'~','p','v',0366,'?',0362,017,0266,0377,0,0256,'I',0374,0205,'X',0252,0366,'?',0362,017,0266,0377,0,0256,'I',0374,0205,'X',0257,06,0177,023,'?','X',0303,0377,0,06,036,0213,0362,012,0342,'/',0377,0,0344,'!','s',0377,0,']','[',0371,0232,0355,0353,0210,0277,0377,0,0220,0205,0317,0375,'u','o',0346,'k',0263,03,0361,'3',0347,'8',0247,0370,'4',0375,'_',0344,'W',0253,026,037,0362,020,0266,0377,0,0256,0253,0374,0305,'W',0253,026,037,0362,020,0266,0377,0,0256,0253,0374,0305,'z',023,0370,'Y',0362,030,0177,0343,'C',0325,'~','g','o','E',024,'W',0202,'~',0260,'g',0353,0177,0362,010,0237,0376,03,0377,0,0241,012,0344,'+',0257,0326,0377,0,0344,021,'?',0374,07,0377,0,'B',025,0310,'W',0251,0202,0376,033,0365,'>',023,0211,0377,0,0337,'#',0376,025,0371,0260,0242,0212,'+',0260,0371,0300,0242,0212,'(',0,0256,0277,'D',0377,0,0220,'D',037,0360,'/',0375,010,0327,'!',']','~',0211,0377,0,' ',0210,'?',0340,'_',0372,021,0256,'<','o',0360,0327,0251,0364,'|','1',0376,0371,'/',0360,0277,0315,032,024,'Q','E','y','g',0335,0234,'E',0377,0,0374,0204,'.',0177,0353,0253,0177,'3','U',0352,0305,0377,0,0374,0204,'.',0177,0353,0253,0177,'3','U',0353,0336,0207,0302,0217,0311,0361,037,0306,0237,0253,0374,0313,026,037,0362,020,0266,0377,0,0256,0253,0374,0305,'v',0365,0304,'X',0177,0310,'B',0333,0376,0272,0257,0363,025,0333,0327,0237,0216,0370,0221,0365,0374,'-',0374,032,0236,0253,0362,012,0257,'}',0377,0,' ',0373,0237,0372,0344,0377,0,0310,0325,0212,0257,'}',0377,0,' ',0373,0237,0372,0344,0377,0,0310,0327,034,'>','$','}',036,'#',0370,'3',0364,0177,0221,0304,'Q','E',025,0357,037,0223,0233,0376,031,0377,0,0227,0257,0370,07,0365,0256,0202,0271,0377,0,014,0377,0,0313,0327,0374,03,0372,0327,'A','^','>','+',0370,0317,0372,0350,'~',0217,0220,0377,0,0310,0276,0237,0317,0377,0,'J','a',0134,0377,0,0211,0277,0345,0327,0376,07,0375,'+',0240,0256,0177,0304,0337,0362,0353,0377,0,03,0376,0224,'a',0177,0214,0277,0256,0201,0237,0177,0310,0276,0247,0313,0377,0,'J','F',05,024,'Q','^',0301,0371,0301,0333,0330,0377,0,0310,'>',0333,0376,0271,047,0362,025,'b',0253,0330,0377,0,0310,'>',0333,0376,0271,047,0362,025,'b',0274,031,0374,'L',0375,'c',017,0374,030,'z','/',0310,'+',0210,0277,0377,0,0220,0205,0317,0375,'u','o',0346,'k',0267,0256,'"',0377,0,0376,'B',027,'?',0365,0325,0277,0231,0256,0314,017,0304,0317,0234,0342,0237,0340,0323,0365,0177,0221,'^',0254,'X',0177,0310,'B',0333,0376,0272,0257,0363,025,'^',0254,'X',0177,0310,'B',0333,0376,0272,0257,0363,025,0350,'O',0341,'g',0310,'a',0377,0,0215,017,'U',0371,0235,0275,024,'Q','^',011,0372,0301,0237,0255,0377,0,0310,'"',0177,0370,017,0376,0204,'+',0220,0256,0277,'[',0377,0,0220,'D',0377,0,0360,037,0375,010,'W','!','^',0246,013,0370,'o',0324,0370,'N',047,0377,0,'|',0217,0370,'W',0346,0302,0212,'(',0256,0303,0347,02,0212,'(',0240,02,0272,0375,023,0376,'A',020,0177,0300,0277,0364,'#',0134,0205,'u',0372,047,0374,0202,' ',0377,0,0201,0177,0350,'F',0270,0361,0277,0303,'^',0247,0321,0360,0307,0373,0344,0277,0302,0377,0,'4','h','Q','E',025,0345,0237,'v','q',027,0377,0,0362,020,0271,0377,0,0256,0255,0374,0315,'W',0253,027,0377,0,0362,020,0271,0377,0,0256,0255,0374,0315,'W',0257,'z',037,012,'?',047,0304,0177,032,'~',0257,0363,',','X',0177,0310,'B',0333,0376,0272,0257,0363,025,0333,0327,021,'a',0377,0,'!',013,'o',0372,0352,0277,0314,'W','o','^','~',';',0342,'G',0327,0360,0267,0360,'j','z',0257,0310,'*',0275,0367,0374,0203,0356,0177,0353,0223,0377,0,'#','V','*',0275,0367,0374,0203,0356,0177,0353,0223,0377,0,'#',0134,'p',0370,0221,0364,'x',0217,0340,0317,0321,0376,'G',021,'E',024,'W',0274,'~','N','o',0370,'g',0376,'^',0277,0340,037,0326,0272,012,0347,0374,'3',0377,0,'/','_',0360,017,0353,']',05,'x',0370,0257,0343,'?',0353,0241,0372,'>','C',0377,0,'"',0372,0177,'?',0375,')',0205,'s',0376,'&',0377,0,0227,'_',0370,037,0364,0256,0202,0271,0377,0,023,0177,0313,0257,0374,017,0372,'Q',0205,0376,'2',0376,0272,06,'}',0377,0,'"',0372,0237,'/',0375,')',030,024,'Q','E','{',07,0347,07,'o','c',0377,0,' ',0373,'o',0372,0344,0237,0310,'U',0212,0257,'c',0377,0,' ',0373,'o',0372,0344,0237,0310,'U',0212,0360,'g',0361,'3',0365,0214,'?',0360,'a',0350,0277,' ',0256,'"',0377,0,0376,'B',027,'?',0365,0325,0277,0231,0256,0336,0270,0213,0377,0,0371,010,0134,0377,0,0327,'V',0376,'f',0273,'0','?',023,'>','s',0212,0177,0203,'O',0325,0376,'E','z',0261,'a',0377,0,'!',013,'o',0372,0352,0277,0314,'U','z',0261,'a',0377,0,'!',013,'o',0372,0352,0277,0314,'W',0241,'?',0205,0237,'!',0207,0376,'4','=','W',0346,'v',0364,'Q','E','x',047,0353,06,'~',0267,0377,0,' ',0211,0377,0,0340,'?',0372,020,0256,'B',0272,0375,'o',0376,'A',023,0377,0,0300,0177,0364,'!',0134,0205,'z',0230,'/',0341,0277,'S',0341,'8',0237,0375,0362,'?',0341,'_',0233,012,'(',0242,0273,017,0234,012,'(',0242,0200,012,0353,0364,'O',0371,04,'A',0377,0,02,0377,0,0320,0215,'r',025,0327,0350,0237,0362,010,0203,0376,05,0377,0,0241,032,0343,0306,0377,0,015,'z',0237,'G',0303,037,0357,0222,0377,0,013,0374,0321,0241,'E',024,'W',0226,'}',0331,0304,'_',0377,0,0310,'B',0347,0376,0272,0267,0363,'5','^',0254,'_',0377,0,0310,'B',0347,0376,0272,0267,0363,'5','^',0275,0350,'|','(',0374,0237,021,0374,'i',0372,0277,0314,0261,'a',0377,0,'!',013,'o',0372,0352,0277,0314,'W','o',0134,'E',0207,0374,0204,'-',0277,0353,0252,0377,0,'1',']',0275,'y',0370,0357,0211,037,'_',0302,0337,0301,0251,0352,0277,' ',0252,0367,0337,0362,017,0271,0377,0,0256,'O',0374,0215,'X',0252,0367,0337,0362,017,0271,0377,0,0256,'O',0374,0215,'q',0303,0342,'G',0321,0342,'?',0203,'?','G',0371,034,'E',024,'Q','^',0361,0371,'9',0277,0341,0237,0371,'z',0377,0,0200,0177,'Z',0350,'+',0237,0360,0317,0374,0275,0177,0300,'?',0255,'t',025,0343,0342,0277,0214,0377,0,0256,0207,0350,0371,017,0374,0213,0351,0374,0377,0,0364,0246,025,0317,0370,0233,0376,']',0177,0340,0177,0322,0272,012,0347,0374,'M',0377,0,'.',0277,0360,'?',0351,'F',027,0370,0313,0372,0350,031,0367,0374,0213,0352,'|',0277,0364,0244,'`','Q','E',025,0354,037,0234,035,0275,0217,0374,0203,0355,0277,0353,0222,0177,'!','V','*',0275,0217,0374,0203,0355,0277,0353,0222,0177,'!','V','+',0301,0237,0304,0317,0326,'0',0377,0,0301,0207,0242,0374,0202,0270,0213,0377,0,0371,010,0134,0377,0,0327,'V',0376,'f',0273,'z',0342,'/',0377,0,0344,'!','s',0377,0,']','[',0371,0232,0354,0300,0374,'L',0371,0316,')',0376,015,'?','W',0371,025,0352,0305,0207,0374,0204,'-',0277,0353,0252,0377,0,'1','U',0352,0305,0207,0374,0204,'-',0277,0353,0252,0377,0,'1','^',0204,0376,026,'|',0206,037,0370,0320,0365,'_',0231,0333,0321,'E',025,0340,0237,0254,031,0372,0337,0374,0202,047,0377,0,0200,0377,0,0350,'B',0271,012,0353,0365,0277,0371,04,'O',0377,0,01,0377,0,0320,0205,'r',025,0352,'`',0277,0206,0375,'O',0204,0342,0177,0367,0310,0377,0,0205,'~','l','(',0242,0212,0354,'>','p',0377,0331,0377,0341,014,'w','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0,'<','?','x','p','a','c','k','e','t',' ','b','e','g','i','n','=','"',0357,0273,0277,'"',' ','i','d','=','"','W','5','M','0','M','p','C','e','h','i','H','z','r','e','S','z','N','T','c','z','k','c','9','d','"','?','>',' ','<','x',':','x','m','p','m','e','t','a',' ','x','m','l','n','s',':','x','=','"','a','d','o','b','e',':','n','s',':','m','e','t','a','/','"',' ','x',':','x','m','p','t','k','=','"','X','M','P',' ','C','o','r','e',' ','4','.','4','.','0','-','E','x','i','v','2','"','>',' ','<','r','d','f',':','R','D','F',' ','x','m','l','n','s',':','r','d','f','=','"','h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#','"','>',' ','<','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n',' ','r','d','f',':','a','b','o','u','t','=','"','"',' ','x','m','l','n','s',':','x','m','p','M','M','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/','"',' ','x','m','l','n','s',':','s','t','E','v','t','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#','"',' ','x','m','l','n','s',':','d','c','=','"','h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/','"',' ','x','m','l','n','s',':','G','I','M','P','=','"','h','t','t','p',':','/','/','w','w','w','.','g','i','m','p','.','o','r','g','/','x','m','p','/','"',' ','x','m','l','n','s',':','x','m','p','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','"',' ','x','m','p','M','M',':','D','o','c','u','m','e','n','t','I','D','=','"','g','i','m','p',':','d','o','c','i','d',':','g','i','m','p',':','8','0','0','1','1','d','e','d','-','1','d','8','3','-','4','f','6','e','-','8','a','a','c','-','9','d','6','c','1','b','5','b','1','f','7','c','"',' ','x','m','p','M','M',':','I','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','f','7','d','e','2','c','2','a','-','2','0','e','7','-','4','7','2','c','-','8','7','4','7','-','6','8','6','7','a','4','4','1','8','e','8','3','"',' ','x','m','p','M','M',':','O','r','i','g','i','n','a','l','D','o','c','u','m','e','n','t','I','D','=','"','x','m','p','.','d','i','d',':','c','4','f','1','2','1','6','2','-','7','b','0','6','-','4','0','e','2','-','9','8','3','a','-','f','7','e','1','a','3','8','3','3','b','b','4','"',' ','d','c',':','F','o','r','m','a','t','=','"','i','m','a','g','e','/','j','p','e','g','"',' ','G','I','M','P',':','A','P','I','=','"','2','.','0','"',' ','G','I','M','P',':','P','l','a','t','f','o','r','m','=','"','L','i','n','u','x','"',' ','G','I','M','P',':','T','i','m','e','S','t','a','m','p','=','"','1','6','7','6','1','6','6','5','6','9','0','7','7','6','8','8','"',' ','G','I','M','P',':','V','e','r','s','i','o','n','=','"','2','.','1','0','.','3','0','"',' ','x','m','p',':','C','r','e','a','t','o','r','T','o','o','l','=','"','G','I','M','P',' ','2','.','1','0','"','>',' ','<','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','r','d','f',':','S','e','q','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','d','e','2','7','4','d','3','3','-','d','6','7','a','-','4','1','7','d','-','9','b','e','8','-','8','1','7','e','8','c','c','d','1','2','b','a','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','2','-','1','2','T','0','1',':','4','9',':','2','9','+','0','0',':','0','0','"','/','>',' ','<','/','r','d','f',':','S','e','q','>',' ','<','/','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','/','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n','>',' ','<','/','r','d','f',':','R','D','F','>',' ','<','/','x',':','x','m','p','m','e','t','a','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','<','?','x','p','a','c','k','e','t',' ','e','n','d','=','"','w','"','?','>',0377,0342,02,0260,'I','C','C','_','P','R','O','F','I','L','E',0,01,01,0,0,02,0240,'l','c','m','s',04,'0',0,0,'m','n','t','r','R','G','B',' ','X','Y','Z',' ',07,0347,0,02,0,014,0,01,0,'1',0,06,'a','c','s','p','A','P','P','L',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,0366,0326,0,01,0,0,0,0,0323,'-','l','c','m','s',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,015,'d','e','s','c',0,0,01,' ',0,0,0,'@','c','p','r','t',0,0,01,'`',0,0,0,'6','w','t','p','t',0,0,01,0230,0,0,0,024,'c','h','a','d',0,0,01,0254,0,0,0,',','r','X','Y','Z',0,0,01,0330,0,0,0,024,'b','X','Y','Z',0,0,01,0354,0,0,0,024,'g','X','Y','Z',0,0,02,0,0,0,0,024,'r','T','R','C',0,0,02,024,0,0,0,' ','g','T','R','C',0,0,02,024,0,0,0,' ','b','T','R','C',0,0,02,024,0,0,0,' ','c','h','r','m',0,0,02,'4',0,0,0,'$','d','m','n','d',0,0,02,'X',0,0,0,'$','d','m','d','d',0,0,02,'|',0,0,0,'$','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,'$',0,0,0,034,0,'G',0,'I',0,'M',0,'P',0,' ',0,'b',0,'u',0,'i',0,'l',0,'t',0,'-',0,'i',0,'n',0,' ',0,'s',0,'R',0,'G',0,'B','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,032,0,0,0,034,0,'P',0,'u',0,'b',0,'l',0,'i',0,'c',0,' ',0,'D',0,'o',0,'m',0,'a',0,'i',0,'n',0,0,'X','Y','Z',' ',0,0,0,0,0,0,0366,0326,0,01,0,0,0,0,0323,'-','s','f','3','2',0,0,0,0,0,01,014,'B',0,0,05,0336,0377,0377,0363,'%',0,0,07,0223,0,0,0375,0220,0377,0377,0373,0241,0377,0377,0375,0242,0,0,03,0334,0,0,0300,'n','X','Y','Z',' ',0,0,0,0,0,0,'o',0240,0,0,'8',0365,0,0,03,0220,'X','Y','Z',' ',0,0,0,0,0,0,'$',0237,0,0,017,0204,0,0,0266,0304,'X','Y','Z',' ',0,0,0,0,0,0,'b',0227,0,0,0267,0207,0,0,030,0331,'p','a','r','a',0,0,0,0,0,03,0,0,0,02,'f','f',0,0,0362,0247,0,0,015,'Y',0,0,023,0320,0,0,012,'[','c','h','r','m',0,0,0,0,0,03,0,0,0,0,0243,0327,0,0,'T','|',0,0,'L',0315,0,0,0231,0232,0,0,'&','g',0,0,017,0134,'m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'G',0,'I',0,'M',0,'P','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'s',0,'R',0,'G',0,'B',0377,0333,0,'C',0,03,02,02,03,02,02,03,03,03,03,04,03,03,04,05,010,05,05,04,04,05,012,07,07,06,010,014,012,014,014,013,012,013,013,015,016,022,020,015,016,021,016,013,013,020,026,020,021,023,024,025,025,025,014,017,027,030,026,024,030,022,024,025,024,0377,0333,0,'C',01,03,04,04,05,04,05,011,05,05,011,024,015,013,015,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,0377,0302,0,021,010,01,0,01,0,03,01,021,0,02,021,01,03,021,01,0377,0304,0,035,0,01,01,0,03,01,01,01,01,01,0,0,0,0,0,0,0,0,010,05,06,07,04,03,011,02,01,0377,0304,0,034,01,01,0,01,05,01,01,0,0,0,0,0,0,0,0,0,0,0,06,02,03,04,05,07,01,010,0377,0332,0,014,03,01,0,02,020,03,020,0,0,01,0252,'@',0,0,0,0,0363,0325,0347,'%',0333,'Q',0310,0267,'6',0371,0316,0316,0215,'s',047,0317,0207,0276,'l',026,'*',0354,0332,';',0224,0324,'^',0367,0276,0217,'@',0,0,0,0,0,0,03,023,'w',0311,0316,'I','f','{',0222,'Z',0302,0344,'R',0,0,'u','M','=',0313,0256,05,0225,0376,0200,0,0,0,0,0,03,0371,047,0271,025,0231,'n','Y','c',023,0177,0301,0226,0261,0357,'b',0322,0335,0352,'z',0212,0367,'<','*',0275,0226,0375,0347,0273,'*','#','y',0276,'0',0263,0240,0331,'=',0313,'G','t',0,0,0,0,0,03,03,0177,0310,0302,'m',0215,0313,'7',026,0306,0331,0205,'U','5',026,0277,0334,'4','W','=','T',0372,0,0302,0335,0363,0363,'g',0250,'a',015,0207,026,0257,0320,0376,'o',0227,0220,0243,0320,0,0,0,0,03,'F',0316,0242,033,0236,0343,'k',0231,'T',0372,'(',0366,0233,0212,0337,0245,'c','7','}',024,0372,0,02,'[',0225,'X',0230,0345,'v',0,0244,0342,0327,0352,0330,0235,0360,0,0,0,0,032,'F','u','0','w','@',0305,0303,0337,0247,'h',0303,0252,0333,0202,0344,0357,0270,025,0200,0,034,0347,'c','D',031,0320,0261,'~',025,'y',0330,0364,'W','x',0346,0366,0327,0336,0237,0177,'B','9',0306,'^',0343,0207,'P',0,0,0,03,025,'w',0317,0317,0336,0211,0211,0253,'f','S',0274,'k',0353,0272,0240,'9','Y',0353,036,0200,0,032,'F','m','0',0217,'@',0305,0302,'d','S',0326,'4',0327,'.','X',036,'T','!','?',0305,0346,';','k','}','g','M','r',0347,0201,0345,0,0,0,0,'#',0271,0226,'?',03,0221,0331,0330,'1',0252,0277,0271,0336,'V',0305,0217,'P',0,01,0312,0266,0266,0342,0271,0316,'6','"',0377,0,0233,0236,05,'w',0267,'>',0312,0313,0332,0367,0224,0355,'m',0302,0275,03,024,'[','p','<',0256,0313,0246,0270,0,0,0,'5','|',0232,0177,':',0372,'^',047,0317,0337,'-',0350,026,'W','b',0323,0334,0,01,0342,0253,0311,'f','Y','f','u',0223,'Y',0376,'=',0363,'{',0327,'W','s','@',0262,0263,0366,'=',034,012,'A','j','<',0232,0343,015,0247,016,0257,0320,0316,'q',0227,0353,0247,0320,0,0,016,01,' ',0265,037,'M','q',0267,'L',012,0377,0,'C','9',0316,'X',0,'y','j',0363,0205,'o',0255,0314,'R',0253,032,0336,']','#',0265,0350,'.',0330,0260,0334,0214,0205,0277,'G',0206,0277,'?','=',0372,'6','&',0253,0231,'H',025,04,'N',0375,'A',026,0276,0,0,01,':',0310,0354,0311,'3',',','}',0323,02,0273,'b',013,0223,0262,0342,0373,0207,0277,0346,0205,0260,0247,0222,'n','-',0361,'m',0355,0274,'=',0372,'F','w',032,0252,0302,'!',0177,0271,0350,0256,0201,0374,0221,0204,0333,033,0210,'o',0355,'f',0361,0352,0244,0342,0327,0245,031,0216,'?',0262,0337,0277,0241,'|',0337,'/','i',0306,0250,0,0,032,0276,'M','?',0236,'}','#',023,0307,'s',0300,0,03,'5',0217,'U',023,032,0273,'F','F',0257,'d','h',0364,017,0231,'!',0314,'q',0347,0371,'%',0237,0357,0317,'m',0370,026,'O',0134,0324,0134,0201,':',026,047,'<',0331,0321,'D',0306,'o','V',0361,014,0200,0,0,011,0276,'I','f','O',0230,0343,0201,0376,0233,'F',025,']','+','Y','_','d',0322,']',0354,032,'z',0375,'4',0372,0,0301,0336,0362,'5',0233,'c','r',']',0315,0277,0364,0256,0241,'y','4',',','z',0350,0233,0344,0226,'d',0371,0216,'?','d',0321,']',0267,' ',0371,' ',0,0,037,0301,04,'t',034,'N','s',0264,0243,0276,0306,0357,'W','P',0374,0217,'O',0200,0,037,0341,0303,'7',0266,0244,0311,0205,0214,'6','E','>',0212,'=',0257,'a','y',035,0357,'C','t',010,'N','{',0213,0312,0367,026,0351,'h',0265,0372,0252,047,'|',0,0,0,'i',0231,0224,0376,'~','t','l','O',0237,0257,0320,'N','s',0227,0273,'a','T',0,0363,'U',0347,032,0335,'[',0233,'$',0366,'t',015,0225,03,'j',0303,0252,0316,0204,'d',0364,0215,'m','`','q','m',0325,0270,0242,'w',0213,0365,0247,0337,0320,0236,'q',0227,0271,'a',0324,0,0,0,04,0321,'&',0263,'+','K',0361,0367,'m','}','t','$','v',0357,0266,0217,'p',0327,'|',0347,0273,'*','9','F',0336,0336,'*',0377,0,0203,0325,'G',0264,0134,'f',0365,';',026,0275,0356,0243,0320,'4',034,0372,' ',0376,0201,0213,0215,0275,0345,033,027,0277,'Y',0304,0257,0200,0,0,0,'>','^',0240,'^',0203,0211,0317,0266,'t',0,0,0314,'X',0253,0274,'G',0256,0321,0321,0253,0273,026,'=','@',016,'k',0262,0242,' ',0236,'b',0342,'/',0371,0324,0265,027,'.','X',036,'O',0246,0237,'@',0,'|',0374,0253,03,'g','`',0,03,'G',0316,0246,'$',0235,0343,0377,0,'&','Z',0313,'=',0217,0356,0357,0201,'W','Q',0325,0134,0352,'Z',0252,0376,0364,0200,03,0214,'n','h',0226,'e',0326,'|',0365,'y',0273,'`','U','g','B','r','2','6',0300,014,0365,0355,0177,0323,0332,'F',0273,'c','e',020,0305,0273,0330,0,0,0,0,0,0,0,0,0,02,0336,0224,0360,'M',0212,0376,0264,'k',0266,'6','Q',014,'[',0275,0200,0,0,0,0,0,0,0,0,0,'-',0351,'O',04,0330,0257,0353,'F','&',0336,'d',0331,0243,0352,0,0,0,0,0,0,0,0,0,0,012,'O','y',0313,0362,0327,'0',0300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,034,0277,02,'U',0255,0330,0332,0216,0327,0264,0202,'z','j',0267,0363,0362,0256,037,0252,0236,0214,0345,0355,0177,'X',0330,'D',06,0245,0215,0270,0347,030,'R','q',0321,0363,'c',033,'n','N',0234,'r','}','|',0277,07,'g','`',';',0206,0326,05,0364,0366,0237,'5','7','8',0246,0256,'v','6','K',0372,0256,0241,0237,025,0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',0,01,'(','G',0272,0377,0,'.',0300,0227,013,0262,'Y',0363,0346,'R',0346,'/',0232,0233,0220,'D','G',0350,0221,0277,'e',0307,'l',')','/',024,034,'o','Y','6',0230,0364,']',0134,'S',0233,0336,'Q',0331,'6','p',0221,036,0306,0273,'^',0203,0211,'"',027,0274,0273,0347,'o','M','V',0361,'v',0362,0241,'8',0237,0320,'c',0250,0347,0304,'j',0371,017,' ',03,0377,0304,0,'+',020,0,01,03,03,03,04,02,01,05,01,01,0,0,0,0,0,05,03,04,06,0,07,020,01,02,027,026,' ','5','6','0','4',024,021,022,023,025,'@','1','`',0377,0332,0,010,01,01,0,01,05,02,0371,0134,'9','I',0242,'E',0256,0240,'A',0332,0220,0274,'d',0226,0325,0334,0350,0373,0335,024,'2',0375,'j',0332,'I',0336,0335,'Y','L','M',0217,0324,05,0341,'W','n',0366,'/',0233,0222,'k',0376,'R','e',0231,0207,'m',' ',0274,':',0376,0244,0315,'>','2',0267,'}',0277,0227,'n',0215,025,0323,'_',0327,'O',0361,'n',0335,0246,0315,0262,0253,0260,0335,0225,022,'*',0354,0303,0234,016,022,0360,0272,0242,0355,01,'W','z','0',0264,01,0333,0323,'{',0177,037,'m',0246,0350,'P','-',0332,036,0264,0303,035,'6',0305,0255,0224,0177,'n','+',0374,'&','N','3',0,0316,']','?','{',047,0337,0200,'1','b','R','5','@','Z','A',0354,'t','l',0325,026,'h',0366,032,'#',0260,'H',0234,0,'2',0264,'|',0260,0367,0310,0223,'e',0363,0313,'%',0255,'b',0214,'N',0237,'y','#','}','M',0333,0252,0351,'h',0225,0247,0375,0264,0335,0272,'M',021,0356,0273,0262,'}','7',0353,0233,'G','(',0376,025,0276,'i','d',0251,0264,'P','q','b',0316,'M',0276,0250,0364,'q',0344,0225,0364,'V',032,0306,',',0337,0276,'m','.','J','*','1','u',0324,'t',0275,'%','o','W','V',023,'H','-',0275,0262,0321,'9',012,'r','`',0277,'!','B','h',07,'a','$',0220,0270,0222,0224,0250,0234,'Q',0314,0251,0370,'P',0215,0,'1',0357,0225,'K',032,'E','X',0230,'0',0344,0351,012,0267,0321,015,'d',0244,0364,0331,0246,0233,'n',04,'c',0246,0316,'U',0271,0224,'t',0361,0257,0222,0353,'J','?',0261,'%','@',0202,0270,0220,023,0,011,0264,'t','o','|',0306,'|',0322,'0',0231,'R',0256,0215,'=',0250,0264,']',0314,0244,0210,0221,'M',0302,0260,0253,0232,0301,027,0221,034,'[',')','G',0367,0201,0376,')','1','}',01,02,'Q','M',0313,')','V',0322,'/',0240,' ',0275,0317,036,0240,'=',0274,0266,0353,0252,0352,0267,0357,0334,0246,0372,0212,'D',']',0312,0236,04,010,0322,'>',0303,027,'|',0316,0326,0241,'q',031,':',0254,'p',0313,'G','I','>','m',0360,0336,'G','[',0222,03,'P',0321,'[','L',0311,0273,0134,0272,'E',0222,'2',033,0270,0311,0225,032,0221,020,0220,0257,0210,'m',0266,'r','w','V',03,0333,0213,'k',0207,0317,'Q',032,0316,'L','y','Y','!',0234,0332,'9','G',0305,'z',033,'~',0341,'u',017,'=',0244,'l',0360,0351,0230,'R',0233,0177,'=',0265,'9',0224,010,'i',0251,013,0256,011,0236,0205,0257,021,07,'4','H',0303,0323,012,0340,'@','G',0247,0134,0304,0355,'s','@',0375,0232,0353,0246,0335,'.','<',0343,0373,0367,024,024,'B',0347,'I',0134,'(','*',010,0307,'i',0233,0265,'X',':',0215,035,'J','F',033,0340,0222,0204,0331,'!',012,0361,0242,0254,035,'w',0214,014,0370,0312,0261,0353,'=',0246,0224,0300,'s','a','m',0363,0277,'~',0324,0266,0134,033,0207,0251,'l','l',0331,0252,0233,0255,0344,'7',0246,0230,'n',0333,0246,0375,0263,0230,0326,0261,0223,0225,'f',0312,0357,'H',0247,0303,'u',0342,'_',0220,0216,0177,0355,'2',0213,027,'!',0250,0333,'B',']',0335,010,0265,01,0207,0323,'v',0310,0263,'G',0260,0271,0246,'@',0232,0314,0256,013,0251,'>',0352,0323,'O',0327,'[','u','o',0377,0,0254,0323,027,0247,'z',0177,0201,'V',0237,'n',0272,0313,0376,035,0373,'6',0253,0262,'u',027,0335,027,'3','V',0244,0273,']',0217,0323,'l',0222,'=',0372,0353,0246,0335,'%','7','M',0220,0255,012,0230,'x','m',0325,' ',0202,0216,0226,0201,0333,0235,0241,0273,'.','<',0207,'C',0322,'*',0263,02,0365,0334,0347,0342,0226,0307,023,0223,0206,'r',0331,'V','N',021,'W','z',012,0303,0344,'[','$',0301,';',034,'9','I',0242,'G','n',0270,0241,0265,'!',0234,025,0221,0353,0200,021,0247,0362,'W','Q','8','3',030,0252,'y',0271,'S',015,01,016,0244,0323,0334,0262,0221,020,'Z','G','@','|','w','b','%',0374,0211,0324,'Z','Z',0362,'(',0351,0265,0347,037,0271,'=','o',' ','j','w','z','[','m',0320,0225,0332,'4',0362,0237,0225,'x','Q','L','6','j',0263,0325,0343,026,0215,'E','u','d',0305,0270,0346,0371,0227,0313,0233,'E',030,021,' ',0271,'W',0265,'j','b',':',0271,'q',0362,'*',0226,0325,0223,0233,'E',0367,'E',0314,0367,015,016,0364,0272,0240,0254,0352,0352,0320,'x',0360,0360,011,'v','L',047,015,'"',0250,025,'*',0344,0323,0352,0203,'B',0225,0225,'<','n',0335,'6',0210,'w','(',0246,0324,'S',0352,'1','U',0324,'b',0253,0250,0305,'W','Q',0212,0256,0243,025,']','F','*',0246,033,'C','J',03,'n','h',0266,0335,0337,0214,0255,'"',011,0332,0373,032,0303,']',0270,0321,0215,0272,'a',0255,013,0211,0303,06,0322,'&',0302,0266,'O',0250,0305,'W','Q',0212,0256,0243,025,']','F','*',0272,0214,'U','K',0256,'v',0250,'h',0343,'G','N',0326,0374,'e','j','/',030,'L',0313,0241,0344,0201,012,'g',0324,'b',0253,0250,0305,'W','Q',0212,0256,0243,025,'I',0251,0265,'d',0361,'#',0365,0377,0,0366,'G','=',0177,022,'?','_',0377,0,'d','s',0327,0360,']',0256,0367,0242,0270,0320,0275,'q',0241,'z',0343,'B',0365,0306,0205,0353,0215,013,0327,032,027,0256,'4','/',0134,'h','^',0270,0320,0275,'q',0241,'z',0343,'B',0365,0306,0205,0353,0215,013,0327,032,027,0256,'4','/',0134,'h','^',0270,0320,0275,'q',0241,'z',0343,'B',0365,0306,0205,0353,0215,013,0327,032,027,0256,'4','/',0134,'h','^',0270,0320,0275,'q',0241,'z',0343,'B',0365,0306,0205,0350,'C',']',0354,0205,0177,0341,'$',023,0244,0200,021,0345,'D','+',0225,020,0246,0313,'~','K','j','S',0177,0361,0247,0312,0210,'W','*','!','A','.',02,'&',0211,0342,'I','!',0331,034,'g',0312,0210,'W','*','!','Q',0271,016,0311,033,'<',033,0270,010,0205,047,0312,0210,'W','*','!','I',0357,0376,'D',0351,0312,0337,0214,0333,0225,020,0256,'T','B',0243,0363,0244,0217,0221,0356,0270,0376,0313,0201,'~','2',0234,0375,'|','A','=',0257,027,'G',0302,'b',0327,'x','L','N',0375,0257,015,0276,0275,024,0361,0230,0267,036,0313,0335,'q',0375,0227,02,0374,'e','9',0372,0370,0202,'{','^','.',0217,0204,0305,0256,0360,0230,0235,0373,'^',033,'}','z',')',0343,'1','n','=',0227,0272,0343,0373,'.',05,0370,0312,'s',0365,0361,04,0366,0274,']',037,011,0213,']',0341,'1',';',0366,0274,'6',0372,0364,'S',0306,'b',0334,'{','/','u',0307,0366,0134,013,0361,0224,0347,0353,0342,011,0355,'x',0272,'>',023,026,0273,0302,'b','w',0355,'x','m',0365,0350,0247,0214,0305,0270,0366,'^',0353,0217,0354,0270,027,0343,')',0317,0327,0304,023,0332,0361,'t','|','&','-','w',0204,0304,0357,0332,0360,0333,0353,0321,'O',031,0213,'q',0354,0275,0327,037,0331,'p','/',0306,'S',0237,0257,0210,047,0265,0342,0350,0370,'L','Z',0357,011,0211,0337,0265,0341,0267,0327,0242,0236,'3',026,0343,0331,'{',0256,'?',0262,0340,'_',0214,0247,'?','_',020,'O','k',0305,0321,0360,0230,0265,0336,023,023,0277,'k',0303,'o',0257,'E','<','f','-',0307,0262,0367,0134,0177,'e',0300,0277,031,'N','~',0276,' ',0236,0327,0213,0243,0341,'1','k',0274,'&',047,'~',0327,0206,0337,'^',0212,'x',0314,'[',0217,'e',0317,0377,0304,0,'9',021,0,01,01,04,02,017,010,03,0,03,01,0,0,0,0,0,01,02,0,03,04,020,06,021,05,022,025,026,' ','0','4','5','Q','S','r',0201,0221,0222,0341,'1','2','3','A','q',0261,0262,0301,023,'!','@','"','C',0321,'`',0377,0332,0,010,01,03,01,01,'?',01,0307,025,0200,0337,0220,0265,0261,'j',0313,'V','Z',0330,0260,'y',0247,0371,0353,0251,0213,0315,014,'I','8',0204,'*',0257,0345,'R',0364,'1','5',0314,012,0330,';','-',0370,0303,'Z',0206,0265,014,'P','<',0246,0203,'X',0376,'"','j','e','.',0271,0204,0222,0301,0330,0363,0302,'?',0251,0203,'Q',0376,025,'*',0325,0211,0256,'i','F',0234,'C',0303,0345,0200,0354,0371,'c',0324,'m','X',0232,0344,05,'l',023,'k',0210,'R',0255,'g','i',0376,'5',0314,032,0306,'4',0376,0230,0232,0344,0224,0333,'0',025,'b',012,0255,'X',0232,0344,0204,0327,'%',0212,0214,0220,'j','8',0325,0237,')',01,'[',01,'V','!','J',0251,0211,0256,'I','M',0263,01,'T',0227,0331,'4',032,0306,',',0232,0204,0320,'*',030,0205,'/','D',0322,0233,'f',02,0251,0274,'?',0252,0246,015,'G',026,0363,0262,'I',025,0234,'2',0360,'y','1','$',0315,'(',0257,0265,0273,'0',024,'k','8',016,0317,0226,')',0347,'d',0222,'j','-','l',014,0253,015,'n',030,0274,0320,0304,0223,'0','+','d',0242,0254,025,0252,0277,0324,0200,0255,0226,0237,0327,0352,']',0214,015,'c',022,'E','a',0273,'1',0,022,0301,0336,0234,'%',0256,0277,0320,0232,'S','T',0224,'*','2','v','|',0261,'K','O',0236,015,0251,'`',0354,0260,'@',0302,'&',0246,'R',0353,0232,023,'W',0354,0315,0344,0235,0366,0342,0324,'*','2','v','|',0261,'%','`','v','1','5',0315,'(',0253,0267,01,'f',0263,047,'c',0317,026,0241,'X',0232,'M','c',010,0254,06,'*','&','`',022,0311,'H','N',02,0325,'T',0322,'*',030,0305,0247,0316,'I','U',0253,'~','@',0337,0220,'7',0344,'b',0360,0265,'u',0340,07,'z','p','T',0253,'V','&',0271,'!','>','x',0345,012,0216,030,04,0260,'w',0245,0200,03,05,'J',0265,'b','k',0222,'S','^','!',')','R',0324,022,0221,'Y','-','s','#',0265,012,0345,'-','s','#',0265,012,0345,'-','s','#',0265,012,0345,'-','s','#',0265,012,0345,'-','s','#',0265,012,0345,'-','s','#',0265,012,0345,',',0253,027,034,'G',0200,0256,'R',0327,'&',0310,'j',025,0312,'Z',0344,0331,015,'B',0271,'K',0134,0253,'!',0250,'W',')','k',0223,037,0250,'W',')','k',0221,035,0251,'W',')','a','b','c',07,0372,025,0312,'Z',0346,'G','j',025,0312,'Z',0346,'G','j',025,0312,'Z',0346,'G','j',025,0312,'Z',0346,'G','j',025,0312,'Z',0346,'G','j',025,0312,'Z',0346,'G','j',025,0312,'X',0330,0330,0377,0,047,012,0345,'-','r',0254,0206,0241,0134,0245,0256,'M',0220,0324,'+',0224,0260,0261,'1',0376,'n',025,0312,'Z',0346,'F',0217,0364,'+',0224,0265,0314,0216,0324,'+',0224,0265,0314,0216,0324,'+',0224,0265,0314,0216,0324,'+',0224,0265,0314,0216,0324,'+',0224,0262,0222,0244,'(',0245,'B',0242,047,'c','2',0347,033,'I',0367,0376,0333,047,0227,'?',0332,'W',0274,0354,'f',0134,0343,'i','>',0377,0,0333,'d',0362,0347,0373,'J',0367,0234,033,0324,0270,0211,'v',0365,']',0211,' ',0360,'-','}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,'}','P',032,025,0303,0253,'_','T',06,0205,'p',0352,0327,0325,01,0241,0134,':',0265,0365,'@','h','W',016,0255,030,0365,'/',0342,'^','=','O','b',0211,'<','O',0376,026,0307,'X',07,0226,'E',0307,0347,'J',0300,'k',0321,'}',0255,034,032,0364,'_','k','G',06,'z',0217,0306,0265,'#','D',0222,'-',0215,'M','z','/',0265,0243,0203,'^',0213,0355,'h',0340,0321,0364,'q',0344,014,':',0242,024,0360,032,0277,0355,'S',0261,'v','5','V','M',0351,'t',0225,'U','P',0255,0257,'E',0366,0264,'p','k',0321,'}',0255,034,032,0312,'X',0325,'X',0307,0241,0322,0225,']','b',0271,0300,'Q',0307,0221,0320,0351,0210,'K',0300,'+',0377,0,0265,'5',0350,0276,0326,0216,015,'z','/',0265,0243,0203,'(','Z',0232,0244,0351,037,0221,'i','F',0226,0275,027,0332,0321,0301,0257,'E',0366,0264,'p','k','#','`',036,'X',0347,037,0235,'K',07,016,0213,0346,0375,0346,'q','^',';',0317,'S',0357,047,'}',0361,':','C',0233,036,0356,0371,011,0321,'<',0261,'{','?','b','t',0263,',','F',0317,0331,0235,036,0315,0216,0267,0374,0214,0336,'w',0314,0241,'|','w','~',0243,0336,'t',0243,'7',0357,030,'t','_','7',0357,'3',0212,0361,0336,'z',0237,'y',';',0357,0211,0322,034,0330,0367,'w',0310,'N',0211,0345,0213,0331,0373,023,0245,0231,'b','6','~',0314,0350,0366,'l','u',0277,0344,'f',0363,0276,'e',013,0343,0273,0365,036,0363,0245,031,0277,'x',0303,0242,0371,0277,'y',0234,'W',0216,0363,0324,0373,0311,0337,'|','N',0220,0346,0307,0273,0276,'B','t','O',',','^',0317,0330,0235,',',0313,021,0263,0366,'g','G',0263,'c',0255,0377,0,'#','7',0235,0363,'(','_',035,0337,0250,0367,0235,'(',0315,0373,0306,035,027,0315,0373,0314,0342,0274,'w',0236,0247,0336,'N',0373,0342,'t',0207,'6','=',0335,0362,023,0242,'y','b',0366,'~',0304,0351,'f','X',0215,0237,0263,':','=',0233,035,'o',0371,031,0274,0357,0231,'B',0370,0356,0375,'G',0274,0351,'F','o',0336,'0',0350,0276,'o',0336,'g',025,0343,0274,0365,'>',0362,'w',0337,023,0244,'9',0261,0356,0357,0220,0235,023,0313,027,0263,0366,047,'K','2',0304,'l',0375,0231,0321,0354,0330,0353,0177,0310,0315,0347,'|',0312,027,0307,'w',0352,'=',0347,'J','3','~',0361,0207,'E',0363,'~',0363,'8',0257,035,0347,0251,0367,0223,0276,0370,0235,'!',0315,0217,'w','|',0204,0350,0236,'X',0275,0237,0261,':','Y',0226,'#','g',0354,0316,0217,'f',0307,'[',0376,'F','o',';',0346,'P',0276,';',0277,'Q',0357,':','Q',0233,0367,0214,':','/',0233,0367,0231,0305,'x',0357,'=','O',0274,0235,0367,0304,0351,016,'l','{',0273,0344,047,'D',0362,0305,0354,0375,0211,0322,0314,0261,033,'?','f','t','{','6',':',0337,0362,'3','y',0337,'2',0205,0361,0335,0372,0217,'y',0322,0214,0337,0274,'a',0321,'|',0337,0274,0316,'+',0307,'y',0352,'}',0344,0357,0276,047,'H','s','c',0335,0337,'!',':',047,0226,'/','g',0354,'N',0226,'e',0210,0331,0373,'3',0243,0331,0261,0326,0377,0,0221,0233,0316,0371,0224,'/',0216,0357,0324,'{',0316,0224,'f',0375,0343,03,0377,0304,0,'<',021,0,0,04,02,06,07,06,04,05,04,03,0,0,0,0,0,01,02,03,04,0,020,05,021,022,024,'1','3',023,' ','!','0','2','R','q',025,'"','A','Q',0201,0221,'#','@',0241,0261,'B','C','D','S',0360,06,'4','a',0321,'`',0301,0341,0377,0332,0,010,01,02,01,01,'?',01,0336,0224,0242,'a',0250,0260,0215,024,0345,']',0242,025,'u',0204,0350,'D',0203,'0',0302,'0','J','=',0251,06,0260,047,0375,0375,0340,033,0242,030,020,'=',0243,'@',0227,'(','{','A',0330,0266,'S',0210,0201,0366,0373,'C',0212,024,'*',0255,01,0364,030,'9',014,0231,0254,0234,'*',037,0226,'M','#',0254,'k',')',0205,'c',015,0350,'_',025,0307,0320,'!','&',0351,' ',025,'&','Z',0267,024,0223,';',0312,'v',0213,0304,037,0312,0276,'U',0245,020,'u',';',0313,0354,017,0254,'$',0212,'h',026,0312,'a','T',0325,']','4',02,0265,015,'T','+','M','"',']',0211,0205,0177,'H','R',0231,'p','n',032,0202,015,'H',':','>',047,030,0276,'9',0375,0301,0367,0204,')','u',0310,'o',0213,0336,011,0322,0255,'4',012,0351,013,0201,0276,0377,0,'$',0212,'*','.','k',011,0205,'p',0316,0215,'M',0257,'x',0333,'M',0374,0302,'n',036,'"',0324,'>',' ',0303,0212,'a','e','6','%',0335,017,0254,030,0302,'q',0254,0303,0252,0212,'b',0252,0205,'L','<','f',0345,02,0271,'H','S',030,'9',014,0231,0204,0206,0304,'>','A',0243,'C',0273,'=',0222,0341,0342,'0',0335,0262,'m','I','a','9',030,0305,' ','Z','0',0354,0207,0224,0270,0217,'q',0277,0277,0372,0203,030,'L','5',0233,'^',0206,'k',0372,0203,'z','j','S','-',0177,'P','_',']',0373,'F',0207,'v',0245,0202,0341,0343,010,0242,'F',0344,04,0323,015,0222,'r',0351,'6',0244,0266,'x','t',0361,'G','f',0254,0330,'y','n',031,'4','3',0265,'*',0360,0361,0202,0224,010,'P',')','p',0220,0322,'E',07,0232,037,0303,0207,0257,0363,'d',0214,'P','8',011,'M',0200,0303,0266,0342,0325,'Q','L','w',0251,0246,'e',0216,04,'&','#',015,'[',021,0252,'v',013,047,0217,010,0320,0225,0216,'>',020,0262,0307,0134,0366,0324,035,0273,0206,0215,024,'v','{','$',0204,020,'#','t',0301,'2','J',0222,'{','v','N',0311,'x',0206,'T','k',0253,0312,'=',0356,' ',0225,'(',0322,0360,0225,0242,0361,027,'{','D','4',0321,0223,'N','l','G',016,0222,'p',0271,'[','&','*',032,027,0134,0356,'T',025,017,0270,'e','G',0250,0354,'k',0300,0276,'p',0212,'$','n','K',011,0206,0311,'<','v','F',0204,0264,'8',0370,'B',0252,0231,'c',0211,0317,0210,0312,0214,'P',0304,'t','[','>','3',0245,032,']',0325,0264,'^',023,'n',0333,'#',0247,'X',0251,0371,0300,0,024,'*',011,'R','n',0257,013,'Y','/',011,'u',0312,'S',034,'l',0224,'+',030,'g','D',01,'{',0356,'=',0240,0,0,'*',011,'<','z','F',0205,0333,0217,0224,',',0261,0334,036,0332,0203,0266,'t','2','"','u',0264,0276,05,0233,0266,0340,0351,'!','L','`',0305,022,010,0224,0330,0356,0250,'R',0200,0256,'&',0362,011,'>','T','P','n','c',0206,':',0305,'(',0234,'j','(','C','j',035,'U','6',0253,0335,017,0254,' ',0325,'&',0301,'R','a','7',0264,0241,020,0254,0211,'m','7',0332,016,0241,0225,'5',0263,0215,'c','2',020,0312,030,012,0134,'F',032,'7',06,0251,02,'a',0251,'L','4',0250,'o',05,0365,0335,'P',0206,0251,'c',027,0374,'I',0363,'{',0322,'"',0230,'c',012,'3','p',0217,031,06,',',0217,0224,025,0262,0347,0332,'R',017,0264,047,'D',0272,'>','!','T','#','B',0246,']',0252,0232,0270,'I',04,0220,012,0223,'-','S',']',0302,'m',0313,'i','A',0207,0224,0252,0213,0367,023,0330,'_',0256,0255,030,0303,'@',032,'U','8',0207,0351,'%',0327,'+','t',0305,'C','E',032,0374,0332,'q','*',0243,0307,0367,0222,0204,'*',0245,022,033,01,0207,'(',013,'e','E','1',0334,0266,0134,'[',0252,012,07,0204,'&','r',0252,'P','9','p',035,0302,0256,022,'@','+','P',0325,'C',0232,'h','G','b',01,0352,'0','u',014,0241,0255,034,'k',035,'L','b',0215,0243,'t','_',031,'l','|',03,0313,0377,0,'d','"',0,025,0214,'R','/','o','G',0250,0274,'!','*','=',0325,0351,032,0307,0210,'1',0225,'6',0210,011,012,0257,0216,033,0252,'!',0345,0203,']',0317,0200,0341,0252,'w',0215,0323,0342,'8','B',0264,0322,05,0340,012,0341,'j','Y',0302,0273,013,0335,0203,030,'L','5',0233,'U','$','T',0134,0326,023,012,0306,031,'Q',0244,'k',0337,'>',0323,'K',010,0244,0251,035,'7',0302,'K',0207,0357,':',020,07,'H','q',0360,0252,'T',0317,0366,0336,0273,0254,'"',0217,'w','z','K','o',020,'c','*','a',03,011,'A','r','x','c',025,0210,0356,032,'Q','J',0255,0336,'W',0272,'_',0254,'"',0202,'m',0313,'e','0',0252,'F','1','H',026,0214,';','"',0220,0244,0205,0307,0303,'K',0207,0357,0251,'E',0266,0320,'!','X',0342,'m',0262,0246,0325,0330,'D',0275,'w','m',034,0213,'U','A','@',0202,034,0252,024,016,0134,06,014,'P','0',011,'F',036,'6',026,0252,0212,'z',0245,'(',0230,'j',',','7',0242,'W','W','i',0373,0241,015,0250,0364,033,'m',0,0254,'|',0346,0345,0332,'M','K','Y',0306,035,0276,'U',0330,0355,0330,'_','-','J','1',0225,0345,'K','f',0341,011,010,0201,'B',0261,0207,'k',0336,'V','2',0233,0312,'!',0345,0221,0273,0237,0322,'N',0331,'&',0360,0265,033,020,0203,'P',0213,'W',0335,'0','G','b','8',0346,017,0257,0372,0202,'P','j',017,031,0303,0371,0355,011,'P',0315,0311,0307,0266,023,'E','4','B',0244,0313,'T',0316,'r',0246,'[','G',032,0202,035,'S','?',0205,0277,0274,034,0346,'P','m',030,'k',035,'F','m',016,0354,0366,'K',0207,0210,0302,'I',025,022,02,'d',0300,'%','K',0274,0250,'.',0344,0365,0336,0200,0325,0264,'!',0203,0273,0332,'U',0217,020,'c',0256,0252,0351,' ',025,0250,'j',0241,0305,'4',01,0261,0,0365,030,'Y',0302,0253,0215,'j',015,'z',0254,0330,0250,0354,0333,'6',027,0316,021,'D',0215,0311,0243,'L','6','J',0220,'~',015,013,'d',0274,'C',06,'0',0230,'m',033,0134,'F',0255,0243,032,'d',0271,0202,'4',0311,'s',04,'i',0222,0346,010,0323,'%',0314,021,0246,'K',0230,'#','L',0227,'0','C',':','@',0215,'U',03,0201,0203,0374,0300,'R',0214,'G',0363,0213,0356,021,0332,'l',0177,'x',0276,0341,03,'L',0321,0345,032,0264,0241,07,0247,0230,027,03,0327,012,0177,'Q','%',0371,'a',0356,'0',0255,'4',0252,0277,0230,01,0322,05,0302,'b','5',0211,0376,0261,0246,'K',0230,'#','L',0227,'0','F',0231,'.','`',0215,'2',0134,0301,032,'d',0271,0202,031,0246,0320,0335,0367,013,024,03,0312,0260,0202,0322,014,010,026,'J',0251,'j',0352,021,0332,'l',0177,'x',0276,0341,016,0351,0266,0250,0227,0341,034,014,'=','a','G','E','T',0302,'s',0237,'h',0306,0231,'.','`',0215,'2',0134,0301,032,'d',0271,0202,'4',0311,'s',04,0,0327,0264,'&',0266,'Q',0272,'|',0352,'9','E',0351,'5',0262,0215,0323,0347,'Q',0312,'/','I',0250,'[','D',022,0204,0134,'U',0213,0212,0261,'q','V','.','*',0305,0305,'X',0270,0253,027,025,'b',0342,0254,0134,'U',0213,0212,0261,'q','V','.','*',0305,0305,'X',0270,0253,027,025,'b',0342,0254,0134,'U',0213,0212,0261,'q','V','.','*',0305,0305,'X',0270,0253,027,025,'b',0342,0254,0134,'U',0213,0212,0261,'q','V','.','*',0302,'e',0262,'@','(',0377,0,0301,'V','t',010,0232,0310,0204,'v',0201,'y','c',0264,013,0313,0,'5',0205,'s',0355,02,0362,0307,'h',027,0226,022,'x',012,0234,011,'T',0327,'X',021,'-',0241,0216,0320,'/',',','v',0201,'y','a',05,0201,'b',0332,011,0252,0360,022,'8',0222,0250,0355,02,0362,0307,'h',027,0226,'b','5',05,'q',0332,05,0345,0216,0320,'/',',','"',0350,026,'5',0220,015,'w',0271,0263,047,010,'H','p',0233,'L',0342,0315,0376,'X','u',0233,014,0261,0353,'7','y',0306,0230,'a','#',0360,0214,0331,'f',0353,0275,0315,0231,'8','B','C',0204,0332,'g',026,'o',0362,0303,0254,0330,'e',0217,'Y',0273,0316,'4',0303,011,037,0204,'f',0313,'7',']',0356,'l',0311,0302,022,034,'&',0323,'8',0263,0177,0226,035,'f',0303,',','z',0315,0336,'q',0246,030,'H',0374,'#','6','Y',0272,0357,'s','f','N',020,0220,0341,'6',0231,0305,0233,0374,0260,0353,'6',031,'c',0326,'n',0363,0215,'0',0302,'G',0341,031,0262,0315,0327,'{',0233,'2','p',0204,0207,011,0264,0316,',',0337,0345,0207,'Y',0260,0313,036,0263,'w',0234,'i',0206,022,'?',010,0315,0226,'n',0273,0334,0331,0223,0204,'$','8','M',0246,'q','f',0377,0,',',':',0315,0206,'X',0365,0233,0274,0343,'L','0',0221,0370,'F','l',0263,'u',0336,0346,0314,0234,'!','!',0302,'m','3',0213,'7',0371,'a',0326,'l','2',0307,0254,0335,0347,032,'a',0204,0217,0302,'3','e',0233,0256,0367,'6','d',0341,011,016,023,'i',0234,'Y',0277,0313,016,0263,'a',0226,'=','f',0357,'8',0323,014,'$','~',021,0233,',',0335,'O',0377,0304,0,'L',020,0,01,03,01,02,05,015,015,07,03,02,07,0,0,0,0,02,01,03,04,0,020,021,05,022,'!','1','A',023,' ','"','Q','a','q','r','s',0222,0223,0261,0262,0341,'#','0','4','5','B','R','t',0201,0202,0221,0241,0301,0321,024,025,'$','2','3','@','b','C','S','c','%','T',06,'`','d',0204,0322,0342,0360,0377,0332,0,010,01,01,0,06,'?',02,0357,0244,0353,0356,03,'-',0216,'s','5',0271,022,0224,'Z','3',0234,0342,0177,'a','6','>',0365,0253,0242,'D','b','(',0355,0235,0346,'_','*',0271,0314,'(',0372,047,0370,0227,'S',0352,0335,'[','9',0322,'O',0204,0351,'-','d',0224,0362,'o','8',0265,'{','8','N','F',0361,0236,':','{',0226,0205,0274,'/',035,014,'?',0276,0302,0134,0251,0276,'4',022,'b',0272,'/','2','y','D',0307,0366,0312,0374,0311,01,035,0275,0262,0134,0373,0324,0255,'`',0210,0377,0,0367,017,0247,'@',0375,'k','T',0233,')',0311,05,0374,0327,'"','o','&',0216,0360,'-',0272,'K',0366,011,013,0212,0350,0337,0220,'W',0317,0253,0323,'*','~',0315,'H',0225,04,'S',':',0255,024,'|',020,0203,')',0355,'2',027,0364,0307,'{','n',0225,0371,0262,016,'C',0253,0244,0327,'6',0366,0325,0272,0234,'8',0316,'I','?',0340,'7',0335,0277,'H','S',036,'f',010,0355,'~','r',0370,'d',0370,0325,0362,035,0221,',',0267,'K',024,'~',037,'Z',0270,'p','c','E',0306,'*',0237,'M',']',0367,'T','o','P',']','N',026,016,0306,0207,'%','2',0212,'c',')',02,0356,'e',0267,0356,0367,0316,0371,'Q',022,0344,0277,0312,'o','G',0273,'7',0273,0366,'K','&','k',0310,0320,'h','M','$',0273,'H',0224,'M',015,0361,'`','_',0221,0221,0134,0245,0302,0333,0267,026,024,'u',' ','O',0314,0351,'d',01,0365,0320,0271,0204,'M','g',0275,0237,021,'6','-',0247,0326,0205,0246,032,06,'[',034,0300,0330,0334,0232,0331,'s',017,0362,0262,0332,0226,0375,0261,0347,'3',0235,0265,0331,017,0234,':','R',0231,0224,0301,'c','2',0350,0241,012,0376,0303,'U','{',0272,'H','?',0322,'a',027,')','v','R',0311,0230,0346,'1','y',' ',0237,0224,023,'i',',',06,0231,'l',0235,'t',0326,0341,0,'K',0325,'h','%','a',0254,0253,0235,'"',012,0365,0227,0345,'B',0323,'-',0213,'M',012,0134,' ',011,'r','&',0274,'0','+',05,'}',0327,'9','"',0357,0200,0374,0375,0332,0302,0300,0322,013,'`',0346,0316,'=',0372,013,'H',0367,0375,']',0336,0350,0371,0344,'e',0235,'&',0277,'J','r',0134,0267,'5','G',0217,0334,0233,0211,'b','F',0210,031,0262,0233,0213,0371,'A','7','j',0346,'G','U',0224,0251,0263,0220,'I',0262,']',0355,0244,0357,012,'H',0250,'S',']','K',0231,'o',0346,0273,0224,0343,0316,0222,0233,0246,0270,0304,'K',0245,'l',0134,'.',0230,0337,'j',0277,'U',026,0266,0331,0377,0,0354,0266,'6',0363,'E',0210,0343,'d',0204,'$',0232,025,')',0231,'c','r',';',0371,']',04,0362,'O','O','}','z','d',0223,0304,'e',0244,0275,'W',0345,'N','K',0220,0267,'h','m',0275,0,';','V','j','-','l',030,014,0256,0275,0240,'S',0353,'A',022,033,'x',0215,0246,'u',0322,'K',0266,0275,0343,'U',0177,'f',0361,0376,0223,011,0234,0327,0351,'N',0314,0226,'x',0356,0237,0270,'S','i',',',0325,'^',037,0364,0370,0353,'{',0213,0347,0257,0233,'X',0267,'&','.','k',0250,0221,0261,0272,034,0216,0350,0316,0346,0330,0372,0254,'F',0336,'+',0241,'J',0330,'9','~','a',']',05,0337,'~',0353,'`',0377,0,015,025,'{',0245,0336,'S',0235,0226,'3',012,'2','l',0317,'9','h',024,0322,0253,'M',0303,0212,'7',010,0376,'b',0134,0346,0273,'k',0336,025,0226,0356,0223,0204,027,'3','(',0271,07,'t',0250,0345,'K','u',']','x',0364,0256,0215,0304,0261,030,'e','1','Z',034,0256,0275,'v','@','J','j',034,'P',0304,'e',0264,0367,0356,0331,')',0307,'n',023,0217,'s',0215,0222,0350,'[',0356,0370,0337,'u',0277,'e','x',0257,0231,021,020,'V',0377,0,'(','4','/','{',0231,'7','&','3','a',0260,0277,0316,0314,0237,032,'#','2','R','2','[',0325,'W','J',0330,'2','^',013,0246,'K','D','2',0277,'8',0216,0201,0327,0223,0362,']',026,'Y',034,0346,'k','r','Q','F',0300,0327,0260,0326,'e',0222,0277,0235,'w',0266,0251,'H',0225,'H',0225,'o','U',']','6','b','4',0232,0234,'`',0375,'W',0325,'2',017,'m',04,'H','m',0342,'6',0231,0327,'I','.',0332,0332,0326,016,025,0356,0262,0213,030,0223,'h',07,'/','M',0326,0261,'5',0274,0250,'+','s',0201,0347,016,0224,0246,0244,'2','X',0355,':','(','B','I',0245,';',0324,'F',021,'n','G','_',0275,'w','Q',022,0310,021,0134,'L','f',0210,0361,0215,'6',0321,'2',0374,0265,0304,0354,0207,'A',0226,0207,'9',0270,'W','"','Q','5',0203,03,0355,0257,'f',0325,013,'#','i',0365,0255,'V','t',0202,'w',0315,014,0302,';',0311,'k','r',0246,0343,'E',0201,0237,0371,0271,0275,0271,0273,'A',032,'+','B',0303,01,0230,06,0327,'d',0310,'=','M',0226,0207,030,0212,0237,0232,0346,'D',',',0215,0207,0232,032,023,'X','X',026,'A',0355,0234,'{',0376,'#',0363,0367,0367,0254,036,0375,0337,0221,0345,013,0367,0323,0377,0,'[',030,0232,'b',0246,0322,'^','&','#',0236,0345,'J',025,'c',010,0261,'y','y',016,026,'!','{',0226,0274,'!',0256,'Z','R',0243,0270,'N',' ',022,'y',':',0262,'_',0356,0245,0324,0215,0331,0205,0264,0323,'w','t',0335,'D','0','#','5',014,'r',0354,0317,'f',0177,'J',0325,'&',0312,'r','I',0177,'2',0310,0233,0311,0242,0335,'B',024,'r','|',0364,0335,0230,'w',0327,'E',04,0234,'!',0213,'6','b','e','A',0376,0230,'/',0317,'X',0252,0253,'r','&',0232,0373,014,'#',0377,0,'O','i','r',0222,0177,'T',0266,0367,0254,'b',024,'q',0275,0307,012,0353,0374,0324,0322,0265,036,'D',06,0356,',',036,0336,')',0335,0345,0267,0245,'W',0247,0326,0266,'5','!',0202,0304,'u',0242,'B',022,'M',0272,'b','k','y',024,0222,0343,017,'4',0264,0247,'y',0223,04,0362,')',0246,0300,0274,0322,0320,0264,0354,'w',0301,'[','y',0242,0305,'!',']',0276,0361,0251,0302,0212,0344,0202,0376,011,0221,'7',0327,'E',013,0270,'a',0373,0377,0,0351,0330,'^',0222,0372,'P',0261,021,0200,0216,0312,'y',' ',0227,'k',010,0314,0220,'@','R',0365,'U',0321,'G',0203,0260,'i',0252,'B',0314,0353,0311,0375,']',0304,0376,'=','6',' ',0212,')',022,0344,'D','M','5',0253,0311,024,0373,0301,0364,0331,0377,0,0215,'<',0332,'Q','$',0274,'W','"',0242,0323,0215,012,'~',025,0336,0350,0302,0356,'m','z',0254,0225,0203,0325,'{',0223,0255,0352,0251,0270,'I',0330,0277,016,0365,0367,0314,'P',0356,0215,0245,0322,021,'4',0217,0235,0352,0326,0242,'1',0203,'d',0235,0376,'R',0266,0250,0236,0365,0244,'Y','N','3',010,'v',0225,'q',0313,0334,0237,'Z',022,0221,0252,'O','q','?',0270,0267,017,0271,'(','Z','a',0240,'e',0241,0314,0,'7','"','k','V','D',0327,0305,0226,0364,'_',0234,0267,021,'4',0322,0260,0315,0361,'p',0177,0366,0264,0237,013,0351,'e',0311,0225,'h','0',0236,021,'o',0361,'k',0225,0246,'W',0372,'{',0253,0273,'n',015,05,0273,'V','W',011,'S','z',0354,0277,'+',033,0273,'C','&',0253,0336,0210,015,020,0204,0222,0345,'E',0323,'D',02,0237,0203,'{','f',0301,'n','m','z',0254,'<',031,'-',0226,0217,'W',0331,'2','f',010,0253,0215,0346,0327,'s','h',03,0202,'7','k',0357,'U',0271,'(',0330,0301,0327,'N',0227,0233,037,0372,'c',0353,0323,0352,0242,0221,'5',0362,'}',0305,0333,0314,0233,0311,0242,0300,'i',0220,047,035,'5',0270,'@','R',0365,'Z',011,0370,'H','Q',0311,0331,0301,0254,0350,0327,'n',0261,0304,'h',0261,0243,'F',0356,'M',0356,0355,0257,0277,0242,0311,0370,'A','S',' ',0212,'0','+',0277,0225,'z',023,0275,0273,020,0266,'.',0246,0311,0243,0363,'J',0234,'a',0340,'V',0335,'l',0261,'H','W','B',0320,':',0331,'(','8',013,0214,'$',0232,026,0231,0225,0221,036,'M',0203,0303,0264,'z',0322,'u',0367,'A',0226,0307,'9',0231,0134,0211,'J',020,0320,0260,0213,0337,0303,' ','{',0376,0224,0242,0373,0372,0224,0177,0366,0354,0344,037,'^',0335,0272,0214,'6',0257,'O',')',0322,0310,01,0276,0265,0216,'?',0210,0232,0251,'q','H','$',0350,0332,0326,',','(',0307,0370,0371,')','v','L',0355,0206,0335,0202,0330,012,0221,0222,0334,0202,0232,'V',0243,'C',0271,'5','[',0261,0235,'T',0322,'k',0237,0276,'}',0365,024,'6','c',0222,'H',0242,'g','M',05,'a',';',033,025,0306,0334,0310,0343,047,0230,0251,'>',0321,02,'K','g',0245,032,0305,'$',0371,'V','H',0263,0271,01,0377,0,0225,'~',027,06,0272,0342,0377,0,0225,0304,036,0213,0350,0222,'>',0243,010,'4','j','c',0214,'^',0365,0254,'y','r',0235,0222,'_',0344,'+',0356,0264,'Y','a',0242,'y',0322,0314,0,0227,0252,0320,0277,0206,'O','S',017,0366,0255,0256,0311,'w',0327,'G',0252,0205,0210,0314,0203,014,0216,'`',04,0271,'5',0232,0241,0334,0344,0243,0375,026,'<',0355,0335,0352,'v',0134,0223,0325,036,'u','o','%',0263,0357,0231,'A',0334,'Z','_',0303,0242,0371,'E',0347,'z',0273,0351,'6',0340,0241,0201,'%',0312,'+',0245,'(',0331,'D','_',0262,';',0263,'`',0267,'6',0275,'Z',0375,'N',024,'W','$',027,0360,034,0211,0276,0272,'(',0134,0302,0262,021,0201,0376,0313,031,'K',0337,0233,0246,0265,'8','1',0201,0235,0262,0316,'E',0276,0272,0334,0134,0217,0316,'$',0330,'0',0213,0361,'-',0244,0247,'%',0313,'q',']','x',0376,033,0211,'f',';',0227,0267,0203,0332,'^',0350,0347,0235,0374,'R',0233,'e',0220,'F',0332,'m','1','D','G','2','&',0274,0234,'p',0220,0,'R',0365,'"',0134,0210,0225,0343,'(',0234,0360,0327,0214,0242,'s',0303,'^','2',0211,0317,015,'x',0312,047,'<','5',0343,'(',0234,0360,0327,0214,0242,'s',0303,'N','F',0134,'%',015,037,035,0233,047,0253,016,'B',0245,'M','M','r','m','e',0257,0323,'/','u','!',0212,'4',0210,0276,'{',0355,0212,0373,0225,'k','g','/',07,'G',0343,'f',07,0311,'V',0205,'f',0177,0304,0220,'C',0316,026,015,027,0342,0253,0362,0244,'R',0225,032,'c',0211,0345,'H',0222,'+',0360,0315,'H',0333,'S',0241,'4',011,0230,'A',0321,'D','J',0361,0224,'N','x','k',0306,'Q','9',0341,0257,031,'D',0347,0206,0274,'e',023,0236,032,0361,0224,'N','x','h',0342,0340,'f',0325,0327,'s',',',0245,035,0210,0360,'v',0350,0336,'{','T','u',0323,'[',0310,0313,'*',0255,'~',0231,'{',0253,0361,0263,032,0301,0361,03,0363,023,0206,0202,'e',0270,'(',0264,0324,'X',0263,0241,0264,0303,'i','p',0212,'<','5',0343,'(',0234,0360,0327,0214,0242,'s',0303,'^','2',0211,0317,015,'x',0312,047,'<','4','.','6','H','`','I','z',020,0256,'E','K','p',0227,0243,'9',0325,'_',0336,0340,0337,'F','o',0252,0226,0341,'/','F','s',0252,0277,0275,0301,0276,0214,0337,'U','-',0231,035,0273,0265,'G','Y',' ',033,0366,0325,'+','<','~','_','e','g',0217,0313,0354,0254,0361,0371,'}',0225,0236,'?','/',0262,0263,0307,0345,0366,'V','x',0374,0276,0312,0317,037,0227,0331,'Y',0343,0362,0373,'+','<','~','_','e','g',0217,0313,0354,0254,0361,0371,'}',0225,0236,'?','/',0262,0263,0307,0345,0366,'V','x',0374,0276,0312,0317,037,0227,0331,'Y',0343,0362,0373,'+','<','~','_','e','g',0217,0313,0354,0254,0361,0371,'}',0225,0236,'?','/',0262,0263,0307,0345,0366,'V','x',0374,0276,0312,0317,037,0227,0331,'Y',0343,0362,0373,'+','<','~','_','e','g',0217,0313,0354,0254,0361,0371,'}',0225,0236,'?','/',0262,0241,0307,'r',0355,'Q',0246,'D',012,0355,0264,'O',0371,025,'b',034,'S','u','P','P',0261,0220,0256,0257,0,'s',0234,'J',0360,07,'9',0304,0246,0235,0273,027,'T',024,'+',0267,0354,'"',0317,'r','_','^',0,0347,'8',0225,0340,016,'s',0211,'L',0303,030,'f',0332,0271,'~',0311,'O','5',0311,0177,0312,0326,0344,033,'*',0362,031,0342,0134,'+','v',0216,0312,0360,07,'9',0304,0257,0,'s',0234,'J','r','@','2',0254,0240,036,'%',0304,0267,0350,0355,0265,0350,'e',014,0334,'V',0356,0331,'!',0347,0275,'/',0371,0327,0200,'9',0316,'%','x',03,0234,0342,'P',0226,'k',0322,0373,035,'v',0354,'m','L','T',0256,0336,0257,0,'s',0234,'J',0360,07,'9',0304,0244,0210,021,'M',0245,'Q','R',0306,'R',0277,'^',0134,'P',0333,023,0211,016,0213,035,0340,0255,0260,'}',0276,0242,0333,033,0322,023,0252,'V',0311,0364,0205,0352,0215,0263,0275,0216,0242,'Z',0327,05,',',0227,0304,0237,'E',0243,0305,026,0274,0270,0241,0266,047,022,035,026,';',0301,'[','`',0373,'}','E',0266,'7',0244,047,'T',0255,0223,0351,013,0325,033,'g','{',035,'D',0265,0256,012,'Y','/',0211,'>',0213,'G',0212,'-','y','q','C','l','N','$',':',',','w',0202,0266,0301,0366,0372,0213,'l','o','H','N',0251,'[',047,0322,027,0252,'6',0316,0366,':',0211,'k',0134,024,0262,'_',022,'}',026,0217,024,'Z',0362,0342,0206,0330,0234,'H','t','X',0357,05,'m',0203,0355,0365,026,0330,0336,0220,0235,'R',0266,'O',0244,'/','T','m',0235,0354,'u',022,0326,0270,')','d',0276,'$',0372,'-',036,'(',0265,0345,0305,015,0261,'8',0220,0350,0261,0336,012,0333,07,0333,0352,'-',0261,0275,'!',':',0245,'l',0237,'H','^',0250,0333,';',0330,0352,'%',0255,'p','R',0311,'|','I',0364,'Z','<','Q','k',0313,0212,033,'b','q','!',0321,'c',0274,025,0266,017,0267,0324,'[','c','z','B','u','J',0331,'>',0220,0275,'Q',0266,'w',0261,0324,'K','Z',0340,0245,0222,0370,0223,0350,0264,'x',0242,0327,0227,024,'6',0304,0342,'C',0242,0307,'x','+','l',037,'o',0250,0266,0306,0364,0204,0352,0225,0262,'}','!','z',0243,'l',0357,'c',0250,0226,0265,0301,'K','%',0361,047,0321,'h',0361,'E',0257,'.','(','m',0211,0304,0207,'E',0216,0360,'V',0330,'>',0337,'Q','m',0215,0351,011,0325,'+','d',0372,'B',0365,'F',0331,0336,0307,'Q','-','k',0202,0226,'K',0342,'O',0242,0321,0342,0213,'Y',0377,0304,0,'*',020,0,01,01,06,05,05,01,0,03,01,0,0,0,0,0,0,01,021,0,020,'!','1','Q',0360,'A','a','q',0201,0241,' ','0',0221,0301,0361,0261,'@',0321,0341,'`',0377,0332,0,010,01,01,0,01,'?','!',0356,0202,0211,'(',0261,0263,'%',0212,0373,021,'=','(',021,0242,0261,0324,'T',0366,'(','8','m',047,0201,0370,'2',0312,'S','6','Q',033,0250,'>',0331,'&',0371,0356,'t','1','J','B',0233,0343,0211,0262,'h',0301,'P',0352,'*',015,0323,0370,0300,'L','s','E','@',0231,'9',06,'(','(',011,'b',0254,0237,0203,'F','[',0250,0376,0220,0330,';',04,0306,024,0210,0224,0,'i',0216,'Z',06,0,0210,011,020,'G',0360,0307,0204,024,0204,0,'2',016,'8','D',0373,036,'5','o',0353,0210,0220,022,014,0203,0342,0337,020,0203,06,0244,0206,0354,'R',' ','.',037,'P',0301,025,030,0210,07,0210,025,0232,0375,0204,0271,0226,'_',06,'2',0177,014,032,'F',022,'I','j',04,'H',0324,030,'P',0275,'q',022,024,0243,'(',0254,0362,0376,020,0274,'X','N',0363,0221,'b',0306,06,016,'p',047,0370,0226,0263,'z',0212,'"','y','{',0320,')','`',0352,'(',0240,0221,0240,0216,0350,032,'0','s',0262,0,026,0303,0244,0210,0242,037,022,'H',01,0231,'(','7','y',0311,'&','t','@','h',027,'Q',0351,0264,'_','Z',032,0347,0374,05,' ',04,'!','8',0365,'4',014,'K','a',0316,0240,'(',014,034,0243,'`',0,0214,0200,'`',0300,'`','C','[','_',0217,'8','2','#',0264,020,0250,0,0353,0212,015,' ',0261,0237,0271,0320,0230,0354,'I',0250,0336,0230,0314,032,0367,0316,'&',01,'J','z','!',0211,0366,0214,'K',0346,0304,0340,0340,014,0,0243,0226,0347,06,0356,0213,0360,'b',0301,'`','q',0134,0376,01,0272,0366,010,013,0207,0306,'4',0250,0346,'L','`','k',0237,0220,0251,'.',020,0204,'H',0264,047,0251,0342,'3','q','x','M',030,'B',0203,0345,0214,'R',012,'a','&',0206,'c','"',';',0240,0264,0263,0246,'h',031,0223,01,0253,'!',0220,'a',016,'H','=',0234,'K',0201,0344,0302,0307,0372,0213,0,0302,'c',033,0273,0213,0211,0354,',',0350,0340,'o',0371,03,023,0355,03,033,0211,0262,0330,013,0,034,'<','Z',022,0245,'0',017,0274,0265,014,016,'"',020,0201,020,'J','4',0352,0202,022,0213,0220,'|',020,0343,'+',0240,',',0377,0,014,'`','r','9','4',0373,0207,025,'P','!','u','5','%',0321,0332,'q',04,037,0204,'?',0241,0213,'M',0370,0265,'W','8',0361,'.',0302,':',047,'4',0230,'i','3',0313,'M','<',0222,03,0,'`',05,034,'}',0311,0213,'W',0276,'N',01,0201,0341,'(',014,'K',022,0251,'.','Z',0310,0244,0332,'6',026,0340,0364,'s',0315,'9',0253,'x',0230,'!',0323,'>',0331,0332,'@',0364,'H','N',017,0220,'c',0316,'Q',0345,'$',0211,'%',0320,0202,'(','U',0345,'T',0346,'r',0353,04,0235,'T',0201,0242,0272,0300,0323,'G',0207,'3',035,030,0203,0334,']','I',031,0222,0134,0276,0306,'`',0325,05,'r','4',0320,04,0261,0307,023,022,0360,0220,' ',0324,0,0255,0370,013,0325,'Y',':','c',0375,06,'`','0','I',0343,0214,02,0216,0324,020,'f',0324,0341,0344,0217,016,0215,0364,'@','P',031,'0','r','0','n',0300,' ','A',0322,'8',0250,0242,'7',0205,0201,0233,022,0242,'&',0376,0355,'A',0233,'B','$','*',035,0230,'`','5',0233,0305,0232,0264,02,020,'9','0',0314,0331,0205,'n','P','T',032,0346,'s','x','F',024,';',0,031,'p',0216,'Y',0205,0364,'9',0223,0321,06,0260,0317,0177,0334,';','B',017,'P','5','D','w',03,0377,0,0323,0212,'I',05,0304,024,';','0',',',0245,016,0256,0331,'k','{',0333,'L',0306,04,'_',021,'V',04,017,0224,'T',036,'e','h',0254,'(',0243,'@',0332,0210,0220,'n',013,'D',0262,0250,'X',0360,033,036,'?',05,026,010,'*',0310,06,'R',0250,010,'v',0300,0317,0231,0360,0300,' ','@',0361,0266,011,'I',024,0,'4','F',0305,0230,0200,'_',0206,036,'h',0342,'R',024,'H',0206,'#',0220,021,'h','*',0262,0,0263,'*',0210,'*',0340,'C',0270,'c',0,0262,'c',047,'"',0251,0373,'8','#',0262,'~',02,0371,'0','c',0346,0341,0213,0330,030,'`','v','"',0275,0320,0377,0,'H','n',',','F',0253,0224,0263,0375,'4',0212,0222,0235,0256,'g','>',0203,0220,'A','t',01,'R','X',0350,'u',0200,033,0217,0361,'6','%',0363,0,0324,0221,0220,01,0206,'T',0257,'V','(',037,'y',0350,0303,0320,'.',0,'C',027,'<','l',0316,'z',0312,032,'%',0134,0251,0344,0311,'3','`','C','^',07,'k',013,0230,0134,'p',0265,'H','r',0323,0240,02,'H','"','K',07,0220,012,'8',014,034,0262,0326,'p',0245,033,0300,0302,0201,0243,034,'n',0350,022,'X','a',0201,05,015,0220,035,'#','f',0240,0244,'M',0301,'h',0300,0230,'S',0,';',0344,'?',0306,0256,' ',0200,'I',0,06,'-','%',0352,0213,0241,'q',0254,0234,030,0305,037,0210,020,0375,037,027,033,0244,0322,0210,0237,0244,'v',0216,'D',0201,0224,01,0230,',','S',0321,024,'.','c',0314,0212,'h',0225,'p',0327,0306,0206,02,'"',0243,0201,02,031,0214,0330,'Z','h',047,0343,0254,0344,0,05,'$',0310,'1','o',021,'P',0237,0237,0343,0344,0322,0332,'R',0340,0322,'@','d',035,036,0252,'$','(',03,016,'K',0266,032,0361,030,'W',0241,0,015,'`','`','@',0363,0360,07,'j',027,0344,'H','x',0371,'{','i',0343,025,0304,0231,'l','d','r',',','s',0356,0237,0202,'a',0202,0300,'3',0,025,04,'0','Z','`','g',012,'{',031,0215,'z','A',0300,0224,'P',0331,0222,0310,0234,'`',0260,'g','3',0236,0302,0304,0324,'Y','(',0237,'-',0317,030,',','x',0300,',',0204,0330,'`','8',0232,0263,03,0203,0232,0364,01,0212,0230,0221,020,':',0314,0206,0347,07,016,0322,0206,')','$',0,014,'u','!',0327,0202,',','R','C',' ',';',0230,'p','D','e','#','f','G','$',0243,0220,0360,0204,0222,022,'9',031,0307,'6','4',0343,'q',0262,'$',0376,031,024,'I',0314,'M',021,0321,'2','<',030,0214,0216,0231,020,'n',0216,03,'F',0332,'(',047,035,03,015,0236,'a','V',0206,0366,01,0261,0347,'c',0302,'>',036,'A',0200,0370,'Q','(',0350,'!',' ',022,024,0211,'U','@',0304,0261,0375,0252,0337,0301,'@','$',0341,'9',021,0273,'t','`',0317,'N',0351,'<',030,'j',0202,'L',026,'6','"',0204,0305,'q',0221,0254,0236,016,'=','`',0353,':',025,0217,01,0271,0215,0315,0311,'6',0331,0225,0263,'#',0322,0204,030,0335,'1','=','&','+','S','K',',','3','c',0343,010,0223,' ',0300,030,01,'G','#','8','f',0201,'/',0326,0247,06,037,'N',0206,'@',0244,07,'Y',0364,0371,'0',04,0311,'8',06,0266,0275,0265,0265,0355,0255,0257,'m','m','{','k','k',0333,'[','^',0332,'4','V','p',0275,0344,'d','X',0211,')','$','(','G',0221,'6',0372,0366,0225,0316,0207,0205,022,0312,0215,'T',0264,':','.',0364,0230,021,0224,017,'D',0370,0221,0301,0206,'n',0323,'D',0300,013,'[','^',0332,0332,0366,0326,0327,0266,0266,0275,0265,0265,0355,0210,'j',02,'I',0260,'3','f','a',0253,0,0230,0302,'H',0314,0267,0327,0264,'G',0346,0367,01,0314,0265,'n','z',0223,0210,0306,'$',0342,'Z',0332,0366,0326,0327,0266,0266,0275,0265,0265,0355,0207,0247,0313,0202,'$','A',0304,0177,0301,0220,' ','@',0204,0304,0213,'P',')',01,'|',0267,0323,0263,0351,0331,0364,0354,0372,'v','}',';','>',0235,0237,'N',0317,0247,'g',0323,0263,0351,0331,0364,0354,0372,'v','}',';','>',0235,0237,'N',0317,0247,'g',0323,0263,0351,0331,0364,0354,0372,'v','}',';','>',0235,0237,'N',0317,0247,'g',0323,0263,0351,0331,0364,0354,0372,'v','L','H',0265,'B',020,'S',0307,0374,'*',02,'X','0',0216,'H',0327,0347,0246,0277,'=','2','f',0224,0134,0250,0205,'G','B','8',0244,'U',032,0374,0364,0327,0347,0246,0200,'{',0343,020,0246,'D','x','H','3',035,010,0212,0262,0374,0364,0327,0347,0246,'2',014,0307,'F',02,0257,'D','=',0361,0200,'C','"','2',0374,0364,0327,0347,0246,0204,'p','H',0242,0271,'s','J','.','E','B',0243,'_',0236,0232,0374,0364,0310,011,'`',0302,031,047,']',0266,0205,0367,0312,']','z',0243,0371,0375,0222,'@',0207,'=',0346,0365,'G','_','+','}',0266,0203,0256,0333,'B',0373,0345,'.',0275,'Q',0374,0376,0311,' ','C',0236,0363,'z',0243,0257,0225,0276,0333,'A',0327,'m',0241,'}',0362,0227,'^',0250,0376,0177,'d',0220,'!',0317,'y',0275,'Q',0327,0312,0337,'m',0240,0353,0266,0320,0276,0371,'K',0257,'T',0177,'?',0262,'H',020,0347,0274,0336,0250,0353,0345,'o',0266,0320,'u',0333,'h','_','|',0245,0327,0252,'?',0237,0331,'$',010,'s',0336,'o','T','u',0362,0267,0333,'h',':',0355,0264,'/',0276,'R',0353,0325,037,0317,0354,0222,04,'9',0357,'7',0252,':',0371,'[',0355,0264,035,'v',0332,027,0337,')','u',0352,0217,0347,0366,'I',02,034,0367,0233,0325,035,'|',0255,0366,0332,016,0273,'m',013,0357,0224,0272,0365,'G',0363,0373,'$',0201,016,'{',0315,0352,0216,0276,'V',0373,'m',07,'G',0377,0332,0,014,03,01,0,02,0,03,0,0,0,020,0222,'I','$',0222,'H','R',0363,0305,0344,0222,'I','$',0222,'I','$',0222,07,0277,0377,0,0377,0,0304,0222,'I','$',0222,'I','$',0212,0277,0374,0367,'/',0374,0222,'I','$',0222,'I','$',017,0372,014,0222,'o',0363,0222,'I','$',0222,'I','#',0277,'C','$',0222,'_',0376,0222,'I','$',0222,'I',0,0374,0311,'$',0222,0317,'8',022,'I','$',0222,'I','/',0222,'I','$',0231,'s',0207,'"','I','$',0222,'H',0270,'r','I','$',0257,0345,037,0362,'I','$',0222,'O','>',0222,'I','<',0334,0311,07,0367,0311,'$',0222,'I',0300,0222,'B',0277,0374,0310,'O',0376,0311,'$',0222,'C',0346,0244,'i',0372,'"','I','|','}',0371,'$',0222,'O',0377,0,0377,0,0376,0217,0222,'e',0323,'G',0271,'$',0222,'H',0377,0,0347,0324,'d',0223,037,'d',0213,0251,'$',0222,'H',0237,'2','I','$',017,'u',0244,0217,0211,'$',0222,'I',020,'B','I',')','?',0221,'$',035,'I','$',0222,'I','"',0370,0204,0177,0362,'Y','%',0377,0,'I','$',0222,'I','$',0377,0,0377,0,0374,0206,'I',07,0346,0311,'$',0207,0377,0,0377,0,0263,0311,0345,0377,0,0377,0,0347,0313,0377,0,0314,0236,0333,'m',0266,0333,'m',0266,0333,'m',0266,0333,'|',0236,0333,'m',0266,0333,'m',0266,0333,'m',0266,0333,'|',0203,'m',0266,0333,'m',0266,0333,'m',0266,0333,'m',0204,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'}',0234,'[','Y',036,0316,'K',0262,0217,'o','$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0222,';','t',0326,0351,035,0256,'M','n',0232,0327,'$',0377,0304,0,047,021,0,01,02,04,05,05,01,01,01,0,0,0,0,0,0,0,01,0,021,020,'!','1',0360,' ','A','Q',0241,0361,'0','a','q',0261,0301,0321,'@','`',0377,0332,0,010,01,03,01,01,'?',020,0352,0222,0323,'+',0273,'#',0220,021,'>','k',0274,0273,0210,06,0205,'i',020,' ',0207,037,0314,'@',034,0254,0244,0250,036,0203,0226,'4',0376,'P',0211,'!',011,0311,0211,'(',010,0212,0226,'@','5','@','y','.',0312,'(','d',0214,0260,0324,0177,020,01,0312,'$',0242,0221,0244,0241,'5',' ',0,0220,0302,'L','&','&','x',' ','A',016,'?',0200,0,0345,034,0334,0300,02,'K',04,0314,0324,06,0220,0307,0223,0301,0233,0353,0204,034,0242,033,0230,034,0330,'!',04,0272,0,016,0350,0227,'.','`',010,0352,'@',026,'.',020,0336,0352,0220,07,'(',0346,0346,04,'$',0,'a',0320,020,'9','D','7','0','r',0346,0220,0243,'P',0302,'L','h','z',0257,0226,'@',0306,0301,0,'X','t',03,0346,0210,'N','`','B','d',0,'a',0,04,0336,'2','c','Q',0323,'x','*',0260,0233,032,0234,'d',0200,034,0247,'e',031,013,0262,0,0260,0213,035,0310,0317,0220,'.',034,'t',0212,0210,'4',0214,'D',0201,'2',0204,0224,0312,0253,022,'M','B',0,03,010,0222,0,'r',0246,0330,'3','}','!',0220,0302,'l',0205,021,'N',021,025,'J','#','D','4','*',0201,0211,'M',0202,014,0306,'g',015,022,0220,'!',0260,'A',0233,'$',01,'$',0341,011,0341,0321,'z',010,0202,'L','z',024,0,0263,0220,0,03,014,'=',0201,026,0256,'k',017,035,011,0207,0244,'x','3',010,'-',02,'"',0262,'A',0326,'h',06,0220,0302,0,'r',0211,'(',0244,'{',0242,'-','a',0325,'|','t',0,0356,0350,0313,'&','(',0206,0346,0,022,'X','*',0312,0260,'Q','2',0205,'n',0230,'-','"',010,',','P','-','0',0246,0330,'I','i',0225,'D',0232,0256,0304,0353,05,0345,'0','1','a','X','U','1',016,0243,0322,0300,0205,'$','3',0202,0354,0242,'9',04,'M','$',0211,'T','b',01,'%',0202,0316,'P',0,014,'0',0,034,0242,023,0230,'g','z',0336,';',035,0,'#','f','R',0,'0',0200,';',0242,023,0230,'?','s','D',03,'H','c',':','b',0,0,07,'$',0232,0,'3','%','X',0277,025,0213,0361,'X',0277,025,0213,0361,'X',0277,025,0213,0361,'2',0255,'|','+','3',0342,0263,'>','+',0263,0342,07,0265,0331,014,0373,0336,0312,0331,'v','M','Z',0354,0254,'_',0212,0305,0370,0254,'_',0212,0305,0370,0254,'_',0211,0273,'_',';','"','b',0346,0323,0262,0263,'>','#',0214,0215,0232,' ','3',013,'^',0312,0305,0370,0254,'_',0212,0305,0370,0254,'_',0210,0351,0210,' ',0202,030,0202,'*',010,0310,0210,0330,0264,0377,0,'m',0213,0134,'l','Z',0177,0266,0305,0256,'/',0256,0344,'j',0260,011,'n',0362,0134,01,'8',02,'p',04,0340,011,0300,023,0200,047,0,'N',0,0234,01,'8',02,'p',04,0340,011,0300,023,0200,047,0,'N',0,0234,01,'8',02,'p',04,0340,011,0300,023,0200,047,0,'N',0,0234,01,'8',02,'p',04,0340,010,0372,0354,'G',0253,020,0207,0357,'?',0360,0243,'a',0256,'C',020,'M','<','.','i',0372,0271,0247,0352,'w','K',0270,0207,0360,'Z',014,0272,0313,'.','i',0372,0271,0247,0352,07,0301,0262,0,0202,0134,'>',0242,017,0307,'0','C',0346,03,'K',0312,0346,0237,0253,0232,'~',0240,'~','9',0200,033,'2',032,'~','"',017,0203,0344,'A','$','1','|','.','i',0372,0271,0247,0352,'u',0322,'Z',014,0351,'g',0,0376,'K','.','i',0372,0271,0247,0352,';',015,'p',030,02,'+',0347,035,013,0251,033,'V',0250,'n','G',0274,'N',0357,0361,0366,0374,'[',0273,0223,0356,026,0255,021,0251,'u','q',0320,0272,0221,0265,'j',0206,0344,'{',0304,0356,0377,0,037,'o',0305,0273,0271,'>',0341,'j',0321,032,0227,'W',035,013,0251,033,'V',0250,'n','G',0274,'N',0357,0361,0366,0374,'[',0273,0223,0356,026,0255,021,0251,'u','q',0320,0272,0221,0265,'j',0206,0344,'{',0304,0356,0377,0,037,'o',0305,0273,0271,'>',0341,'j',0321,032,0227,'W',035,013,0251,033,'V',0250,'n','G',0274,'N',0357,0361,0366,0374,'[',0273,0223,0356,026,0255,021,0251,'u','q',0320,0272,0221,0265,'j',0206,0344,'{',0304,0356,0377,0,037,'o',0305,0273,0271,'>',0341,'j',0321,032,0227,'W',035,013,0251,033,'V',0250,'n','G',0274,'N',0357,0361,0366,0374,'[',0273,0223,0356,026,0255,021,0251,'u','q',0320,0272,0221,0265,'j',0206,0344,'{',0304,0356,0377,0,037,'o',0305,0273,0271,'>',0341,'j',0321,032,0227,'W',07,0377,0304,0,'*',021,01,0,0,02,010,06,03,01,01,01,0,0,0,0,0,0,01,0,021,020,'!','1','A','Q','a',0221,0261,'q',0201,0241,0301,0321,0360,' ','0',0341,0361,'@','`',0377,0332,0,010,01,02,01,01,'?',020,0373,'C',022,0255,0201,'[',02,'H',035,'Z',023,'u',010,'&','j','e',' ',0357,0332,'$',0347,0316,'{',0214,'X',0313,0223,0304,'+','n',0223,0304,035,'.','H',0360,'D',0362,0277,0251,0301,0362,'s',0205,'R',0205,0243,0376,'b',0215,0310,0206,'e','/',0351,'[',0343,'X',0224,0227,05,0274,0333,'^','o',0320,'.',025,'s','3','=','U',0237,027,0374,0200,0254,0210,0221,0360,0253,0336,'7',0312,0370,0226,'8',0313,0273,'k',0316,0231,023,014,0355,0344,'Z',0362,0206,'f','s',0330,0356,0364,'"',0243,'<',022,'o','Y',0235,'!',0211,0362,'U','m','(',013,0312,0203,'B',0305,0250,036,'I',0336,0336,0264,0325,015,0367,013,0307,';','N','e',0337,0342,027,'0',0333,'7',02,010,'8',0335,0307,0253,0355,0341,'e','3',0205,'n',05,'k',0313,0314,0210,'E','.',0246,0253,0271,'V','c',011,030,0255,0355,'o',0306,0321,024,032,0323,'~','=',0216,015,0317,0267,'L',0203,'f','I',047,0227,0370,',',0372,'8',01,0335,0300,0355,'6','%',0203,0213,'z',0347,'C',0263,02,0325,0211,0255,'Y',0212,0336,'K',0270,0265,0344,'B','f',0232,0332,0266,0374,0326,'i',0342,'w','=',0265,0370,'M',03,0254,0253,0261,0354,0362,0373,0354,0220,'-','`','w','p',';','M',0211,'t',06,0253,0213,0237,0266,'Q','9','5',0266,027,0256,']',0333,0264,0211,0361,0220,0260,'X','y','s',0330,0253,0350,'7','d',0332,0313,03,'6',0355,'`',0362,0220,'$',031,'Q','=','s',037,'v',035,'U',0320,'T','L',021,0340,0333,026,'4',0332,'8',0227,'=',0234,0347,0366,0234,'S',0260,0367,'+',0340,0335,0275,0356,'/',0266,027,024,'[',0241,0330,0307,'7','(',']','8',0272,'d','e',0364,'X',0240,'-','n','?','[',0216,0323,'`',0221,0220,'j',0267,0256,'o',0345,0224,024,0356,0256,0254,0214,'|','g',0302,'&',0316,'q','W',')',0324,0271,0340,0363,0334,'h',0230,0225,0341,0231,'y',0334,0316,0253,0376,0322,'Q',0331,'b',0347,0267,032,',',0353,',','1','n',017,'l',0233,016,015,'n',0201,'p','e',0375,'k',0372,'&',015,'E',0270,0262,'1','z',035,' ',0344,0240,0352,0342,0342,0321,'j',0325,'c',027,0301,'|','&','s',0364,0322,0202,'Q','2','a','2',0227,'k','y','S','Q',0326,0211,0223,'y',0343,'.',037,'Z',023,'z',0276,027,0272,'A',0203,0220,'T','p',0241,0331,'.',014,0333,0337,031,'|',0315,0251,',',010,0222,'V',0270,',',0346,0226,0360,'*',0315,0262,01,04,0202,0211,0376,0263,0263,0271,0300,0364,0207,0223,0213,0246,'F','T',0251,'V',035,'Z',0266,0235,'6',0264,'Z','8','%',0236,034,0230,'*','$',031,'&','g',0324,0256,'-','%',0305,'C','i',0320,0346,0312,'I',034,'V','U','f','N','|',0276,'A',030,0255,0305,'l','H','_','"',0337,03,0235,'f',021,'U','~','-',0357,027,0265,0230,024,0363,0306,']',0344,0345,0256,020,0321,011,'j',0322,01,0315,'$',021,'_','C','j',0342,0266,0370,'2','>',022,0203,0251,0253,0261,0355,0246,'?','U','y','[','6',0211,0346,0205,'S','*',0211,';','&','~','N',034,'d',02,0360,0231,0251,'3',0254,'f',0240,0331,0241,0210,0245,0254,0241,'R','Q',0315,0354,'M',0211,'2',0235,'U',025,031,0227,0257,')','D',0260,0270,'-',0346,0332,0363,0246,0247,'r',0354,'^',05,0376,0316,'&','=',0330,'f',0335,0300,0346,0277,013,'j','!',0245,0370,06,017,'-',0370,025,'c','C',0177,'Q',0325,0270,'8',0376,0331,025,0236,012,'|','.','K','&',0315,'0',0240,'I',0230,'I',0213,0231,0354,'q','.','}',0341,0364,0336,'~',0254,0304,0274,0346,'B',0223,'0',0231,0364,'J','K',0212,0336,'E',0257,'"','&','R',0372,0234,0213,'5',0237,010,'l',0304,0275,0257,0340,012,0221,'l','T',07,0330,0233,0263,016,'6','B','$',0220,'C','O',0360,0363,'q',0361,0201,0305,0201,0223,'2',014,022,0343,0261,0347,0274,0350,02,0330,'t','3','z',047,'_',0252,0262,'6',016,034,0367,0343,0360,'P','&',0301,0323,0344,0231,0272,023,'b','b',';',0320,0325,0257,0244,'M',0220,031,'[',0253,'^',0222,0204,0314,0253,'j',0326,0374,'g',0227,0261,0233,0201,0233,022,0211,030,0367,034,'<',0333,0204,0250,'P','M',0262,021,0257,'R',0327,0325,0233,0322,0322,0134,'O',0214,0352,0331,0241,01,0236,016,0377,0,'P',0252,'d',021,0256,0347,0261,0347,0274,0350,'p',033,0203,'+',0236,'M','O',',','!',0264,'3',0371,0333,012,0235,0341,0300,0273,0213,0304,030,'3','.',0352,0361,'o',0241,0334,0260,0265,'a',0205,0245,'}',0277,0300,0313,0134,012,'P',0316,0371,0302,0343,'J',0371,0312,0211,'a','s','l','w',0372,0353,'9',',','L','K',0374,0231,0302,03,'0',0230,0300,'3','1','$',0360,'a',011,'e',0243,0210,0331,0341,0314,0370,0206,'%','[',02,0266,'$',0374,0362,0335,'<',0312,'$','9',0245,'[',0312,0343,0225,'y',0323,'h',0265,0301,'k',0313,014,0354,0211,'i',0310,'j',035,0361,'}',03,0340,0222,034,'|',0333,0216,0356,0134,'h','r',0362,012,0336,04,'=',0310,0265,'p',',',0375,0317,0354,0256,'z',0235,015,0347,';',0263,0343,'A',012,0233,04,0273,0311,0354,0340,'H','q',0234,0307,'I',';',0307,0364,'`','B',0250,'d','.',0360,0220,')','|','d','h','W',0326,'%',0301,0300,'n',0332,0363,0245,'q',02,0366,010,023,0257,027,'c',0273,0244,'!','R','^',0327,0360,0261,'`',0344,036,'[',0216,0320,'X','K',0322,'|','Z',016,0177,'[',0321,'q',0316,0327,'.','/',0332,0210,'I','$',020,0245,0307,025,0317,'=',0347,0363,0226,027,025,0274,0213,'^','Q','6',0235,'y',034,0217,')',0302,'&','>',0272,034,013,017,0215,0302,026,0366,030,0276,0260,'v','@','u','q','q','h',0264,0255,0221,0206,'o','b',0370,'N',0223,'Z',0327,027,0346,01,'I',04,0177,'h',0217,0355,021,0375,0242,'?',0264,'G',0366,0210,0376,0321,011,0324,'X','&','V','k',0314,0316,0,023,0332,0316,'=',0253,0274,'0',0134,0251,0275,'B','P',0214,0271,011,'w','H',0255,0201,0222,035,'C',0314,'O',0,'8',' ',0353,'9',0365,0204,'B','W',047,0230,0376,0321,037,0332,'#',0373,'D',0177,'h',0217,0355,020,0331,0304,04,0361,0256,0243,0257,010,'>','x',0260,'<',0321,0355,']',0342,'B','K','d',0202,034,'Q',0351,'o',010,032,015,'b',0314,0217,0355,021,0375,0242,'?',0264,'G',0366,0210,0,'$',0306,0236,0265,0267,0373,'z','V',0324,0365,0255,0277,0333,0322,0266,0245,0255,0242,'&',0244,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'g',032,0376,'F','q',0257,0344,'5',0264,0,0320,0377,0,0205,0233,'k',031,0215,'c','1',0254,'J',0261,'P',0262,026,'3',032,0306,'c','X',010,'2','~',047,'H',' ',0234,0331,'F','c','X',0314,'k',010,0202,'R','e','J','A',0262,0361,'8',0314,'k',031,0215,'`','f',015,023,0254,021,0230,0326,'3',032,0304,0333,'O',0236,0331,'O','N','m','E',0265,';',0355,0232,'}',014,0232,'}',014,0212,'v',0333,024,0331,'Q',0323,0273,'S',0266,0374,0366,0312,'z','s','j','-',0251,0337,'l',0323,0350,'d',0323,0350,'d','S',0266,0330,0246,0312,0216,0235,0332,0235,0267,0347,0266,'S',0323,0233,'Q','m','N',0373,'f',0237,'C','&',0237,'C','"',0235,0266,0305,'6','T','t',0356,0324,0355,0277,'=',0262,0236,0234,0332,0213,'j','w',0333,'4',0372,031,'4',0372,031,024,0355,0266,')',0262,0243,0247,'v',0247,'m',0371,0355,0224,0364,0346,0324,'[','S',0276,0331,0247,0320,0311,0247,0320,0310,0247,'m',0261,'M',0225,035,';',0265,';','o',0317,'l',0247,0247,'6',0242,0332,0235,0366,0315,'>',0206,'M','>',0206,'E',';','m',0212,'l',0250,0351,0335,0251,0333,'~','{','e','=','9',0265,026,0324,0357,0266,'i',0364,'2','i',0364,'2',')',0333,'l','S','e','G','N',0355,'N',0333,0363,0333,')',0351,0315,0250,0266,0247,'}',0263,'O',0241,0223,'O',0241,0221,'N',0333,'b',0233,'*',':','w','j','v',0337,0207,0377,0304,0,'(',020,01,01,0,01,03,03,04,03,0,02,03,0,0,0,0,0,01,021,'!',0,'1','A',020,'Q','a',' ','0','q',0201,'@',0221,0360,0241,0321,'`',0261,0301,0377,0332,0,010,01,01,0,01,'?',020,0367,'Q',0251,0311,0240,0252,0240,011,0335,0325,0263,0362,'x','e',0253,'p',027,'Z',0342,' ',0257,0204,0224,'3',0262,0364,0255,'y',0251,'K',0355,023,0306,0232,'W',022,'9',0317,0333,0326,015,0314,0240,0375,0232,'-','-',02,021,';','G',0372,'4','{','.',0320,'&',024,'(','L',0252,0324,0331,';',0343,'s','P',015,0221,0344,'F',0212,0210,0210,0203,0370,0325,'U','a','4',026,033,0341,013,0343,'E',0251,0253,0251,0334,'R','q',0302,047,0316,0251,0261,'Q','G',030,'a',0205,0215,0210,0366,'3','U','$','H',010,0260,'q',031,0275,0356,0300,0344,0210,0205,021,0331,037,0303,'C','B',',','1','U',0134,0,'s',0247,0361,'e','5','f',0310,0211,'M',0361,0230,0216,'f',0260,'i',0254,0200,'v','3',0300,03,0307,'R',0262,0305,030,0354,0354,0270,'r',0203,'F',025,'y','W','v','Q',0372,'-',015,'+',07,'S',0312,'E',0373,'Z','N','I','k',0373,'B','/',0255,'/',0134,0345,0317,0334,':','6',0233,'d','Y',0210,'N',0306,0341,'p','N',0263,02,0271,'8',0336,'J',0242,0361,'N',0177,011,'y',0304,0327,010,0246,0341,0246,0306,0306,'X',013,0246,0217,0312,' ','6',035,0334,0316,',',0302,016,0245,0325,0306,'(',0363,0221,'v',0375,06,0222,0254,0240,030,0331,'C',0266,0330,033,0352,'H',0250,'c',0314,0,0,'z','Z',0324,'(',0200,'^','v',')',017,'#',0250,0200,034,'^',0300,'N',021,0337,'f',0267,015,033,0371,'O',030,'X','8',015,021,0310,0211,0307,0340,'/',03,05,017,0223,';','j',0214,0330,025,05,0306,0255,0273,'V',0225,0261,0335,0312,0356,0253,0320,'R','q',0253,0370,02,0256,0236,'`',0262,'y',0347,0272,0317,',',0306,'P',0272,01,0363,026,'^',0301,0,'|','z',0302,'X',023,0220,'9','~','L',027,0373,'z',024,0344,'F',0270,032,027,'b','J','y','(',0367,0314,0323,010,'0','2',0256,'s',07,0207,01,'P','o',0302,011,0200,0370,'C','`',037,'-','U','u',024,020,05,036,0311,0216,'c',014,0241,0206,024,0207,0321,037,'G','}',0317,023,'p','R',0317,0261,0275,0263,'U','L','H',0216,'q','v',0250,034,0250,0240,'w',012,0371,017,'u','W',0240,'L','!',026,010,'A',0346,0215,0351,01,'z','6',0310,0361,'L',037,0220,017,0326,0216,'R',0254,'1','L',034,'P',0367,'d',0330,'N',0206,']',0203,0313,0,0345,06,0255,'s',0251,0222,0257,0234,0363,0310,'.','0',032,032,027,'P',0326,0354,'x',011,0366,'0',027,'A','c','E',03,010,'E',0313,'7',0343,0,0,036,0306,015,'p',0270,'M',0327,0316,'+',0202,0201,'R','b',0216,'Q',0203,0257,'j','L',017,0225,0252,0256,0207,'t',0210,0201,0213,'y',0303,';','v',0251,0240,0244,0222,01,'$','#','i','1','4',0231,0337,0361,06,'%',0360,047,0371,0367,0246,0333,0334,0255,'S',0303,'J','c','*',0354,0320,0200,'F',0216,'D',0367,022,'B',0225,0236,'$','F','n',05,0335,0311,'0','t',0241,025,0257,'9',0344,033,07,0355,'C','#','P',0206,'g',025,0357,'y','N','6',0,' ',07,0261,0346,'B','`',0230,026,0315,0220,0360,'l','`',0213,0373,'"',036,0360,027,'0','c','~','U',0350,0325,0273,0312,'@',0370,'I',0272,0271,0300,')',0316,'|','9',0331,'o','*',0253,0335,0350,0352,020,0326,'h',0213,'L',0300,'w',0300,0303,0255,0263,'a',0327,'8',0263,'`',0252,0255,013,0267,0333,037,' ','f','E','Q',0310,0323,0342,0352,0205,013,0362,024,'9','U','U',0363,0322,0261,030,0260,0203,011,05,'F','r',0340,'l',0372,0340,0377,0,'S',017,0313,0272,0360,031,'x',0326,012,'V',036,'n','G','2',037,'w',03,'.',0221,'x',0225,'u','P',0312,0252,0252,0357,0322,'m',06,0243,0204,0361,0134,0330,0276,'X','g','F',0363,0233,0243,0362,0344,0370,0,0,0,0353,0275,0343,'r',0321,035,0242,'K',0277,0207,0250,0243,'`','3',034,0355,0330,024,0300,0216,'4',0317,0352,0254,04,0237,0247,'n','=',0247,034,'@',0271,015,'x',0277,0344,'t',0330,'D','=',0235,0316,'#','[',0240,0,0,020,016,'=','(','S',01,013,0312,01,0254,'U','X',0334,0245,'(','I',015,0210,'4',0325,0313,'5','B','%','{',' ','3',05,01,'W','~',0253,0316,0207,0334,'x',0306,'o',0260,0330,0332,'a','z',025,0227,'*',0345,032,0252,0252,0252,0257,'^',')',0363,0212,0270,'9',']',0200,0312,0240,'o',0242,'F',0266,'7',0251,0363,0305,'N','Q',0317,0240,0200,0303,'C',013,0271,0273,0360,0263,0372,036,0322,'y',032,'<','`',0374,0377,0,0323,0241,0331,'Q','S','d',0330,'(',0205,'.',024,0272,0247,'Z','$','%',0246,'C','g','a',023,'"',0231,0320,0300,0214,':','C',0331,'(',020,0371,037,0341,0245,07,'<',0345,'9',0306,'|',0262,'q','t',011,0305,'B','C',0213,0205,0206,'`',0354,0316,'2',0372,0210,0312,010,017,05,0203,0,':',0212,'b',0344,0304,0261,0334,07,'+',0230,0312,0343,'K','R','D','H','3',0204,' ',0360,0314,010,022,0350,0,0,010,07,035,0134,0202,015,0,'U','W','`','4',026,033,'L',0212,036,0134,'w',013,0364,'h',017,010,'j',0376,'Y','.','Y',0314,0206,'P',0321,0265,'8','x',0315,011,'W','w',0262,0347,035,026,'-','Q',0222,0223,0344,0304,'M',0222,0216,0372,'%','x',0236,0234,'z',014,'2',024,0312,'9',0366,'s',')','_',0314,0221,'3',02,'S',0224,0234,0350,0206,0207,'q','d','~','N','D',0302,'"','a',0366,016,0313,0212,0253,0242,0225,0205,0215,0310,0320,0310,'f','J','>',030,0327,0310,017,017,'[',04,07,0251,0312,0231,'N','U','^','_','A',0346,0302,0346,0225,'F',0,'3',']','*',0346,'Y',0134,'o',0310,'w','s',0320,047,0225,0272,0352,01,0225,'T',0,0337,'U',0310,0312,0213,'t',014,'[',026,'a',01,'P','*',025,0310,'U','D','D',0344,'M',031,0235,0302,0245,0262,'3',0225,0311,0312,0364,'&',0224,0361,0304,'8',0363,'+','}',0250,0342,'v',0206,0274,'L',0337,02,'x',0266,'z','&',01,'D',0,0252,0352,0264,'`',026,'|','Z','Y',0357,0262,037,0301,0273,0321,0323,02,0263,'G','i','Q','x',']',030,034,026,'F',0,'@','z','j','s',06,0322,0254,'[',01,0300,'{',0260,0316,0261,'P',0230,0342,'p',0344,'{',0201,0216,'h',023,'O',0344,'@',0252,0235,0200,0321,05,'@','M',0271,0216,0360,'8','8',0365,037,'#',0212,'U',037,0207,0364,0235,025,'t','!',0357,037,'h',010,013,026,025,0,0356,'"',0223,'O',034,0257,'(',0262,0347,0204,0345,'S',0265,06,0222,'w',014,'(',0305,',','D','m','^','u','8',034,0330,0225,0372,036,0264,0134,0345,0300,015,0325,'v','4','T',0272,0252,0316,'d',022,0313,0271,'0',0211,'I',0246,0252,'m','|','k','}',0,'9','j',0257,'A','J',0265,013,0354,014,0256,0231,'$',017,'K',0366,'T',0247,0234,0274,0205,0352,0333,'D',0345,'+',047,0211,'c',0270,016,'E','<',0364,'D',0343,0215,0300,0202,'w',031,0177,0337,0333,'H','1',0234,'S','4',0263,'j',0313,0222,'d',035,020,'*','Z',';',022,'c','s','s',016,0346,0221,'X',0373,017,'-',0334,'A','>','4','P',0213,036,'B','X','V',012,'x',0211,0270,0372,'^',0243,011,'`',0252,0240,017,0227,'S','x','P',0363,0246,0312,0357,0340,'1',0311,0244,':','/',0300,'c','/',0333,'N',0301,0325,0352,0356,'>',011,0231,0240,0347,06,0256,06,'2','U','Z','8',035,0335,'/',0332,0254,'S',0,0352,'Y','%',035,0364,0134,0333,'&',0336,'|',027,'V','P',0376,0230,01,0312,0250,07,0235,06,05,'W','H',0327,02,024,'d',0276,0342,011,'|',0214,0207,'0','y',0305,0374,0230,037,'B','2',0222,'5',024,023,047,'@','.',0352,'&','4',0370,0,'A','o','4',0357,0330,0321,0376,012,013,0376,0372,06,'H',0305,' ',0357,')','|','S',0347,'W','y','N',05,0250,0242,'.','r','o','c','9',0322,0272,0211,0214,';',0331,0207,0300,016,0267,035,0276,'7',0200,'_',0365,0254,07,02,0307,'a',07,'A',0270,0321,0333,0261,0250,036,'a','{',0206,033,0256,0352,0345,'r',0276,0202,024,0324,0222,0343,016,'j',036,'M',0214,0272,'U',035,0332,0256,0300,'p',0,034,0,'t','V','B',012,'@',0251,'.','r',013,0233,'w',0367,'a',0364,'l',014,'@',';',0210,0246,0255,'I',032,0344,0345,'7','f',0271,'O','X','T',030,'X',024,0275,0213,0312,015,'&',0217,010,'1',06,0242,0266,0214,'x','&',0245,0134,'X',' ',0362,'9',0260,0260,0270,017,'J','o','~','d','Z',014,'r','m',0314,'!',0312,'p',0377,0,'2','?',0204,0272,03,0374,0252,0272,0201,0206,01,016,'6',0357,023,0260,'n',0350,'%',0334,':',0200,0200,0354,07,0254,0350,05,0302,0225,'L',0,'*',0270,03,0326,'<','x',0361,0343,0307,0330,0306,0340,'X',0301,'x',0367,0304,0335,0303,'N',0376,0355,'a',030,0312,03,0310,0243,0306,0277,0244,0377,0,0315,'l','8',0303,037,'#','~',0303,'@',',',031,024,0235,0347,0373,0232,0303,0262,'*','/',0300,0177,'*',0370,0322,0327,05,0270,0336,0352,0303,0212,0377,0,'y',0320,0202,0261,0272,'6',0,03,0343,0324,'<','x',0361,0343,0331,0266,037,'>',0312,'l','Y',0205,0305,03,0244,0203,0300,'[',0356,0246,'W','_',0322,0177,0346,0221,0240,0236,0377,0,020,0212,0316,'d','y','c','D',0345,'X',0270,'7','F',0321,'T',0252,0252,0265,0364,0217,036,'<','y',0320,013,0205,'(',0230,'A',021,'0',0217,0374,015,'2','d',0311,0231,0322,0211,0270,0204,0214,'(',0254,0374,0325,0353,0327,0257,'^',0275,'z',0365,0353,0327,0257,'^',0275,'z',0365,0353,0327,0257,'^',0275,'z',0365,0353,0327,0257,'g','Z','&',0342,022,024,0252,'3',0376,013,'N',')',0374,012,0312,'[','N',0254,'X',0233,0240,'+',0241,034,0230,0262,0313,0322,0233,',',0376,'`','Y','~',0272,0261,'b',0217,034,'T',0303,0240,'-',021,0367,0324,0235,0365,'#',034,0262,'8',0310,0373,0352,0305,0213,';',0352,'F',031,'`','1',0201,0365,0325,036,'8',0211,0207,022,'H',03,0353,0253,026,'0',0331,'g',0367,0,0313,0367,0320,0335,021,'M',012,0344,0314,0262,'^',0254,'X',0303,0212,0177,02,'2',06,0367,0334,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0360,'i',0324,0251,'O',0371,0375,0376,0375,'=','Z',0251,0377,0,'?',0267,0331,0247,'S',0377,0331,}; diff --git a/src/embedded_images/shred_db.jpg.h b/src/embedded_images/shred_db.jpg.h new file mode 100644 index 0000000..28fa222 --- /dev/null +++ b/src/embedded_images/shred_db.jpg.h @@ -0,0 +1,16 @@ +/* Autogenerated by hxtools bin2c */ +#ifndef SHRED_DB_JPG_H +#define SHRED_DB_JPG_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern const unsigned char bin2c_shred_db_jpg[27063]; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* SHRED_DB_JPG_H */ diff --git a/src/embedded_images/tick_erased.jpg b/src/embedded_images/tick_erased.jpg Binary files differnew file mode 100644 index 0000000..3710146 --- /dev/null +++ b/src/embedded_images/tick_erased.jpg diff --git a/src/embedded_images/tick_erased.jpg.c b/src/embedded_images/tick_erased.jpg.c new file mode 100644 index 0000000..6bbfc2a --- /dev/null +++ b/src/embedded_images/tick_erased.jpg.c @@ -0,0 +1,4 @@ +/* Autogenerated by hxtools bin2c */ +#include "tick_erased.jpg.h" +/* Autogenerated from te.jpg */ +const unsigned char bin2c_te_jpg[54896] = {0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,02,0,'v',0,'v',0,0,0377,0341,047,'6','E','x','i','f',0,0,'I','I','*',0,010,0,0,0,07,0,022,01,03,0,01,0,0,0,01,0,0,0,032,01,05,0,01,0,0,0,'b',0,0,0,033,01,05,0,01,0,0,0,'j',0,0,0,'(',01,03,0,01,0,0,0,03,0,0,0,'1',01,02,0,015,0,0,0,'r',0,0,0,'2',01,02,0,024,0,0,0,0200,0,0,0,'i',0207,04,0,01,0,0,0,0224,0,0,0,0246,0,0,0,'O',02,0,0,05,0,0,0,'O',02,0,0,05,0,0,0,'G','I','M','P',' ','2','.','1','0','.','3','0',0,0,'2','0','2','3',':','0','2',':','1','2',' ','2','0',':','5','9',':','4','7',0,01,0,01,0240,03,0,01,0,0,0,01,0,0,0,0,0,0,0,011,0,0376,0,04,0,01,0,0,0,01,0,0,0,0,01,04,0,01,0,0,0,0367,0,0,0,01,01,04,0,01,0,0,0,0,01,0,0,02,01,03,0,03,0,0,0,030,01,0,0,03,01,03,0,01,0,0,0,06,0,0,0,06,01,03,0,01,0,0,0,06,0,0,0,025,01,03,0,01,0,0,0,03,0,0,0,01,02,04,0,01,0,0,0,036,01,0,0,02,02,04,0,01,0,0,0,017,'&',0,0,0,0,0,0,010,0,010,0,010,0,0377,0330,0377,0340,0,020,'J','F','I','F',0,01,01,0,0,01,0,01,0,0,0377,0333,0,'C',0,010,06,06,07,06,05,010,07,07,07,011,011,010,012,014,024,015,014,013,013,014,031,022,023,017,024,035,032,037,036,035,032,034,034,' ','$','.',047,' ','"',',','#',034,034,'(','7',')',',','0','1','4','4','4',037,047,'9','=','8','2','<','.','3','4','2',0377,0333,0,'C',01,011,011,011,014,013,014,030,015,015,030,'2','!',034,'!','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2',0377,0300,0,021,010,01,0,0,0367,03,01,'"',0,02,021,01,03,021,01,0377,0304,0,037,0,0,01,05,01,01,01,01,01,01,0,0,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,020,0,02,01,03,03,02,04,03,05,05,04,04,0,0,01,'}',01,02,03,0,04,021,05,022,'!','1','A',06,023,'Q','a',07,'"','q',024,'2',0201,0221,0241,010,'#','B',0261,0301,025,'R',0321,0360,'$','3','b','r',0202,011,012,026,027,030,031,032,'%','&',047,'(',')','*','4','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0341,0342,0343,0344,0345,0346,0347,0350,0351,0352,0361,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0304,0,037,01,0,03,01,01,01,01,01,01,01,01,01,0,0,0,0,0,0,01,02,03,04,05,06,07,010,011,012,013,0377,0304,0,0265,021,0,02,01,02,04,04,03,04,07,05,04,04,0,01,02,'w',0,01,02,03,021,04,05,'!','1',06,022,'A','Q',07,'a','q',023,'"','2',0201,010,024,'B',0221,0241,0261,0301,011,'#','3','R',0360,025,'b','r',0321,012,026,'$','4',0341,'%',0361,027,030,031,032,'&',047,'(',')','*','5','6','7','8','9',':','C','D','E','F','G','H','I','J','S','T','U','V','W','X','Y','Z','c','d','e','f','g','h','i','j','s','t','u','v','w','x','y','z',0202,0203,0204,0205,0206,0207,0210,0211,0212,0222,0223,0224,0225,0226,0227,0230,0231,0232,0242,0243,0244,0245,0246,0247,0250,0251,0252,0262,0263,0264,0265,0266,0267,0270,0271,0272,0302,0303,0304,0305,0306,0307,0310,0311,0312,0322,0323,0324,0325,0326,0327,0330,0331,0332,0342,0343,0344,0345,0346,0347,0350,0351,0352,0362,0363,0364,0365,0366,0367,0370,0371,0372,0377,0332,0,014,03,01,0,02,021,03,021,0,'?',0,0367,'{',037,0371,07,0333,0177,0327,'%',0376,'B',0254,'U','{',037,0371,07,0333,0177,0327,'%',0376,'B',0254,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,0322,0271,0235,'_',0305,0366,0366,'N',0320,'Z','(',0236,'Q',0301,'l',0374,0252,0177,0255,'e',0370,0257,0304,0340,0371,0226,'v',0262,0204,0205,'?',0326,0312,017,0336,0366,07,0322,0274,0306,0377,0,']','w','c',035,0257,0312,0237,0337,0356,'k',012,0370,0210,'Q','W',0233,'"','s','P','Z',0235,0226,0243,0342,0253,0351,0201,'7',027,0376,'J',0177,'u',033,'`',0375,'9','5',0316,0313,0257,0331,0206,047,'|',0222,'1','9','$','/','S',0370,0327,'.',0356,0322,'1','g','b',0314,'{',0223,'M',0257,'.',0246,'i','6',0375,0305,'c',0232,'X',0211,'t',':','3',0342,'(',07,'H','d','?',0210,0245,'_',021,'[',0223,0363,'E',' ',0374,0215,'s','t',0370,0242,'y',0345,'X',0343,031,'f','8',025,0222,0314,'1',015,0331,'~','D',0373,'y',0236,0203,0244,'k','3','Y',0272,0335,'Y','K',0362,0260,0344,'v','o',0250,0242,0247,0360,0256,0201,0366,0331,0243,0264,'$',0371,'1','!','2','8',0365,0366,0374,'h',0257,'z','7',0345,0134,0333,0235,0252,0366,0324,0364,0373,037,0371,07,0333,0177,0327,'%',0376,'B',0254,'U','{',037,0371,07,0333,0177,0327,'%',0376,'B',0254,'U',014,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0231,'4',0321,'[',0304,0322,0315,'"','G',032,0214,0263,0273,'`',01,0356,'h',01,0364,'W',0222,0370,0253,0343,0347,0207,'4','g',0222,0333,'G','V',0325,0256,027,0202,0361,0374,0260,0203,0376,0361,0373,0337,'Q',0305,'x',0227,0211,0376,'-','x',0273,0304,0354,0351,'6',0244,0366,'v',0215,0377,0,'.',0366,'d',0306,0270,0367,'#',0223,0371,0343,0332,0200,'>',0247,0326,0374,'q',0341,0257,017,'d','j','z',0305,0254,'2',017,0371,'g',0274,'3',0376,'B',0274,0347,'W',0375,0243,'<','?','k',0271,'4',0275,'6',0362,0371,0200,0312,0263,'b','$',047,0323,047,0221,0371,'W',0314,0324,'P',07,0262,'j','?',0264,'o',0211,0247,0227,0376,'%',0372,'f',0233,'i',026,':','H',036,'V',0317,0327,' ','c',0247,'j',0346,'n','>','4',0374,'@',0270,0220,0261,0327,0332,'1',0222,'B',0307,'m',012,0201,0236,0337,'s',047,0361,0315,'p','4','P',07,'c','q',0361,'W',0307,'W',',',0246,'O',023,'^',0202,06,07,0226,'V','?',0375,04,014,0324,0220,0374,0134,0361,0344,021,0210,0323,0304,0227,'E','G','w','D','s',0371,0225,'&',0270,0252,'(',03,0321,0254,'>','9','x',0366,0312,'M',0322,'j',0261,'^','&',0322,'<',0273,0213,'X',0361,0365,0312,0205,'9',0374,'k',0251,0322,0377,0,'i','-','b',',','.',0255,0241,0331,0134,015,0334,0275,0263,0264,'D','/',0320,0356,0311,0353,0334,'W',0210,'Q','@',037,'U','h',0337,037,0274,'#',0251,'8',0216,0354,']','i',0316,'N','?','~',0200,0257,0346,0244,0340,'}','k',0320,0364,0237,020,'i',032,0354,'>','n',0227,0251,'[',']',0256,01,0375,0324,0200,0220,017,0250,0352,'+',0341,'*',0226,0336,0346,'{',';',0204,0270,0266,0232,'H',047,0214,0345,'$',0211,0312,0262,0237,'P','G','"',0200,'>',0372,0242,0276,'R',0360,0247,0307,'_',024,'h','^','U',0276,0245,' ',0325,0254,0327,03,0367,0377,0,0353,'@',0377,0,0177,0277,0374,013,'$',0372,0327,0270,0370,'C',0342,0347,0205,0274,0134,0311,'o',025,0327,0330,0257,0333,0245,0255,0321,012,'X',0372,')',0350,0337,'A',0315,0,'w',0225,0311,'x',0263,0304,'B',0332,'7',0260,0265,0223,022,0221,0211,0134,0177,010,0364,0317,0255,'_',0361,'&',0276,0272,'U',0267,0223,011,06,0352,'A',0362,0377,0,0262,'=','k',0306,'u',0315,'U',0244,'w',0267,0215,0311,'$',0376,0361,0363,0324,0372,'V','5',0353,'F',0214,'9',0244,'D',0346,0240,0256,0312,0272,0266,0246,'n',0344,0362,0242,047,0311,'S',0377,0,'}',032,0313,0242,0212,0371,0252,0265,'e','V','N','r','8','%',047,047,'v',024,'Q','E','f','H',01,0223,0201,0326,0272,0337,017,'h',0222,0231,'c','U','M',0327,'S','p',0253,0375,0321,'Y',0372,'&',0226,'X',0255,0314,0253,0237,0371,0346,0270,0353,0357,'^',0311,0341,'}',04,'i',0266,0302,0346,0341,0177,0322,0245,035,'?',0270,0276,0237,'Z',0366,0260,030,'N','_',0336,0317,'~',0207,']',012,'_','i',0232,032,'6',0225,036,0221,'`',0260,'!',0334,0347,0346,0221,0375,'M',025,0243,'E','z',0247,'I','^',0307,0376,'A',0366,0337,0365,0311,0177,0220,0253,025,'^',0307,0376,'A',0366,0337,0365,0311,0177,0220,0253,024,0,'Q','E',024,0,'Q','H','H','U',',',0304,0,'9','$',0366,0257,012,0370,0241,0361,0275,'l',0332,'}',017,0302,0262,',',0223,0355,')','6',0240,017,021,0237,0356,0247,0251,0367,0355,0357,0330,03,0276,0361,0347,0305,015,027,0300,0266,0245,'f','&',0357,'Q','`','|',0253,'H',0230,'d',0237,0366,0217,0360,0217,0314,0373,'W',0315,036,'3',0370,0225,0342,037,032,0312,0351,'}','r','a',0261,'-',0225,0263,0204,0341,06,':','g',0373,0337,0215,'r',0227,'7','3',0336,0134,0311,'q','s','+',0315,'4',0207,'s',0310,0355,0222,0307,0334,0324,'T',0,'Q','E','w',0236,016,0370,'I',0342,'o',027,0254,'w',021,0333,0375,0213,'O','~','E',0325,0310,' ','0',0365,'U',0352,0337,0312,0200,'8',':',0265,'e',0246,0337,'j','R',030,0354,',',0256,'.',0234,'r','V',010,0231,0310,0374,0,0257,0247,0274,'7',0360,017,0302,0332,'C','G','>',0251,0346,0352,0267,012,'>',0354,0247,'l','Y',0377,0,'t','u',0374,'N','=',0253,0323,'l',0264,0333,035,'6',05,0202,0306,0316,0336,0332,'$',030,'T',0206,'0',0200,017,0240,0240,017,0222,'4',0337,0203,'>','8',0324,0227,'p',0322,'~',0316,'3',0200,'n','$',013,0237,0347,']',035,0277,0354,0347,0342,0231,'T',031,0265,015,'6',03,0214,0341,0235,0233,0237,'N',026,0276,0236,0242,0200,'>','u',0217,0366,'i',0277,'1',0251,0223,0304,0266,0312,0370,0371,0225,'m','Y',0200,'>',0307,'p',0317,0344,')',0227,037,0263,'V',0252,0250,015,0257,0210,0254,0344,'|',0362,'%',0201,0220,'c',0352,013,'W',0321,0264,'P',07,0313,'w',0277,0263,0317,0213,0355,0324,0233,'y',0364,0373,0242,016,'0',0262,0225,0343,0327,0221,0134,0246,0253,0360,0267,0306,'z','F',0363,'q',0241,0134,'I',032,0214,0357,0200,011,01,0372,01,0317,0177,'J',0373,'>',0212,0,0370,012,'H',0336,031,'^',')','Q',0222,'D','b',0254,0214,'0','T',0216,0240,0216,0306,0233,'_','r',0353,0236,022,0360,0377,0,0211,'-',0314,':',0276,0223,'k','t',0244,'`','3','&',035,'~',0214,'0','G',0340,'k',0312,'|','I',0373,':','i',0227,01,0345,0360,0366,0241,'-',0243,0366,0202,0340,0371,0211,0371,0365,0240,017,0234,'+','s',0302,0376,035,0272,0361,016,0250,0221,'C',0230,0341,0215,0203,'K','7',0367,07,0267,0275,'_',0325,'>',034,0370,0237,'E',0326,0342,0322,0357,0264,0331,021,0246,'m',0261,0316,0240,0264,',','=','C',0364,0350,011,0307,'_','j',0364,0375,';','O',0264,0360,0216,0204,0226,0320,0200,0322,0177,023,036,0262,'?',0257,0322,0246,'R','P',0213,0224,0266,'B','m','%','v','Y',0325,'5',03,'c','j',0226,0311,',',0222,'M',0260,'.',0371,034,0263,0,';',0222,'{',0327,'2','I',047,047,0255,'>','Y','^','i','Z','I',033,',',0307,'$',0323,'+',0346,0361,'X',0207,'^','w',0351,0320,0340,0251,'7','7','p',0242,0212,'+',0230,0314,'+','O','I',0323,'M',0334,0276,'d',0203,0367,'*','y',0377,0,'h',0372,'U','k',033,047,0275,0270,021,0257,012,'9','f',0364,025,0351,'^',026,0360,0352,0337,0314,0252,'P',0255,0224,'8',0335,0217,0342,'>',0225,0350,0340,'p',0236,0321,0373,'I',0354,0277,023,'z','4',0371,0235,0336,0306,0277,0204,'<','>',033,'n',0243,'r',0237,'"',0377,0,0251,'B',':',0377,0,0265,']',0275,'"',0252,0242,04,'P',02,0201,0200,07,'j','Z',0367,0216,0320,0242,0212,'(',02,0275,0217,0374,0203,0355,0277,0353,0222,0377,0,'!','V','*',0275,0217,0374,0203,0355,0277,0353,0222,0377,0,'!','V','(',0,0244,'$','(','$',0220,0,0344,0223,'K','^',015,0361,0277,0342,'{','[','y',0236,025,0321,'.','1',')',030,0275,0236,'6',' ',0247,0375,'3',037,'^',0364,01,0227,0361,'{',0342,0374,0367,'w','7','>',034,0360,0355,0302,'-',0220,06,';',0253,0250,0311,0335,'!',0356,0252,'{',016,0240,0372,0327,0206,0321,'E',0,025,0273,0341,0177,07,0353,'^','0',0324,'V',0313,'H',0264,'2',034,0374,0362,0266,'D','q',0217,'V','n',0325,0323,0374,'8',0370,'Q',0251,0370,0336,0346,'+',0273,0214,0332,'h',0312,0337,0274,0234,0217,0232,'@','?',0205,07,0277,0257,'j',0372,0247,'C',0320,'t',0317,016,'i',0261,0351,0372,'U',0244,'v',0366,0350,':',' ',0301,'c',0352,'O','s','@',034,'7',0201,0376,014,'h',036,025,0215,'.','o',0243,'M','O','R',0340,0231,'f',0134,0242,037,0366,'T',0373,0367,'<',0327,0245,0200,0,0,014,01,'E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'R','3','*',')','f',' ','(',031,'$',0366,0245,0256,'3',0305,0372,0366,'3',0246,0333,'?',0375,'v','p',0177,0361,0332,0,0305,0361,'O',0210,0205,0374,0315,0206,0333,'g',016,'v',0377,0,0264,'}','O',0364,0257,'?',0271,0212,0357,'T','V',0273,013,0362,03,0204,'N',0370,0245,0326,'u',023,'q',')',0202,'3',0373,0244,'<',0237,0357,032,0237,'E',0232,0345,0224,0241,0301,0201,';',0236,0337,'J',0371,0334,0327,031,047,0356,'S',0331,'o',0346,'x',0371,0246,'*',0245,':','N','T',0255,0247,'~',0246,031,05,'I',04,020,'G','c','I',']','5',0305,0225,0256,0242,0205,0343,'e',0337,0375,0365,0376,0265,0203,'u','g','5',0243,0355,0221,'x',0354,0303,0241,0257,'6',0235,'e','=',':',0234,0330,0134,'}','<','G',0273,0264,0273,'2',0275,'>',030,'^','y','V','8',0306,'Y',0216,05,'0',014,0234,016,0265,0322,0351,0366,0221,'i','v','o','w','t','B',0260,']',0314,0315,0374,013,']',0330,0134,';',0257,';','t',0352,'z','4',0340,0346,0354,'l',0370,'w','A','y',0346,0216,0316,0334,'|',0315,0314,0222,'z',016,0346,0275,'r',0306,0312,035,'>',0316,';','h',027,010,0203,0361,047,0324,0327,01,0360,0227,0305,0232,'7',0211,'4',0353,0304,0263,'V',0216,0372,011,'H',0225,'_',0253,0246,'~','V','_','l','v',0365,0315,'z','=','}','$','b',0242,0224,'c',0261,0336,0222,'J',0310,'(',0242,0212,0241,0205,024,'Q','@',025,0354,0177,0344,037,'m',0377,0,0134,0227,0371,012,0261,'U',0354,0177,0344,037,'m',0377,0,0134,0227,0371,012,'u',0335,0324,'6','6','s',']','N',0341,'"',0205,013,0273,036,0300,012,0,0341,0276,',','x',0361,'|',025,0341,0206,0373,'4',0200,'j','w',0200,0307,'l',07,'%','8',0345,0361,0355,0374,0353,0344,031,'$','y','d','i','$','v','w','r','Y',0231,0216,'I',047,0251,'&',0272,'?',036,'x',0252,0177,031,'x',0272,0363,'V',0221,0211,0211,0217,0227,'n',0204,'}',0310,0206,'v',0217,0324,0237,0251,'5',0315,'P',01,'^',0217,0360,0247,0341,0224,0236,'9',0324,'Z',0352,0370,'K',026,0217,'n',0300,'H',0353,0307,0232,0337,0334,07,0371,0237,'z',0347,'<',015,0341,013,0257,032,0370,0232,015,'*',0337,')',027,0337,0236,'P','?',0325,0306,':',0237,0257,0245,'}',0231,0242,0350,0326,'>',037,0322,'-',0364,0315,':',05,0206,0332,05,0332,0252,0243,031,'=',0311,0367,047,0232,0,0261,'e','e','m',0247,'Y','C','g','g',02,'A','o',012,0204,0216,'4',030,012,05,'O','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E','A','y','w',025,0215,0244,0227,'3',034,'"',014,0237,0177,'j',0,0314,0361,'&',0264,'4',0233,022,'#',' ',0334,0313,0304,'c',0323,0324,0327,0217,'k',0232,0233,'F',0255,022,0271,'3','I',0313,'1','<',0201,0376,'5',0261,0342,035,'q',0347,0226,'[',0353,0203,0363,'1',0304,'q',0347,0240,0354,05,'p','r',0312,0363,'J',0322,'9',0313,'1',0311,'5',0347,'c',0361,'^',0316,'<',0221,0335,0230,'V',0251,0312,0271,'V',0343,'+',0241,0322,012,'M',0246,0274,031,0303,'r',016,':',0363,'Q','Y',0330,0333,'[','[',',',0367,0200,026,'~',0212,'F','z',0373,'T',0267,'v',0361,0333,0315,021,0264,0375,0325,0303,0234,0,':',021,0356,'+',0345,0252,0324,'S',0367,'W',0336,'|',0306,'3',023,'O',021,0373,0210,0335,';',0350,0372,']','~',0204,'6','z','m',0335,0255,0360,'!',0361,020,'<',0220,'z',0217,0245,'C',0254,'_',031,0244,'6',0352,'0',0250,'y','>',0246,0237,'>',0257,'y',016,0350,'^','5','I',07,04,0325,'m','6',0305,0257,0356,'K','>','|',0265,'9','s',0353,0355,'[','a',0350,'N',0265,'E','}',0372,033,0341,'0',0265,0252,0326,'U',0253,0245,'t',0264,0267,0346,0134,0321,'4',0355,0344,']',0314,0277,'(',0373,0200,0367,'>',0265,0304,'|','E',0361,'Y',0274,0234,0350,0366,'R',0376,0342,'3',0373,0366,'S',0367,0333,0373,0277,'A','^',0302,'<',')',0251,'k',0336,034,0324,'S','K',0231,'m','f',020,0224,0267,'v',034,027,0364,0366,0343,0214,0366,0315,'|',0307,'y','i','q','a','y','5',0245,0334,'M',025,0304,'.','R','H',0334,'r',0244,'u',025,0365,0324,'(','F',0214,'9','Q',0364,0220,0202,0202,0262,'5','|',')',0342,'{',0377,0,010,0370,0202,0333,'V',0260,'o',0236,'&',0371,0343,047,013,'*','w','S',0365,0257,0263,0274,'5',0342,013,'/',024,0370,'~',0323,'X',0260,'b','a',0270,'@',0333,'N','7','#','w','S',0216,0340,0361,'_',013,'W',0260,0374,011,0361,0347,0366,'&',0272,'<',';',0177,'6',0333,033,0367,0304,014,0307,0210,0346,'8',0,'{',06,0351,0365,0307,0255,'l','Y',0364,0365,024,'Q','@',05,024,'Q','@',025,0354,0177,0344,037,'m',0377,0,0134,0227,0371,012,0361,0257,0332,033,0305,0362,0351,0372,'E',0247,0206,0255,033,017,'}',0231,'n',0230,'6',012,0306,0244,'a','q',0376,0321,0316,'}',0227,034,0346,0275,0216,0321,0326,'=','.',011,034,0200,0253,012,0222,'O','a',0266,0276,'2',0370,0205,0342,'F',0361,'W',0215,0265,035,'H','I',0276,03,047,0227,07,0240,0215,'x',030,0372,0365,0374,'h',03,0227,0247,'G',033,0313,'"',0307,032,0226,'w','!','U','G','r','i',0265,0351,0277,04,'|',032,'|','K',0343,'$',0277,0271,'B','t',0375,'0',0211,0237,'#',0207,0223,0370,027,0363,0344,0375,'=',0350,03,0334,0276,022,'x',026,'?',06,'x','R','6',0270,0211,'F',0253,'z',04,0227,'O',0216,'@',0376,024,0372,0,0177,'<',0327,0240,'Q','E',0,024,'Q','E',0,024,'Q','E',0,024,'Q','E',0,024,'Q','E',0,024,'Q','E',0,025,0347,'~','.',0327,05,0345,0323,'[','D',0370,0265,0200,0374,0315,0236,031,0273,0237,0240,0256,0217,0305,'Z',0327,0366,'u',0227,0331,0241,'o',0364,0231,0306,06,'?',0205,'{',0232,0361,0315,'w','Q',0311,'6',0261,'7',0375,'t','?',0322,0261,0257,'Z','4','`',0346,0310,0234,0324,'U',0331,0235,0251,'_',033,0353,0222,0303,'"','5',0341,07,0365,0252,0253,034,0205,014,0201,030,0242,0236,'N','8',0245,0202,'#','<',0351,020,0352,0307,025,0321,'J',0216,0252,0226,'6',0251,0265,'v',0374,0362,021,0300,037,0343,'_',')','_',020,0334,0357,'-',0331,0341,0342,0361,0236,0312,'j',';',0267,0253,0362,']',0311,0342,0362,'n',0342,0206,'a',0363,'l',031,'_','c','U',0322,06,0212,0346,'K',0353,0307,'Q',0264,'|',0240,036,024,'T','o',0247,0275,0215,0273,0313,'k','<',0201,0224,'d',0203,0202,017,0341,'X',0323,0336,0134,']',0220,0262,'H','[',0321,'G',02,0270,0351,0323,0347,'o',0225,0351,0370,0236,'>',027,012,0353,'9',':','3',0367,036,0236,'i','o','e',0352,'=',0274,0315,'O','P',';',07,'.','x',0366,025,0335,'x','w','B','7','s',0305,'e',0,0333,032,0363,'#',0372,016,0347,0353,'Y',':',036,0222,0361,04,'E','M',0327,'3',020,'1',0375,'+',0327,0364,'-',036,'=',036,0300,'F',0,'3','?',0315,'+',0372,0237,'O',0240,0257,0256,0300,'a',025,030,']',0356,0317,0257,0303,0321,'T',0342,0222,'/','Z',0332,0305,'g','m',035,0274,013,0266,'4',030,02,0274,017,0366,0203,0360,'8',0214,'E',0342,0353,'(',0270,',','!',0275,03,0266,'x','G',0374,0370,0374,'E','}',05,'U','u','=','>',0337,'V',0323,'.','t',0373,0270,0326,'K','{',0210,0332,'7','V',031,04,021,0212,0357,':',017,0202,0251,0360,0315,'%',0274,0361,0315,023,025,0222,'6',016,0254,';',020,'r',015,'j','x',0247,'B',0227,0303,'^','&',0277,0321,0345,0311,'6',0322,0224,'V','#',0357,'/','P',0177,'*',0310,0240,017,0265,0376,036,0370,0246,'?',027,0370,'6',0307,'S',04,'y',0373,'|',0271,0327,0373,0262,'/',07,0374,'k',0250,0257,0231,'?','g',0257,023,0313,0247,0370,0252,0347,'@',0232,'P',',',0357,0342,'2','"',0221,0322,'e',0306,'1',0351,0225,0334,017,0321,'k',0351,0272,0,'(',0242,0212,0,0363,0337,0212,'>',' ','o',017,'|','&',0272,0226,'&','+','q','u',02,'Z','D','A',0301,05,0306,011,07,0331,'w',037,0256,'+',0344,'*',0367,0217,0332,023,'W','a',0247,'x','w','G','R','v',0230,0215,0303,0340,0372,0,0,'#',0277,'Z',0360,'z',0,'+',0353,0357,0203,'~',032,'_',017,'|','>',0262,'g',0210,'-',0315,0360,0373,'L',0247,0271,0335,0367,0177,'L','W',0313,036,027,0321,037,0304,'~','(',0323,'t','t',0310,0373,0134,0353,033,025,'8','!','3',0226,'#',0203,0321,'A','5',0367,',','Q','$',020,0244,'Q',0250,'X',0321,'B',0252,0216,0200,016,0,0240,07,0321,'E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'T',027,0227,'Q','X',0332,'K','s','3',05,0216,'5',0311,0317,0177,'j',0236,0270,037,032,0353,'K','$',0306,0311,034,010,'`',0371,0245,'n',0305,0277,0372,0324,01,0312,0370,0217,0134,'y','%',0226,0362,'S',0373,0331,'N','#','_','A',0333,0362,0256,031,0231,0235,0313,'1','%',0211,0311,0253,':',0205,0343,'^',0335,'4',0207,0205,034,'(',0364,025,'k','G',0265,'G','w',0271,0227,033,'#',0351,0237,'Z',0371,0254,0303,027,0355,'$',0332,0331,'l','y','x',0314,'R',0247,027,'Q',0354,0210,'!',0265,0274,0266,'d',0272,020,'6',0325,'9',0374,'>',0225,0252,0272,0261,0271,0375,0325,0254,',','f','#',0370,0272,'/',0275,'X',0216,0371,'M',0263,0134,0312,'6','D','[',011,0352,'E','V',0324,'m','!','H',0215,0344,'O',0345,'8',0344,025,0350,0325,0343,0271,')',0312,0323,'Z',0237,'9','*',0321,0304,'U','Q',0304,0323,0264,0266,'O','V',0257,0331,0367,033,'}','(',0261,0323,0314,06,'B',0363,'K',0234,0223,0357,0324,0323,'4','=',';','q',027,'r',0257,03,0356,03,0374,0352,0235,0205,0254,0232,0235,0346,0351,'X',0262,016,']',0217,0362,0257,'L',0360,0246,0202,'/',0356,04,0322,0246,'-',' ',0350,'1',0303,036,0302,0275,0354,0257,05,'o',0336,0314,0372,',',0273,07,0354,'c','y',';',0266,0356,0375,0177,0310,0333,0360,0216,0204,'-',0241,032,0205,0302,'~',0371,0307,0356,0324,0217,0272,0276,0277,'S',']',']',0,0,0,03,0,'Q','^',0371,0352,0205,024,'Q','@',037,'<',0376,0321,0276,030,021,0335,0351,0336,'&',0202,'5',02,'Q',0366,'[',0222,':',0226,034,0243,037,0303,'#','>',0313,'^',015,'_','i','|','K',0320,0227,0304,'?',017,0365,'k','-',0240,0310,'!','2',0305,0222,'F',035,'>','a',0323,0351,'_',026,0320,06,0237,0207,'5','w',0320,'|','G',0247,0352,0261,0222,032,0326,'u',0220,0343,0256,'3',0317,0351,0232,0373,0232,0326,0341,'.',0355,'!',0270,0214,0345,'%','@',0343,0350,'F','k',0340,'j',0373,03,0340,0306,0264,'5',0237,0206,032,'^','Y','L',0266,'{',0254,0344,0,0364,0331,0367,'G',0375,0360,'T',0376,'4',01,0337,0321,'E',024,01,0362,027,0306,'m','O',0373,'C',0307,0357,010,'$',0255,0225,0244,'0','{','g','`','c',0217,0373,0353,037,0205,'y',0355,'m','x',0273,'Q',0376,0325,0361,'v',0253,'x','$','I',021,0356,031,'c','t',0350,0310,0247,'j',0221,0377,0,01,02,0261,'h',03,0326,'?','g',0335,')','o','~',' ',0275,0353,0252,0262,0331,'[','3','.','z',0207,'n',01,037,0206,0357,0316,0276,0247,0257,04,0375,0232,0254,0224,'[','k',0267,0333,'N',0342,0361,0302,'N','x',0300,04,0364,0374,'M','{',0335,0,024,'Q','E',0,025,'^',0356,0372,0326,0306,'?','2',0346,'t',0211,'{','n','<',0237,0245,'s',0272,0357,0213,'R',0321,0336,0326,0303,022,'L',0274,'4',0207,0225,'S',0355,0352,'k',0316,'u',']','|',011,0331,0356,'&','y',0356,017,'Q',0234,0343,0374,'*',047,'R','0',0134,0322,'v','B','r','Q','W','g',0244,0134,'x',0336,0306,'6',0304,'0',0313,'/',0277,0335,025,'L','x',0364,0356,0347,'O',0371,'s',0327,0315,0347,037,0225,'y',025,0306,0265,'w','1',';',037,0312,'_','E',0353,0371,0325,'d',0276,0273,0215,0303,0213,0211,'r','=','X',0232,0340,0226,'g','I',';','$',0331,0203,0304,'F',0372,037,'B',0350,0372,0365,0246,0260,0254,'"',0312,'J',0243,'-',033,'u',0307,0257,0275,'j',0327,0214,0370,'W',0134,0305,0354,027,'$',0205,'x',0234,011,06,'{',036,'3','^',0312,010,'`',010,0350,'y',0257,'B',023,0214,0342,0245,035,0231,0272,'i',0253,0241,'h',0242,0221,0230,'"',0226,'c',0205,03,'$',0325,014,0311,0361,016,0254,'4',0255,'5',0235,'O',0357,0344,0371,'c',036,0376,0277,0205,'x',0226,0277,0250,031,034,0333,'+',022,'s',0231,016,'z',0237,'J',0351,0374,'c',0342,'#','s','s','$',0341,0276,'E',0312,'@',0276,0336,0277,0326,0270,0230,0364,0351,'g',0263,'{',0267,0220,')',0345,0276,'n',0376,0246,0274,0254,0317,026,0251,0307,0331,0247,0253,'8',0361,'x',0230,'R',0212,'R','v',0276,0205,'H','b','i',0245,'T','P','y','<',0343,0265,'_',0324,'#',']','=',0274,0233,'y',0230,07,'_',0235,'3','K',0244,'^','[',0333,'3',',',0253,0265,0237,0370,0377,0,0245,']',0324,'4',0241,'t','L',0360,'7',0316,'y',0301,'<',032,0371,0311,0324,0265,'K','K','D','x','U',0361,'|',0230,0245,012,0276,0354,'?',06,0377,0,0340,022,0304,0266,0267,0272,'|','*',0314,'6',0240,04,0200,'q',0202,'=','k','2',0376,'C','}','~',0260,'[',0235,0312,'0',0240,016,0231,0365,0254,0347,'G',0211,0312,':',0225,'a',0301,06,0272,'m',017,'L','1','"',0312,0310,'L',0362,'p',0243,0270,07,0265,'u',0340,0260,'^',0326,0256,0372,035,'8','<',0271,'F',0257,'?','3','k','[','y','_','s','c',0303,0372,033,'O',',','V','6',0343,0223,0314,0217,0216,0236,0244,0327,0255,0331,0332,'C','c','i',035,0264,013,0266,'4',030,036,0376,0365,0233,0341,0315,025,'t',0213,034,0270,06,0346,0134,031,017,0247,0265,'l',0327,0326,'F','*',')','E','l','{',0351,'$',0254,0202,0212,'(',0246,'0',0242,0212,'(',01,0256,0213,',','m',033,0214,0253,02,0244,'z',0203,'_',012,'x',0212,0307,0373,'3',0304,0332,0265,0206,'s',0366,'[',0311,0241,0317,0256,0327,'#',0372,'W',0335,0265,0361,0357,0306,'{','F',0264,0370,0257,0255,0203,033,'*','J',0321,0312,0204,0256,03,06,0215,'r','G',0250,0316,'F','}','A',0240,016,012,0276,0213,0375,0232,0357,0213,'h',0372,0335,0201,'#',011,'p',0223,'(',0372,0256,017,0376,0202,'+',0347,'J',0366,0277,0331,0272,'b',0236,047,0325,0342,030,0304,0226,0253,0237,0301,0215,0,'}',')','E',024,'P',07,0300,024,'Q','E',0,'}','3',0373,'8',0333,',','~',016,0324,0256,03,022,'f',0274,0301,036,0230,'Q',0376,'5',0354,0325,0343,'_',0263,0215,0312,0311,0340,0335,'J',0334,')',015,015,0346,'I','=',016,'T',0177,0205,'{','-',0,025,0317,'x',0273,'T','{',015,'9','a',0205,0212,0313,'9','#','#',0250,'Q',0326,0272,032,0343,'|','y',021,')','e','/','`','Y',0177,'<',037,0351,'@',036,'e',0254,0352,0215,01,0373,'<',07,016,'G',0314,0336,0225,0316,022,'I',0311,'9',047,0275,'X',0277,',','u',013,0215,0335,'|',0306,0376,'u','^',0276,'g',025,'Z','U','j',';',0354,0217,'>',0244,0334,0245,0250,'Q','E',025,0314,'f','h','h',0367,036,'F',0240,0231,'8','W',0371,'M','{',0327,0206,'/',0376,0337,0241,0302,'Y',0263,'$','_',0273,0177,0303,0247,0351,0212,0371,0331,'I','V',014,016,010,'9',025,0353,'>',02,0326,024,0134,'$','l',0330,0216,0351,'@',0372,'8',0377,0,'&',0275,0254,0256,0255,0342,0351,0276,0232,0235,'x','y','h',0342,'z','E','r',0336,'3',0326,'E',0225,0227,0330,0243,'l','I','(',0314,0215,0375,0324,0377,0,0353,0327,'C','{','y',025,0205,0234,0227,'3','6',021,06,'~',0276,0325,0341,0336,'-',0326,0345,0275,0273,0220,026,0371,0345,'9',0177,0366,'G','e',0257,'B',0275,'e','J',016,'l',0336,'r','Q','W','f','i','-',0254,0352,'d',0223,0373,0204,0355,0355,0377,0,0327,0253,0272,0204,'3','N',0360,0332,'D',0233,'a','?','y',0207,'L',016,0325,0317,0303,'<',0266,0362,07,0211,0312,0265,'t',026,':',0264,'W','8','I','q',034,0237,0241,0257,0215,0305,'J',0244,0252,'{','W',0251,0362,0231,0232,0304,0252,0253,021,025,0314,0227,'N',0317,0271,'G','X','[','x',0314,'V',0360,0306,'<',0305,034,0221,0351,0351,'H',0222,'_','i','H',0245,0300,'h',0233,0242,0223,0320,0326,0227,0366,'d','K','}',0366,0242,0304,0217,0274,'U',0275,'}','k','2',0342,'I','5','}','@','C',021,0375,0332,0234,017,0247,'s','J',0212,'u','Z',0247,025,'q','a','&',0261,'*','4','"',0271,0243,'o','y',0276,0357,0242,'$',0322,0355,036,0376,0355,0256,0356,'9','@','s',0317,'s','^',0255,0340,0355,017,047,0373,'J',0341,'x',034,'B',0247,0365,'o',0360,0256,'{',0303,':',07,0333,0356,'c',0267,'P','V',0326,',',031,033,0333,0323,0352,'k',0324,0343,0215,'"',0215,'c','E',012,0212,'0',0,0354,'+',0354,'0',0270,'u','B',0232,0212,0334,0372,0252,'T',0325,'8',0362,0241,0324,'Q','E','t',032,05,024,'Q','@',05,024,'Q','@',05,'|',0251,0373,'A',')','_',0211,'y',' ',0200,'l','b','#',0337,0226,0257,0252,0353,0345,'O',0332,011,0231,0276,'%',0200,'I','!','l','b',03,0330,'e',0250,03,0312,0353,0325,0177,'g',0277,0371,')','g',0376,0274,'%',0376,'k','^','U','^',0253,0373,'=',0377,0,0311,'K','?',0365,0341,'/',0363,'Z',0,0372,0252,0212,'(',0240,017,0205,0374,'U',0247,0177,'d',0370,0257,'T',0262,020,0210,'R',';',0227,0362,0343,07,'!','c',047,')',0377,0,0216,0221,'Y',025,0337,0374,'d',0323,0177,0263,0376,' ',0315,' ','?','-',0345,0254,027,0,'c',033,'~','@',0247,0353,0312,023,0370,0327,01,'@',037,'B','~',0315,'w',0252,'m','u',0333,035,0337,'8','x',0346,'+',0216,0304,021,0234,0376,06,0275,0356,0276,'Z',0375,0236,0365,'e',0262,0361,0364,0266,'.',0312,0253,'{','l',0312,0271,'<',0227,'^','@',037,0206,0343,0370,'W',0324,0264,0,'V',017,0213,0255,0274,0375,06,'G',035,'b','`',0377,0,0322,0267,0252,'+',0230,026,0352,0326,'X',037,0356,0310,0205,'O',0342,'(',03,0347,'=','n','/','+','R','s',0331,0300,'j',0316,0256,0217,0304,0366,0215,021,'R',0303,017,023,0230,0337,0353,0376,'E','s',0225,0363,'X',0332,'|',0225,0344,0273,0352,'y',0365,'U',0246,0302,0212,'(',0256,'S','0',0255,0377,0,016,'^',030,0331,0240,0336,'U',0201,0336,0204,034,020,'}',0253,02,0235,034,0217,014,0213,'"','1','V','S',0220,'E','o',0207,0255,0354,'j',')',0227,011,'r',0312,0347,0242,0370,0207,0305,027,'7','V',011,0366,0246,0134,'F','8','U',0343,'{','z',0232,0363,0271,'d','i',0245,'i',034,0345,0230,0344,0232,0222,0346,0362,'{',0266,015,'3',0356,0307,'A',0330,'T',025,0256,'3',025,0355,0345,'e',0262,'*',0255,'N','w',0344,024,'Q','E','q',0231,026,0306,0243,'r','m','M',0266,0342,0312,0334,03,0337,036,0225,0322,0350,':','D',0213,0345,0305,032,'o',0272,0230,0201,0217,'O','j',0310,0320,0364,0377,0,'6','O',0265,'H','>','E',0373,0240,0367,'>',0265,0354,036,020,0321,'>',0313,'o',0366,0373,0205,0304,0322,0217,0335,0203,0374,'+',0353,0365,'5',0354,0345,0270,'E',05,0355,'Z',0325,0354,'t','a','p',0360,0247,'y','%','k',0233,'Z','>',0227,036,0223,0247,0245,0272,'`',0277,'Y',037,0373,0315,'W',0350,0242,0275,'c',0260,'(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'+',0343,0377,0,0215,'W',0262,'^','|','V',0326,03,'9',')',07,0225,014,'`',0377,0,010,021,0251,'#',0376,0372,',',0177,032,0372,0371,0335,'c','F','v','8','U',031,047,0320,'W',0302,0276,'#',0275,032,0227,0212,'5','k',0361,0234,0134,0336,0315,'0',0317,'_',0231,0311,0376,0264,01,0231,'^',0325,0373,'7',0302,'_',0305,':',0264,0270,0134,'G','j',0275,'z',0362,0335,0253,0305,'k',0350,0237,0331,0256,0304,0215,'+',0134,0324,012,0360,0323,0244,'*',0334,'s',0205,0334,'G',0352,0264,01,0356,0324,'Q','E',0,'|',0357,0373,'B','i',015,0375,0237,0341,0355,'a',024,0355,021,'}',0235,0310,034,'d',0200,'F','O',0341,'^',021,'_',0134,0374,'W',0320,'_','^',0370,'I','r',0260,0250,'k',0213,'8','c',0273,0217,'=',0302,014,0260,0377,0,0276,'w','~','8',0257,0221,0250,03,'g',0302,'z',0323,'x','w',0305,0272,'V',0254,030,0252,0332,0334,0243,0310,'@',0317,0311,0234,'8',0307,0272,0222,'+',0356,'H',0344,'I','c','Y','#','`',0310,0340,'2',0260,0350,'A',0257,0200,0253,0354,037,0203,0336,'%','_',021,0374,'>',0261,0334,0340,0334,'Y','/',0331,'e',031,0344,'m',034,'~',0230,0240,016,0372,0212,'(',0240,017,'-',0361,0366,0227,0213,0353,0220,07,023,0257,0232,0277,0357,017,0376,0270,0375,'k',0313,0353,0336,0274,'o','e',0347,'i',0221,0335,'(',0346,027,0303,0177,0272,'x',0376,'x',0257,020,0324,0240,0373,'=',0374,0251,0216,011,0310,0372,032,0362,'3','J','Z','*',0213,0320,0345,0304,'G','i',025,'(',0242,0212,0361,0316,'P',0242,0212,'(',0,0242,0212,'(',0,0253,026,'V',0217,'y','r',0261,'/','N',0254,'}',05,'W',0,0223,0200,'2','M','v',0276,035,0321,'e','w',0212,0332,'4',0315,0304,0304,'n',0377,0,'d',0177,0200,0256,0274,036,037,0333,'T',0327,'e',0271,0255,'(','s',0263,0242,0360,0236,0202,'/','n','P',0262,'b',0316,0337,033,0275,030,0366,025,0351,'@',0,0,03,0,'U','m',':',0306,'-','6',0306,';','X',0207,0312,0203,0223,0352,'{',0232,0265,'_','H',0225,0264,'G','x','Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E',024,01,0312,'|','H',0327,07,0207,0374,01,0253,0337,07,'U',0227,0310,'1',0305,0273,0241,'v',0340,017,0326,0276,'+',047,047,'&',0275,0367,0366,0215,0361,':',0264,0232,'w',0206,' ','s',0225,0377,0,'K',0271,0301,0300,0356,021,'O',0257,'s',0371,'W',0201,'P',01,'_','^','|',023,0321,06,0213,0360,0307,'O','f','@',0263,'_',0263,'^','I',0202,'N','w',0340,')',0347,0375,0205,'N',0237,0375,'z',0371,'S','A',0322,0244,0327,'u',0373,015,'.',' ',0305,0356,0247,'X',0376,0134,'d',02,'y','<',0372,014,0232,0373,0236,0316,0331,',',0354,0240,0265,0214,'a','!',0215,'Q','@',0364,03,024,01,'=',024,'Q','@',025,0255,021,'d',0322,0340,'F',031,'V',0205,'A',07,0323,'m','|',']',0343,0357,015,0277,0205,'<','i',0250,0351,'d','b','%',0220,0311,07,030,0375,0333,'r',0277,0227,'O',0302,0276,0322,0261,0377,0,0220,'}',0267,0375,'r','_',0344,'+',0306,0277,'h','O',06,0266,0241,0243,0333,0370,0236,0315,011,0232,0307,0367,'W','J',0243,'%',0242,047,0206,0377,0,0200,0237,0320,0373,'P',07,0315,0265,0352,037,03,0274,'b','|','9',0343,'5',0323,'n',033,026,032,0256,'!','r','O',021,0310,'3',0261,0277,023,0362,0237,0250,'=',0253,0313,0351,0321,0310,0361,'H',0262,'F',0305,']',010,'e','a',0324,021,0336,0200,'>',0375,0242,0270,'?',0205,036,'8','O',032,'x','J',047,0230,0250,0324,'l',0361,015,0322,'g',0251,03,0207,036,0304,'~',0271,025,0336,'P',04,027,0266,0311,'y','e','5',0263,0217,0226,'D','+','^',015,0342,'{',047,0206,'@',0354,'0',0321,0261,0215,0353,0350,012,0363,'?',036,0351,'8',0275,0220,0201,0362,']','&',0345,'?',0355,016,0277,0322,0260,0304,0322,0366,0264,0234,010,0251,036,'h',0264,'y','M',024,0254,0245,030,0253,014,020,'p','i','+',0345,0366,'<',0360,0242,0212,'(',020,'Q','E','O','g','j',0327,'w','+',012,0367,0352,'}',05,'8',0305,0311,0250,0255,0330,0322,0273,0262,'4',0264,'+',037,'6','O',0264,0310,'>','D','?','.','{',0232,0366,'o',011,0350,0277,'`',0263,0373,'T',0351,0213,0211,0207,'B','9','U',0364,0256,'o',0301,0272,012,0134,0316,0263,':',0177,0242,0333,020,0,0354,0315,0351,0375,'k',0321,0353,0351,0360,0364,025,032,'j','(',0364,')',0303,0222,'6',012,'(',0242,0267,',','(',0242,0212,0,'(',0242,0212,0,'(',0242,0212,0,'*',0246,0251,0250,0333,0351,032,']',0326,0241,'w',' ','H','-',0343,'i',035,0211,0300,0,014,0325,0272,0360,'/',0332,07,0307,'8',0206,'/',011,0351,0363,0217,0234,0371,0227,0305,'O','8',037,'u','=',0275,'O',0320,'P',07,0212,0370,0247,'_',0237,0304,0376,'%',0276,0326,'.','3',0272,0346,'B',0312,0247,0370,'W',0240,037,0226,'+',036,0212,'t','q',0264,0262,',','h',0273,0235,0310,'U',03,0271,'4',01,0354,037,0263,0337,0206,'$',0324,'|','Y','>',0273,'4','`',0332,'i',0361,0225,'F','=',0346,'l','c',037,'E',0311,'?','Q',0370,'}',';',0134,0237,0303,0217,012,0217,07,0370,'*',0307,'M','l',0233,0202,0276,'l',0344,0367,'v',0344,0217,0303,0247,0341,']','e',0,024,'Q','E',0,'W',0261,0377,0,0220,'}',0267,0375,'r','_',0344,'(',0277,0262,0267,0324,0264,0373,0213,033,0270,0326,'K','{',0210,0332,'9',021,0206,'C',')',030,'"',0213,037,0371,07,0333,0177,0327,'%',0376,'B',0254,'P',07,0304,'^','8',0360,0274,0376,020,0361,'m',0366,0221,',','n','"',0215,0367,'@',0354,'8',0222,'3',0312,0220,'{',0360,'q',0365,04,'W',';','_',']',0374,0134,0360,012,0370,0323,0303,'M','-',0244,'J','u','k','%','/','n',0330,0345,0307,'R',0237,0217,0363,0257,0221,0244,0215,0342,0221,0243,0221,031,035,011,'V','V',030,' ',0216,0240,0212,0,0351,0274,03,0343,033,0237,04,0370,0242,015,'N',034,0264,015,0373,0273,0230,0307,0361,0306,'O','?',0210,0353,0370,'W',0331,032,'.',0261,'c',0257,0351,026,0332,0246,0233,':','O','k','p',0233,0221,0324,0347,0352,017,0241,07,0202,';',021,'_',07,0327,0245,'|','(',0370,0237,047,0202,'5',01,'c','~','Y',0364,'K',0211,'3','(','Q',0270,0302,0307,0215,0340,'w',0355,0221,0351,0353,0322,0200,'>',0265,0254,0217,022,'i',0207,'S',0322,035,020,'f','h',0317,0231,037,0324,'v',0374,0253,'F',0326,0352,013,0333,'X',0256,'m','f','I',0240,0225,'C',0244,0210,'r',0254,017,'B',015,'M','@',037,':',0353,0266,'&',033,0217,0264,'*',0235,0216,'~','a',0350,0325,0217,'^',0317,0342,0217,011,'<',0263,'I','q','g',017,0233,014,0274,0311,010,034,0251,0365,036,0325,0302,'M',0340,0351,025,0310,0362,0256,0223,0333,'f',0177,0245,'x',0370,0254,0276,'R',0237,'=','>',0247,'-','J','-',0273,0304,0344,0350,0256,0234,0370,'B','o',0372,'x',037,'X',0215,':','?',07,'L',0314,024,0255,0313,023,0330,'D','E','r',0377,0,'g',0342,';','~','&','~',0302,'}',0216,0134,02,'H',0,'d',0232,0354,0374,'3',0241,0313,',',0261,0300,0211,0376,0221,'1',0371,0216,'>',0352,0326,0256,0225,0340,'+',0302,0312,0311,'i',0345,0177,0323,'I',0316,'1',0370,'u',0375,'+',0320,0364,'M',06,0337,'F',0211,0266,037,'2','w',037,'<',0204,'~',0203,0320,'W',0243,0203,0300,0373,027,0317,'=',0315,0351,'Q',0345,'w','e',0353,033,'8',0264,0373,'(',0255,'a',030,'H',0306,'>',0247,0271,0253,024,'Q','^',0211,0270,'Q','E',024,0,'Q','E',024,0,'Q','E',024,0,'Q','E','a','x',0267,0305,'z',0177,0203,0364,033,0215,'R',0375,0301,0362,0324,0230,0341,014,03,'J',0335,0224,'f',0200,'2',0276,'$',0370,0352,0337,0300,0336,031,0226,0350,'2','6',0243,'8','1',0331,0304,0303,'9','|','u','#',0320,'u',0375,'+',0343,0253,0353,0353,0235,'J',0372,'{',0333,0311,0236,'{',0231,0334,0274,0222,'9',0345,0230,0326,0267,0213,0374,'[',0251,'x',0317,'^',0227,'T',0324,0234,'n','?',',','Q','/',0335,0211,';','(',0377,0,036,0365,0203,'@',05,'z',0357,0300,0257,02,0177,'o','x',0207,0373,'z',0376,0337,'v',0237,0247,0260,'h',0203,016,'$',0233,'9',037,'P',0275,'~',0270,0367,0257,':',0360,0307,0206,0357,0374,'W',0256,0333,0351,'Z','|','e',0244,0225,0200,'g',0306,'D','k',0335,0217,0260,0257,0264,'|','5',0341,0353,'?',013,'x','~',0323,'H',0261,'_',0335,'[',0306,024,0271,03,'t',0215,0335,0216,';',0223,'@',032,0324,'Q','E',0,024,'Q','E',0,'W',0261,0377,0,0220,'}',0267,0375,'r','_',0344,'*',0305,'W',0261,0377,0,0220,'}',0267,0375,'r','_',0344,'*',0305,0,025,0363,0357,0307,037,0206,'[','M',0307,0213,0364,0210,0216,'8','k',0350,020,023,0355,0346,0,':','q',0327,0267,031,0365,0257,0240,0251,031,'U',0324,0253,0,'T',0214,020,'{',0320,07,0300,'4','W',0265,0374,'_',0370,'B',0332,'3','?',0210,'<','7','k',0273,'N',047,'7','6',0261,016,'`',0377,0,'i','G',0367,'=','q',0323,0351,0234,'x',0245,0,'z','O',0303,'?',0213,027,0376,012,0273,'K','+',0343,'%',0336,0212,0374,'4','Y',0313,'C',0376,0322,0177,'Q','_','S',0350,0372,0316,0237,0257,'i',0261,'j',032,'m',0312,0134,'[','H','2',0254,0207,0364,'>',0206,0276,017,0256,0213,0302,'>','5',0326,0274,027,0252,'-',0346,0225,'r','B',0236,'%',0267,'s',0230,0345,'_','B','?',0257,'Q','@',037,'n',0321,'^','u',0340,0177,0214,'^',037,0361,'p',0206,0326,'y',06,0237,0252,'8',0307,0331,0346,'n',035,0273,0354,'n',0207,0371,0327,0242,0320,01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E',024,'P',01,'E','E','q','s',05,0245,0274,0227,027,'3','G',014,'1',0215,0317,'$',0214,025,'T','z',0222,'k',0306,'<','y',0361,0356,0307,'O',0216,'K','/',012,030,0357,'.',0210,0301,0273,'e','&','$',0372,016,'7',037,0322,0200,'=',03,0307,037,020,'t','o',03,'i',0306,'k',0351,'D',0227,'n',017,0221,'j',0234,0274,0207,035,0375,07,0271,0257,0222,0374,'_',0342,0375,'S',0306,0232,0334,0232,0226,0247,'.','z',0210,'a','S',0362,'B',0277,0335,'Q',0374,0317,'z',0313,0324,0265,'K',0355,'b',0372,'K',0335,'F',0356,'k',0253,0231,011,'-','$',0255,0270,0237,0360,036,0303,0212,0251,'@',05,'M','i','k','=',0365,0334,'6',0266,0261,'4',0263,0314,0341,'#','E',0352,0304,0364,024,0330,' ',0226,0352,0342,'8',' ',0215,0244,0232,'F',012,0210,0203,'%',0211,0350,05,'}','I',0360,0243,0341,'-',0277,0204,0355,0343,0326,'5','x',0326,']','i',0327,'*',0247,0221,'n',017,'a',0376,0327,0275,0,'j','|','(',0370,'q',037,0201,0264,'C','-',0336,0331,'5',0213,0260,032,0341,0300,030,0214,'v','E','=','q',0353,0352,'k',0320,0350,0242,0200,012,'(',0242,0200,012,'(',0242,0200,'+',0330,0377,0,0310,'>',0333,0376,0271,'/',0362,025,'b',0253,0330,0377,0,0310,'>',0333,0376,0271,'/',0362,025,'b',0200,012,'(',0242,0200,021,0321,']',012,':',0206,'V',030,' ',0216,010,0257,04,0370,0237,0360,'<',0317,'$',0332,0337,0205,'#','E','c',0363,'O',0247,0216,01,0365,'h',0375,0377,0,0331,0375,'k',0337,'(',0240,017,0201,'&',0202,'[','i',0232,031,0342,'x',0245,'C',0206,'G','R',0254,0247,0334,032,0216,0276,0301,0361,0367,0302,'}',023,0306,0361,033,0215,0277,'b',0325,'T','|',0227,'q','/',0336,0366,'q',0374,'C',0337,0250,0375,'+',0346,0237,031,'|','=',0327,0274,025,'t','W','P',0265,'g',0264,'?','r',0356,'%','&','6',0372,0236,0307,0330,0320,07,')','^',0213,0341,'/',0214,0376,'(',0360,0302,'%',0274,0223,015,'F',0315,'x',021,0134,0222,'Y','G',0240,'n',0265,0347,'T','P',07,0325,0336,030,0370,0361,0341,'M','u',0274,0235,'A',0244,0322,'.','p','?',0343,0353,06,'&','>',0316,':',0177,0300,0200,0353,0336,0275,'*',0326,0366,0326,0366,'%',0226,0326,0342,')',0321,0206,'C','F',0341,0201,037,0205,'|',017,'W',0264,0335,'g','S',0321,0345,0363,'4',0333,0373,0213,'V',0316,'O',0225,'!','P','O',0270,0350,'h',03,0357,032,'+',0344,035,'7',0343,'_',0216,0264,0345,'U',032,0262,0334,0250,' ',0221,'s',012,0276,'G',0246,'z',0343,0351,']','5',0207,0355,'!',0342,'H',0234,0375,0277,'H',0323,'.','c',0333,0201,0344,0357,0211,0263,0352,'I','f',036,0274,'`','P',07,0323,024,'W',0317,0221,0376,0323,'3',04,0304,0236,024,'F','o','U',0277,'*','?','/',',',0323,'e',0375,0246,'.','I',036,'W',0205,0242,'Q',0337,'}',0351,'o',0375,0220,'P',07,0320,0264,'W',0313,0367,0337,0264,'_',0213,047,'w',026,0226,':','U',0254,'g',0356,0376,0351,0335,0307,0324,0226,0301,0374,0205,'r',0272,0247,0305,0257,033,0352,0300,0254,0372,0344,0321,0243,014,025,0201,'V','0',0177,'!','@',037,0134,'j',0276,' ',0321,0364,'H',014,0332,0246,0245,'k','i',030,'8',0314,0322,0205,0347,0322,0274,0233,0304,0277,0264,'V',0217,'i',0272,037,017,'X',0315,0177,'&',016,'.','&',036,'T','`',0366,0300,'?','1',0374,'@',0257,0234,'n','n',0356,'o','f','3',']',0134,'K','<',0247,0253,0312,0345,0230,0376,'&',0241,0240,016,0237,0305,0177,020,'<','G',0343,')','O',0366,0255,0373,0233,'|',0345,'m','b',0371,'b','_',0370,010,0353,0323,0251,0315,'s',024,'Q','@',05,'i','h','~',037,0325,'<','I',0250,0245,0206,0223,'g','%',0315,0303,'v','Q',0302,0217,'R','z',01,']',0347,0201,0276,012,0353,0276,')','h',0256,0365,025,'m','7','L','a',0273,0314,'q',0373,0307,037,0354,0257,0365,'5',0364,0227,0205,'<',033,0242,0370,'3','J','[',015,'"',0333,'`',0353,'$',0316,'w','I','+','w','f','?',0320,'`','z',012,0,0345,0276,032,'|',047,0260,0360,'E',0262,0336,'^',0371,'w','z',0324,0212,'<',0311,'q',0224,0213,0375,0230,0362,01,0374,'z',0232,0364,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,02,0212,'(',0240,012,0366,'?',0362,017,0266,0377,0,0256,'K',0374,0205,'X',0256,'V',0317,0307,0376,017,'K',033,'u','o',024,'h',0341,0204,'j',010,'7',0261,0360,'q',0365,0251,0277,0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,0,0351,'(',0256,'o',0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0243,0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0240,016,0222,0212,0346,0377,0,0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,'?',0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,0,0351,'*','9',0355,0341,0272,0201,0340,0270,0211,'%',0211,0306,0326,'G',0134,0202,'=',0305,'s',0377,0,0360,0260,'|',033,0377,0,'C','V',0215,0377,0,0201,0261,0377,0,0215,037,0360,0260,'|',033,0377,0,'C','V',0215,0377,0,0201,0261,0377,0,0215,0,'p','^','*',0375,0237,0264,035,'P',0311,'q',0241,0314,0372,'e',0301,04,0210,0276,0364,'D',0375,017,' ','}','+',0304,'<','O',0360,0313,0305,0236,023,'f','k',0375,'.','I','-',0201,0300,0272,0265,0375,0354,'G',0361,034,0257,0247,0314,05,'}','Y',0377,0,013,07,0301,0277,0364,'5','h',0337,0370,033,037,0370,0320,'~',' ','x','0',0202,017,0212,'t','b',017,0375,'>',0307,0376,'4',01,0361,')',05,'I',04,020,'G',04,036,0324,0225,0365,0246,0270,0237,010,0274,'C',0270,0352,032,0207,0207,'Z','F',04,'y',0261,0335,0306,0216,'?',020,'k',0316,'5',0237,0205,0377,0,015,0356,031,0237,'G',0370,0207,0247,0331,0222,'s',0345,0317,'s',024,0310,07,0240,0303,')',035,0271,'$',0320,07,0211,'Q',']',0266,0241,0360,0350,'Z',0274,0206,0323,0306,036,024,0275,0214,'7',0311,0263,'T','D','f',031,0340,0220,0330,0,0343,0266,'O',0324,0327,'=',0250,'h','3','i',0320,0274,0262,'^',0351,0223,05,' ','m',0266,0276,0216,'V','?','@',0244,0223,'@',031,'T','Q','E',0,024,'V',0375,0257,0204,0356,'n',0212,0201,0252,'h',0221,0202,'3',0231,'u','8','W',037,0134,0267,0351,']','.',0233,0360,0303,'O',0235,0363,0251,'|','@',0360,0255,0242,'v',0362,'o','D',0315,0371,'|',0243,0365,0240,017,';',0251,' ',0202,'k',0231,'V','(','"',0222,'Y',033,0200,0221,0251,'b',0177,01,'^',0365,0242,0374,':',0370,'I','a',0265,0365,'/',031,'Y','j','R',0,'7',06,0277,0216,'$',0317,'r',02,0234,0343,'=',0211,'5',0350,0372,'F',0263,0360,0307,'A','@',0272,'^',0253,0341,0313,0134,'w',0216,0346,' ',0177,'<',0320,07,0202,'x','S',0340,0217,0212,0274,'H',0253,'=',0334,07,'H',0264,'=',036,0355,010,0220,0363,0332,'>',017,0347,0217,'j',0367,'o',011,0374,036,0360,0257,0205,0274,0251,0315,0232,0352,027,0310,'C',013,0213,0265,017,0265,0207,' ',0252,0364,04,'v','=','k','o',0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0243,0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0240,016,0222,0212,0346,0377,0,0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,'?',0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,0,0351,'(',0256,'o',0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0243,0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0240,016,0222,0212,0346,0377,0,0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,'?',0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,0,0351,'(',0256,'o',0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0243,0376,026,017,0203,0177,0350,'j',0321,0277,0360,'6','?',0361,0240,016,0222,0212,0346,0377,0,0341,'`',0370,'7',0376,0206,0255,033,0377,0,03,'c',0377,0,032,'(',03,0377,0331,0,0377,0341,014,'w','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0,'<','?','x','p','a','c','k','e','t',' ','b','e','g','i','n','=','"',0357,0273,0277,'"',' ','i','d','=','"','W','5','M','0','M','p','C','e','h','i','H','z','r','e','S','z','N','T','c','z','k','c','9','d','"','?','>',' ','<','x',':','x','m','p','m','e','t','a',' ','x','m','l','n','s',':','x','=','"','a','d','o','b','e',':','n','s',':','m','e','t','a','/','"',' ','x',':','x','m','p','t','k','=','"','X','M','P',' ','C','o','r','e',' ','4','.','4','.','0','-','E','x','i','v','2','"','>',' ','<','r','d','f',':','R','D','F',' ','x','m','l','n','s',':','r','d','f','=','"','h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#','"','>',' ','<','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n',' ','r','d','f',':','a','b','o','u','t','=','"','"',' ','x','m','l','n','s',':','x','m','p','M','M','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/','"',' ','x','m','l','n','s',':','s','t','E','v','t','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#','"',' ','x','m','l','n','s',':','d','c','=','"','h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/','"',' ','x','m','l','n','s',':','G','I','M','P','=','"','h','t','t','p',':','/','/','w','w','w','.','g','i','m','p','.','o','r','g','/','x','m','p','/','"',' ','x','m','l','n','s',':','x','m','p','=','"','h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','"',' ','x','m','p','M','M',':','D','o','c','u','m','e','n','t','I','D','=','"','g','i','m','p',':','d','o','c','i','d',':','g','i','m','p',':','e','5','9','4','4','0','5','e','-','8','d','f','0','-','4','a','b','a','-','a','2','d','a','-','c','d','f','c','8','0','0','2','8','5','9','e','"',' ','x','m','p','M','M',':','I','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','1','8','b','0','1','7','6','2','-','f','7','1','8','-','4','c','5','f','-','a','a','5','c','-','7','b','4','d','0','8','a','7','2','7','d','4','"',' ','x','m','p','M','M',':','O','r','i','g','i','n','a','l','D','o','c','u','m','e','n','t','I','D','=','"','x','m','p','.','d','i','d',':','8','0','6','1','1','f','0','9','-','1','5','8','1','-','4','b','9','c','-','b','4','5','8','-','9','8','4','f','e','e','c','e','1','2','6','0','"',' ','d','c',':','F','o','r','m','a','t','=','"','i','m','a','g','e','/','j','p','e','g','"',' ','G','I','M','P',':','A','P','I','=','"','2','.','0','"',' ','G','I','M','P',':','P','l','a','t','f','o','r','m','=','"','L','i','n','u','x','"',' ','G','I','M','P',':','T','i','m','e','S','t','a','m','p','=','"','1','6','7','6','2','3','5','5','8','9','3','2','7','1','8','8','"',' ','G','I','M','P',':','V','e','r','s','i','o','n','=','"','2','.','1','0','.','3','0','"',' ','x','m','p',':','C','r','e','a','t','o','r','T','o','o','l','=','"','G','I','M','P',' ','2','.','1','0','"','>',' ','<','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','r','d','f',':','S','e','q','>',' ','<','r','d','f',':','l','i',' ','s','t','E','v','t',':','a','c','t','i','o','n','=','"','s','a','v','e','d','"',' ','s','t','E','v','t',':','c','h','a','n','g','e','d','=','"','/','"',' ','s','t','E','v','t',':','i','n','s','t','a','n','c','e','I','D','=','"','x','m','p','.','i','i','d',':','9','2','f','7','c','d','9','7','-','d','a','8','4','-','4','9','3','e','-','b','e','0','8','-','b','c','6','3','2','3','4','5','b','d','7','2','"',' ','s','t','E','v','t',':','s','o','f','t','w','a','r','e','A','g','e','n','t','=','"','G','i','m','p',' ','2','.','1','0',' ','(','L','i','n','u','x',')','"',' ','s','t','E','v','t',':','w','h','e','n','=','"','2','0','2','3','-','0','2','-','1','2','T','2','0',':','5','9',':','4','9','+','0','0',':','0','0','"','/','>',' ','<','/','r','d','f',':','S','e','q','>',' ','<','/','x','m','p','M','M',':','H','i','s','t','o','r','y','>',' ','<','/','r','d','f',':','D','e','s','c','r','i','p','t','i','o','n','>',' ','<','/','r','d','f',':','R','D','F','>',' ','<','/','x',':','x','m','p','m','e','t','a','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','<','?','x','p','a','c','k','e','t',' ','e','n','d','=','"','w','"','?','>',0377,0342,02,0260,'I','C','C','_','P','R','O','F','I','L','E',0,01,01,0,0,02,0240,'l','c','m','s',04,'0',0,0,'m','n','t','r','R','G','B',' ','X','Y','Z',' ',07,0347,0,02,0,014,0,024,0,'3',0,'&','a','c','s','p','A','P','P','L',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,0366,0326,0,01,0,0,0,0,0323,'-','l','c','m','s',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,015,'d','e','s','c',0,0,01,' ',0,0,0,'@','c','p','r','t',0,0,01,'`',0,0,0,'6','w','t','p','t',0,0,01,0230,0,0,0,024,'c','h','a','d',0,0,01,0254,0,0,0,',','r','X','Y','Z',0,0,01,0330,0,0,0,024,'b','X','Y','Z',0,0,01,0354,0,0,0,024,'g','X','Y','Z',0,0,02,0,0,0,0,024,'r','T','R','C',0,0,02,024,0,0,0,' ','g','T','R','C',0,0,02,024,0,0,0,' ','b','T','R','C',0,0,02,024,0,0,0,' ','c','h','r','m',0,0,02,'4',0,0,0,'$','d','m','n','d',0,0,02,'X',0,0,0,'$','d','m','d','d',0,0,02,'|',0,0,0,'$','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,'$',0,0,0,034,0,'G',0,'I',0,'M',0,'P',0,' ',0,'b',0,'u',0,'i',0,'l',0,'t',0,'-',0,'i',0,'n',0,' ',0,'s',0,'R',0,'G',0,'B','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,032,0,0,0,034,0,'P',0,'u',0,'b',0,'l',0,'i',0,'c',0,' ',0,'D',0,'o',0,'m',0,'a',0,'i',0,'n',0,0,'X','Y','Z',' ',0,0,0,0,0,0,0366,0326,0,01,0,0,0,0,0323,'-','s','f','3','2',0,0,0,0,0,01,014,'B',0,0,05,0336,0377,0377,0363,'%',0,0,07,0223,0,0,0375,0220,0377,0377,0373,0241,0377,0377,0375,0242,0,0,03,0334,0,0,0300,'n','X','Y','Z',' ',0,0,0,0,0,0,'o',0240,0,0,'8',0365,0,0,03,0220,'X','Y','Z',' ',0,0,0,0,0,0,'$',0237,0,0,017,0204,0,0,0266,0304,'X','Y','Z',' ',0,0,0,0,0,0,'b',0227,0,0,0267,0207,0,0,030,0331,'p','a','r','a',0,0,0,0,0,03,0,0,0,02,'f','f',0,0,0362,0247,0,0,015,'Y',0,0,023,0320,0,0,012,'[','c','h','r','m',0,0,0,0,0,03,0,0,0,0,0243,0327,0,0,'T','|',0,0,'L',0315,0,0,0231,0232,0,0,'&','g',0,0,017,0134,'m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'G',0,'I',0,'M',0,'P','m','l','u','c',0,0,0,0,0,0,0,01,0,0,0,014,'e','n','U','S',0,0,0,010,0,0,0,034,0,'s',0,'R',0,'G',0,'B',0377,0333,0,'C',0,03,02,02,03,02,02,03,03,03,03,04,03,03,04,05,010,05,05,04,04,05,012,07,07,06,010,014,012,014,014,013,012,013,013,015,016,022,020,015,016,021,016,013,013,020,026,020,021,023,024,025,025,025,014,017,027,030,026,024,030,022,024,025,024,0377,0333,0,'C',01,03,04,04,05,04,05,011,05,05,011,024,015,013,015,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,024,0377,0302,0,021,010,02,'T',02,'@',03,01,021,0,02,021,01,03,021,01,0377,0304,0,035,0,01,0,02,02,03,01,01,0,0,0,0,0,0,0,0,0,0,06,07,05,010,03,04,011,02,01,0377,0304,0,033,01,01,0,02,03,01,01,0,0,0,0,0,0,0,0,0,0,0,05,06,02,03,04,01,07,0377,0332,0,014,03,01,0,02,020,03,020,0,0,01,0332,0220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,01,0326,'"',04,0134,0301,0235,'0',0,0,0237,0226,'H',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'8',0312,0374,0201,034,07,016,0254,'q',0261,0372,':','<','Z',0272,0274,0332,0370,'u','c',0363,0217,0237,'Y','{',0331,0350,0316,'I','`',0356,0355,'t','g',0260,0340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,07,'D',0250,'L',031,0207,0211,0346,0216,0300,0361,'b',0243,'t','~','y',0340,0,01,'$',0260,'w','K',0354,0362,033,012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,03,0246,'S',06,03,0233,0134,'6',0245,033,0213,0216,0347,0,0,0,0375,0367,0333,06,0363,'/',':',0355,0335,'n',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,07,021,'L',0221,'.',035,'0','Z',0134,'W',016,0254,0,0,0,04,0246,0311,0337,',',0261,0367,0335,0346,'P',0,0,0,0,0,0,0,0,0,02,'>','W','D',020,0211,021,'s',016,'b',0216,0251,0310,'e',014,0241,'$','%','d',0340,0237,0223,'s',0354,0,0,0,03,0360,0251,'H','?','.',0270,05,'"','#',0207,'N',0,0,0,03,'/',')',0323,'8',0271,'J','Z','~',0373,'6',0,0,0,0,0,0,0,0,01,0324,'*','"',0234,'*','R',' ',0,0,0,0,0,031,'R',0323,'.',02,0352,'$','@',0,0,'+','r',0272,0327,0214,06,0221,021,0322,0343,0324,0,0,0,';',0235,'{','g',0367,'y','y',0326,0334,0255,'0',0,0,0,0,0,0,0,0,0255,015,'y','(',0363,030,0,0,0,0,0,0,0,07,0331,'i',0233,04,'^','G','h',0,'B',0212,0257,0317,' ',0324,0330,0274,'L','_','0',0,0,0,0345,0333,0224,0376,0357,'/',')',0353,0333,'s',0234,0200,0,0,0,0,0,0,03,0344,0245,'M','`','+','`',0,0,0,0,0,0,0,0,0,014,0361,0262,06,0311,031,'B',':','S',0204,':',0255,035,035,0201,0342,0,0,0,037,0276,0373,'9',0271,'J',0310,0245,':','.',0323,0276,0,0,0,0,0,0,0,'*','s','Q','J',0364,0,0,0,0,0,0,0,0,0,0,0,'2',0346,0327,0231,02,'-',011,0311,016,0251,0306,0,0,0,01,',',0263,0310,0311,0254,035,0267,'!','"',0,0,0,0,0,0,0,0217,032,'|','Q',0240,0,0,0,03,0220,0226,022,0303,'<','f',0316,0301,0306,'b','L','1',025,'!',0307,'@',0,0,0,035,0323,'g',0316,0377,0,06,0230,025,'&','#',0347,037,0,0,0,06,'z','k',0256,'e','m',0223,0263,011,0340,0,0,0,0,0,0,05,032,'i',0251,0207,0,0,0,'9',0213,'@',0267,0213,'H',0260,'N',0350,0,0,01,0360,'C','J',0310,0251,'J',0200,0303,0,01,0366,'l',0211,'1',0323,0205,0177,'F',0210,0353,'s',0353,0,0,0,031,036,0375,0363,0333,0264,0264,0307,'/','m',0220,0,0,0,0,0,0,'u',0215,'?','5',0320,0,0,0,0260,'M',0204,'/','S','4',0,0,0,0,0,0,'p',0225,031,0257,0245,',','p',02,0360,'-',0274,'|',0202,'S','"',0261,'q',0274,0340,0,0,03,0237,'v','v',05,0346,'b','C',0321,0235,0324,'s',0,0,0,0,0,0,030,'S','E','J',0274,0,0,05,0264,'m','1','j',0,0,0,0,0,0,0,0,04,'d',0326,'r',0274,'/',0222,047,'X',0217,0215,0327,0370,'@',0,0,07,0357,0276,0316,0356,0222,0331,0311,'-',0367,'a',0224,0,0,0,0,0,0,'#','&',0202,0220,0260,0,0,0236,033,'z','[','`',0,0,0,0,0,0,0,0,0,0303,024,0261,0200,0211,0346,0204,'S',0242,0317,0,0,0,04,0266,0321,'#','$',0237,0355,0267,011,'X',0,0,0,0,0,01,031,'<',0376,'"','@',0,016,0301,0265,'F',0315,0234,0340,0,0,0,0,0,0,0,0,0,0353,024,0221,0203,0345,0327,05,0241,0300,'e','c',0253,0230,016,0373,'?',0317,0276,0200,0,03,';','3',0327,'3',0267,'I',0317,0313,'$',0,0,0,0,0,0,0303,036,'|',0220,0240,0,04,0270,0336,'2',0303,0,0,0,0,0,0,0,0,0,0,025,011,023,0307,0310,015,'"','#','!',03,'R',0224,0305,'P','1',0335,'3',0221,')','k',0367,'S','w','`',0,016,0377,0,'n',0351,0365,0336,'^','K',0237,0267,'!',0364,0,0,0,0,0,03,0254,'h','1','V',0200,0,'-','s','y',0214,0270,0,0,0,0,0,0,0,0,0,0,0200,0225,0251,021,0253,'G','G','`','x',0204,0232,'2',0243,'#',0215,0243,'|','e',0276,'1',047,'z',0300,0310,'Y',0277,0,'9',0266,0345,'`','^','&',':',0275,'[','-','2',0311,0,0,0,0,0,0,'4',0344,0327,020,0,05,0340,'n',0341,0330,0,0,0,0,0,0,0,0,0,0,030,02,0231,'0','q',034,0320,0212,'|','P',0354,'k',0347,0236,0300,'|',0252,'+','-','}',0314,0361,'V',0362,0274,0225,0334,'_','U',0206,037,'3',0364,036,',',0266,'~',0373,0354,0342,0343,')',0224,0225,0351,0326,'s',0340,0364,'@',0313,0,0,0,0,0,05,036,'h',0330,0,02,0360,'7','|',0345,0,0,0,0,0,0,0,0,0,0,035,'R',0220,'0',0374,0372,0353,0352,',','G',016,0254,06,'_',0222,022,'e',013,0363,'X',024,0377,0,0326,':',0233,0273,'g',020,'_','5',0343,0313,'l','.','o',0350,0237,0217,'d',0326,'.',0371,'U',0227,0276,0221,'*',020,']',0346,0362,0200,0,0,0,0,'0',07,0234,0206,024,0,013,'X',0337,'c',0260,0,0,0,0,0,0,0,0,0,0,05,'H','D','|',0362,07,'J',0212,0306,'G','s',0201,0317,0206,0231,0354,07,0312,0177,036,0342,0372,0247,0262,0374,'u',0332,0372,0305,0365,0276,',',0266,'e','d',0272,047,'W','I','X',027,0276,0353,0221,0370,01,0273,'%',0366,0,0,0,0,06,0220,0224,'H',0,022,0303,0321,03,'0',0,0,0,0,0,0,0,0,0,0,04,',',0252,0310,0275,'s',0202,'/','[',0340,034,0372,0371,0344,'q',0325,017,0237,'v','c',':','f',0344,'Q',0324,0356,0346,0230,0350,0364,0215,0276,';','#','k',0354,'o',0316,0301,0274,0314,'t',0267,0347,0252,0247,'D',0,'f',0317,'G',0214,0330,0,0,0,05,'X','y',0374,0,07,'9',0350,'A','b',0200,0,0,0,0,0,0,0,0,0,01,0214,')',023,015,035,0242,05,'J',0211,0374,0363,0317,0337,'<',0234,0301,0374,0317,0367,0317,';',0332,'"','#','2','w',0254,'w','L',0266,';',0246,'W',0360,0375,0367,0331,0345,0326,'[','/','#',0276,0340,'4','@',0257,0200,0,0330,0263,'r','@',0,0,01,0370,'y',0346,'W',0,0,'m','q',0264,0300,0,0,0,0,0,0,0,0,0,0,'|',0224,0271,035,0327,0215,'}','E',0207,0352,'s','k',031,'.','h',0271,0214,'7',0316,'c','r','w','L',0307,025,'r',';','%','q',0225,0304,0320,0240,026,017,0252,0376,022,0313,'<',0204,0222,0301,0335,'h',023,0202,014,'y',0330,'u',0300,07,')',0350,0311,'6',0,0,0,')',0223,'D','@',0,0234,0236,0211,0235,0200,0,0,0,0,0,0,0,0,0,0,'+',0342,0270,'!',0325,'8',0334,04,047,030,031,016,'x',0331,0304,027,0313,'>','2',0337,021,0230,0372,',',0222,'2',0221,0206,0355,0262,0307,'d','m','y',0231,'n',0231,0275,0302,'V','_',0352,0331,0,0325,023,'V','@',0,0275,0315,0335,0,0,0,'<',0372,'+',0,0,'7',0324,0267,0300,0,0,0,0,0,0,0,0,0,0,0304,024,0221,0201,0210,0345,0204,0323,0342,0307,0327,0236,'I','#','j','8','n',0333,016,'z','>',0255,0236,0340,0250,014,'G','e',0226,037,'1',0364,016,0307,'N',0333,02,0365,'1',0232,0333,0225,0332,'s',0200,'t',0217,'7','H',0320,0,0345,'=','$','%','`',0,01,']',036,'x',0,01,'j',0233,0376,0,0,0,0,0,0,0,0,0,0,07,0311,'K',021,0255,030,'W',0264,'X','~',035,'8',011,'L',']','/','%',0313,013,031,0223,0273,'w',0264,0305,0364,'7',0313,'q',0345,0263,0241,0321,'$',0367,0331,0355,0332,'[','-','!',0276,0352,'3','@',0,'k',0241,0246,0300,0,'l',0311,0267,'`',0,01,0246,0246,0272,0200,01,0277,'E',0264,0,0,0,0,0,0,0,0,0,0,04,0,0255,0210,'5','6','+',021,025,0314,'9','p',0325,'a','W',0276,'G',027,0224,0276,0311,0243,'(',0234,0230,0363,0340,0373,0355,0261,')','k',0320,0225,0331,0244,'$',0266,036,0353,'<',0234,0200,0,':',0307,0232,0344,'p',0,'g',017,'L',016,0300,0,034,07,0231,'&',' ',0,'N',0317,'F',017,0320,0,0,0,0,0,0,0,0,0,01,0212,')',02,'9',07,0307,016,0252,'F',0201,0317,0206,0213,06,0275,0362,'?',0337,'5',0341,0373,'-',037,0257,':',0333,':',0342,0322,0267,0134,0274,0247,'L',0346,0345,'+',',',0365,'n',0,0,0,0325,0263,'S',0300,0,0336,0322,0347,0,02,0237,'4',',',0,015,0300,'6','P',0,0,0,0,0,0,0,0,0,0,012,'d',0212,'s','k',0257,'h',0260,0374,'Z',0361,035,0235,'|',0337,'^','c',0330,0327,0311,0331,0325,0307,0313,0216,0231,034,'m','.',011,';',0365,'/',0316,0316,0333,06,0365,'1',0230,0335,0235,0334,'v','@',0,0,'G',017,'4',0316,' ',01,'~',033,0260,0,06,0236,032,0334,0,'9',017,'L',011,0,0,0,0,0,0,0,0,0,0,0,0206,025,'W',0210,'%','2',047,025,031,0316,'2',0234,0260,0363,'(','_',0233,'}','y',0204,'z','F',0345,037,0221,0266,'I',0342,0351,'8','>',0353,'>',';',0252,'Z','w','t',0225,0313,0311,'t',']',06,'t',0,0,0,032,010,'T',0300,03,':','z','j','}',0,017,'8','H','H',0,0263,0317,'A','@',0,0,0,0,0,0,0,0,0,07,'T',0243,010,0234,017,034,'B',0255,032,'9','q',0327,'=',0200,0371,'V',027,0266,0323,0236,0217,0247,0375,0371,0253,0245,0276,'Z',031,'5',0364,'n',0266,0316,0231,'=',0213,0276,'S','e',0357,0262,'I',0370,0,0,0,06,0270,0232,'r',0,07,0242,'e',0202,01,0205,'<',0306,'?',0,06,0326,033,'P',0,0,0,0,0,0,0,0,0,0,'*',0242,05,0313,0256,0275,0242,0303,0361,0341,0210,0314,0361,'@',0347,'x','j',0335,015,0362,0277,'~','`',';',0374,0361,'P',0231,0317,0244,'w',0344,'z','g',0267,'i','i','7',0276,0334,'G',0350,0,0,0,04,'8',0363,'p',0,015,0305,'6','<',02,0243,'4',034,0,015,0376,'-','`',0,0,0,0,'8',016,0241,0370,'w',0216,'P',0,0,0,'G','J','g',0304,022,0231,023,0212,0214,0347,035,0375,021,0275,0315,'<',030,0256,0251,0271,0254,047,0315,0370,0362,0335,0333,0323,033,07,0235,0372,0177,017,'O','m',0203,'y',0230,0313,0365,'l',0273,0316,0350,0,0,0,0,0374,'<',0315,'#',0300,03,'`',0215,0322,0,0326,'c','Q',0,07,0351,0351,0371,0224,0,0,0,07,'P',0203,0221,03,022,01,0314,'Y',0344,0314,0,0,07,0301,'H',020,0250,'>','8','u','R','4','}',0371,0214,0246,'*',0223,0363,0356,'q','Y','[',0256,'{',0202,0265,'%',0214,0245,'a',';',0254,0361,'y','K',0234,0316,0333,047,0236,0232,0353,0267,0311,'@',0,0,0,0,03,'C',0312,'l',0,'X',0307,0241,0300,032,'r','k',0210,0,0224,036,0226,0,0,0,034,'e','~','@','N',017,'<',0304,'E',0363,0341,'b','9',0272,'<','Z','y','6','e','(',0261,0367,'f','d',0272,'/',0203,0266,0,0,020,'"',0254,0347,0302,0274,0242,'C','q','k',0304,'J',0242,0251,'9',0370,0372,0204,'6','g',0351,'X',0216,0311,0261,0372,'~',031,0311,0236,0271,0245,0272,'N','v','Y',0240,0,0,0,0,01,0251,06,0261,0,014,0301,0351,0340,06,0212,024,0260,0,0265,017,'@',0,0,0,'b',0312,0214,0303,0230,'x',0236,'h',0245,'f','?',0245,0311,0250,01,0365,0227,0266,05,0342,'^',0333,0355,0335,';',0,0,'t',0312,',',0257,0351,0261,']',030,'X',0271,0134,'U',032,035,'1',0364,036,0366,0210,0351,'l','G',0317,0373,':',0343,0343,0322,027,'8',0334,0235,0277,0343,0334,0273,']',';',',','+',0324,0306,'w','f','W','Y',0310,0,0,0,0,0,032,0352,'i',0250,0,036,0244,035,0300,'y',0360,'V','@',02,0365,'7','|',0,0,'1','e',',','t','p',0362,035,'T',0215,0301,0303,'r',0,0,031,0211,'^',0233,'V',0345,'+','u',0200,0,'*',0242,0260,0206,0344,0206,'T','"',0346,0360,0237,'6',0341,0317,0246,'9','%','p',0374,'{',0325,0333,0331,'(',0213,0246,'g','x','*','1',')',0177,0242,'a',';',0354,'S',0333,0264,0266,'^','C','}',0332,'e',0200,0,0,0,0,0,'S',06,0211,0,01,0351,'I','+',07,0235,'e','~',0,'6',030,0334,0340,0,0,0245,'H',0376,'>','A',')','q','8',0310,0355,0,0,0,0375,0367,0333,036,0377,0,'5','~',0357,0317,'&',0,'0','E',037,0247,012,0356,0211,017,0232,0210,0251,'H',0243,0251,0260,'i',0337,0251,'L',0341,'~','m',0213,0352,0236,0213,0312,0335,'y','p',0323,0333,0325,0305,0217,0350,0223,0223,'X',0273,0345,'6','^',0373,'@',0234,0,0,0,0,0,0,025,'1',0240,0200,0,'z',':','M',0301,0346,0361,014,0,033,'*','m',0370,0,03,034,'Q',04,'f',0273,0303,025,0255,'G',0200,0,0,011,'m',0236,'F',0344,0260,'v',0330,0340,037,0205,'(','V','5','(',0314,'$',037,014,0376,03,0345,0134,0270,'r','t','w',0313,0362,0343,0317,04,0235,0372,0216,'g',0216,0277,'$',0215,0247,'@','g',0376,0247,0336,0357,0337,'>',0273,0313,0312,0262,0366,0340,0,0,0,0,0,0,05,0134,'y',0370,0,07,0242,0304,0370,036,'s',0220,'0',01,0261,0246,0343,0200,0,'1','E',030,'@',0251,'1',030,0310,0355,0,0,0,03,'!',0337,0272,0314,0274,'L','_',07,' ','!','E','/',031,0317,04,0245,0304,0216,0316,0276,'i','d','E',013,')',0313,'^',0350,0357,0227,0214,0312,'^','&',020,0337,'8',0213,0312,0337,'0',0262,'6','K',02,0361,'1',0231,0354,0333,'x',035,0300,0,0,0,0,0,0,'U',06,0201,0,01,0350,0321,':',07,0236,'e','n',0,'/',0243,'v',0200,0,034,'f',0277,020,'*',0134,'N','&','3',0234,0,0,0,013,016,0367,'3','p',0366,'m',0232,035,022,0214,0303,0312,0316,0213,015,0324,0345,0326,07,0351,0236,0340,0254,0311,0342,0350,0237,'x',0351,0304,0365,0331,'!',0223,'_','C',0226,0332,'$','d','s',0375,0267,01,'(',0,0,0,0,0,0,0,0247,0315,013,0,03,0322,'"','d',015,010,'*',' ',01,'q',033,0344,0,0,024,0251,'[','V','#',0343,'U',0376,020,0,0,0,'$','S',0335,0263,0313,'L',0215,0320,'U',0205,'c','Y',0217,0215,'W',0270,'@',0,'v',0365,'q',0312,'"',0251,'1','I','k',0327,'v','^','B','w','s',0226,0234,'z',0264,0,0,0,0,0,0,0,05,04,'i','@',0,036,0237,031,'`','i','Y',0257,0340,02,'r','z','6',0,0,025,0251,'T',0304,0363,'A',0351,0321,'@',0,0,0,'r',0354,0312,0306,0277,'M','r',0355,0313,0241,0305,0246,0277,0243,'D','~','y',0340,0,0,'9','v',0345,'a','^',0246,'s',0375,031,0335,0247,'(',0,0,0,0,0,0,0,0325,0243,'T',0,07,'l',0365,034,0372,06,0253,032,0250,0,';','G',0250,0207,'0',0,02,'4','R',0372,0261,0255,'~','}',011,0371,0347,0200,0,0,0,'g',0347,';','$',0223,0375,0260,0212,'|','_','O',0223,'P',0,0,04,0316,0333,047,' ',0232,0353,0272,0214,0330,0,0,0,0,0,0,0,032,'J','P',0240,02,'h','z','@',01,'F',0232,':',0,07,0242,0344,0364,0,01,0306,'P','E','w','I',0210,0306,'G','h',0,0,0,0,0,0,0,01,0231,0226,0352,0233,0334,'e',',','b',0302,0,0,0,0,0,0,0,0,'y',0312,'A','@',05,0330,'o','@',04,'4',0363,'t',0,015,0313,'6','$',0,0,'*','"',0256,0256,0360,0305,'k','Q',0340,0,0,0,0,0,0,01,0315,0267,';',016,0367,'1','$',0337,0235,0322,'}',0,0,0,0,0,0,0,01,0211,'<',0304,'>',0,06,0326,033,'P',01,0370,'y',0216,'a',0,05,0340,'o',' ',0,0,'C',012,'s',0217,'U','{','D',0206,0,0,0,0,0,0,0,011,0255,0272,'R','C','3',0325,'w',031,'@',0,0,0,0,0,0,0,05,'"','h',0310,0,033,0360,'[',0200,03,'F',0312,'<',0,'e',017,'M',0316,0310,0,03,0254,'P','e','s','C',0206,0351,'r','j',0,0,0,0,0,0,03,'5','/',0325,'6',0270,'J','Y',0344,0344,0,0,0,0,0,0,0,0,'4',0260,0327,0340,01,0331,'=',';','2',0,03,'^',0215,'0',0,03,'z',0313,0244,0,0,')',0322,0260,0255,'p','F','+',0274,0,0,0,0,0,0,03,0237,'v','v',025,0356,'b','[',0273,';',0210,0,0,0,0,0,0,0,0,':',0247,0231,0206,' ',0,'[',06,0376,0,01,0203,'<',0314,'8',0200,05,0322,'o','X',0,0,'B','J','{',0207,'M','}','F',0207,0,0,0,0,0,0,023,'k',0204,0244,0216,'_',0252,0361,';',0300,0,0,0,0,0,0,0,01,'E',0232,'>',0,06,0343,033,034,0,0,0320,0202,0242,0,034,0247,0244,0244,0250,0,01,0325,'(','B',0271,0241,0303,'t',0271,'5',0,0,0,0,0,03,'5','/',0325,'6',0270,'J','[',04,0300,0,0,0,0,0,0,0,0,07,0237,'e','^',0,'9',0217,'K',0314,0370,0,02,0212,'4',0200,0,015,0220,'7',020,0,0,'*',022,0257,0256,0360,0305,'k','Q',0340,0,0,0,0,07,'6',0334,0254,';',0334,0314,0317,'~','v',0340,0,0,0,0,0,0,0,0,012,0304,0363,0344,0,013,0244,0336,0260,0,0,0353,0236,'k',021,0300,01,0332,'=','"','%',0,0,010,0221,'M','s','k',0256,0250,'0',0337,0217,0,0,0,0,0,'L',0255,0222,'r',0251,0276,0273,0304,0355,0200,0,0,0,0,0,0,0,0,0320,'B',0246,0,03,'~','K','l',0,0,06,0257,0232,0226,0,05,0360,'n',0340,0,03,0214,0241,012,0356,0227,023,0212,0214,0347,0,0,0,0,014,0264,0247,'L',0352,0347,'+','n',022,0300,0,0,0,0,0,0,0,0,024,0311,0242,' ',0,'O',0317,'E',017,0320,0,0,030,0343,0315,'S',014,0,'?','M',0371,'-',0240,0,05,'d','U','q','<',0320,0212,'t','P',0,0,0,03,0223,'f','V',025,0352,'b','u',0323,0262,0330,0,0,0,0,0,0,0,0,01,0320,'<',0345,'"',0200,0,'o','9','v',0200,0,0,03,'Z',0215,'@',0,02,'R','z','.','e',0,0,0306,024,'_',0212,0362,0215,017,0321,0342,0322,0,0,0,04,0272,0323,'#','/',0236,0355,0274,'N',0320,0,0,0,0,0,0,0,0,015,'6','5',0320,0,013,'(',0364,'$',0375,0,0,0,07,0134,0363,0240,0205,0,01,'x',0233,0304,'~',0200,01,'T',0225,0274,'_','<',026,0231,022,0,0,0,'2',0222,']',023,0313,0244,0265,0301,0352,'P',0,0,0,0,0,0,0,0,02,0221,'4','h',0374,0,037,'g',0240,0305,0226,0,0,0,0,'*',0263,'@','O',0220,0,'6',0310,0332,' ',0,':',05,034,'C','k','Q',0361,0232,0357,010,0,01,0373,0357,0271,0251,'~',0231,0205,0252,'J','{',0267,'+','@',0,0,0,0,0,0,0,0,04,04,0363,0354,0306,0200,01,0261,0206,0344,0,0,0,0,0,'4',0360,0326,0340,0,'>',0215,0326,'/',0300,0,'"',0245,'J','c','8',0264,0364,0371,'5',0361,0353,0307,0347,027,0317,0236,'}','z',0354,'t','l',0310,0367,0356,0314,0357,0316,'z','N','O',0320,0,0,0,0,0,0,0,0,0213,036,'}',0221,0200,0,'%',0247,0242,0306,'D',0,0,0,0,01,0323,'<',0366,' ',0,0,'r',0233,0260,'^',0340,0,'c',0314,01,0325,'>',016,'3',0340,0345,';',0306,'d',0313,0200,0,0,0,0,0,0,0,0,021,'c','@',0210,0210,0,035,0203,0320,022,0313,0,0,0,0,0,01,017,'<',0363,'0',0340,0,'}',0233,0206,'l','p',0,0,0,0,0,0,0,0,0,0,0,0,0,020,'3','C',0310,0270,0,03,'q','M',0217,0,0,0,0,0,0,05,'R','h','Q',0326,0,0,'l','q',0267,0307,'`',0,0,0,0,0,0,0,0,0,0,0,0,024,0231,0245,'F','0',0,01,0262,'&',0341,0200,0,0,0,0,0,0,012,'@',0321,0343,0214,0,01,'b',033,0262,'M',0300,0,0,0,0,0,0,0,0,0,0,03,0244,'j','9',0256,'G',0310,0,02,0370,'7','d',0373,0,0,0,0,0,0,0,02,0211,'4',0240,0340,0,0,'v',0215,0242,'6','t',0355,0200,0,0,0,0,0,0,0,0,0,012,'x',0323,0222,'$',0,0,027,0271,0272,0347,'0',0,0,0,0,0,0,0,0,'S',0246,0216,0230,0360,0,0,0224,033,'R','_',0247,'0',0,0,0,0,0,0,0,0,012,0330,0325,022,0242,0,0,01,0261,0346,0341,037,'`',0,0,0,0,0,0,0,0,05,'~','h',0271,023,0,0,01,'(','6','<',0277,0214,0370,0,0,0,0,0,0,07,01,'L',032,0340,'U',0,0,0,'9',0315,0274,'6','D',0,0,0,0,0,0,0,0,0,0,'b',015,'-',')','@',0,0,03,0234,0266,0213,0254,0267,0311,'H',0,0,0,0,030,0342,0252,')',0222,0223,'0','`',0,0,04,0254,0335,0302,0315,0,0,0,0,0,0,0,0,0,0,0,015,0177,'5',020,0303,0,0,0,0,'I',0313,024,0235,0222,0302,'B','d',0216,0361,0300,'b',0314,'9',025,'!','e','z','@',0316,' ',0,0,0,'}',033,012,'m',0321,0223,0,0,0,0,0,0,0,0,0,0,0,0,'0','F',0246,0232,0374,'q',0200,0,0,0,0,0,0,0,0,0,0,0,0261,'M',0300,',',0360,0,0,0,0,0,0,0,0,0,0,0,0,0,' ',0206,0253,0224,0211,0360,0,0,0,0,0,0,0,0,0,0,047,06,0323,0227,0231,0364,0,0,0,0,0,0,0,0,0,0,0,0,0,0,02,036,'k','a','B',0230,0200,0,0,0,0,0,0,0,0,0344,'-',0343,'d',013,0200,0372,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,035,'B',0235,'(',0342,0240,'1',0,0,0,0,0,0,07,'1','e',0227,'q','x',022,'P',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'q',0225,0331,'X',025,0341,02,'"','f','8',0,0,'9',0211,'9','7',',',02,0314,'-',03,'(',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,017,0303,026,'`',0216,0231,0324,'9',0316,0331,0226,'3',0207,'(',0,0,0,0,0,0,0,0,0,0,0,01,0377,0304,0,'.',020,0,0,06,01,02,06,02,03,01,0,02,03,01,0,0,0,01,02,03,04,05,06,07,0,' ',021,022,023,024,'0','@',020,025,026,'1','P','!','"','4',027,'%','&','2',0377,0332,0,010,01,01,0,01,05,02,0376,0342,0356,'R','l','G','6',0244,'I',0245,0354,'o','U',0322,0257,027,'_',0301,05,'8','~',0247,0366,0224,'P',0251,022,'J',0317,0245,'V','Q','s',0351,'E','H',0226,0217,'*',0201,'t','i',0240,0321,0246,'U',0327,0333,'/',0257,0265,'q',0240,0226,'_','I',0314,0237,'H','8','#',0202,0,0360,037,0354,0274,'x',0223,024,'d',0345,0225,0222,'>',0234,'J','$',0216,0226,0223,'Y',']',010,0361,035,0360,0240,'=','B',0224,'N','o',0354,';','t',0233,'$','$','d',024,0221,']',0303,0222,'6','#',0251,05,034,0370,0200,'9',0205,0223,'~',0331,012,0343,'.',0341,0357,0365,0325,'P',0250,0247,'-','(','i','%',0336,'<','+','B','*',0251,0226,'?',0212,')',0236,0222,'H',0313,')',032,0304,'#',0332,'{','o',0354,'1',0221,'Z','y',0226,0253,0255,'A',0346,'p','D',0242,0353,'5',0313,'(','.','r',0275,0221,'q','S','"',0330,0324,0322,0267,')',0325,'u',0371,'L',0326,0211,'m',0234,' ',0247,0177,0260,0245,0244,0262,'}',0225,'1','C','2',0316,0247,0246,0371,0305,'N',',',0263,',','#',0201,0217,0274,0300,0311,0350,0247,03,0227,0306,'#',0303,'S',0263,035,0362,0216,0134,025,0262,'J',0252,'e',0324,0361,'G',0262,0356,'O',0372,0325,'z',047,0266,047,0260,0345,0332,',',0222,0227,0313,'0','Q',0243,')',0232,'d',0234,'j','B',0335,'3','*','>','v','R',0257,'c',06,'/','-','O','0',0324,'V','i',0217,'q',0250,0253,024,'l',0341,'|',026,031,0216,'}','(',0241,'R','#',0247,'&','t',0257,0211,0253,'c',':','U','4',0312,0221,'+',0361,035,0311,0375,'y',0354,0211,011,0,'3',0231,0222,'M',0356,0237,0311,0273,0224,'W',0325,'!',0314,0231,0241,'2','d',0354,'6',0240,0363,014,'T',0206,0233,':','E',0352,';',047,0346,';','R',0210,0360,07,0357,'{',0223,0370,0222,'L',0313,035,0253,'b',0265,'J','&','0',0322,'N',023,'L',0251,023,0324,021,02,0205,0223,'+','E','B',0352,0301,0220,'f','l','^',0344,'L',0354,0204,022,0265,0334,0316,06,030,0351,'6',0222,0315,0365,'3','*',021,0310,0234,0342,0241,0244,0337,'s',0217,0210,03,0210,0307,0262,0355,0210,0321,0251,0336,'.',0305,0231,030,'7',0365,'-','9','"','.',0267,0253,'%',0352,'Z',0314,'o','~','2',']',0344,'3',0212,'v','S','V','X',034,0271,';',0265,0244,0336,0364,0213,0343,0214,'c',0313,0242,0224,'N','h','h',0260,0216,'C',0323,0232,0237,'c','^','k','m',0312,0217,0347,'<',0244,'!',0224,'3','J','|',0333,0341,'k',0212,0354,'n','D',0230,'b','t',0332,'&',020,'{',0303,0377,0,07,0270,0320,0340,0367,'z','_',012,0314,024,0316,'1',025,0205,02,0271,0240,'X','Z',025,0323,07,',','G',0304,0315,0232,0257,0334,0302,0303,0245,012,0315,0353,0260,'j',0221,0214,047,'7',0212,'5',0217,'X',0332,0256,0304,'t',0303,0323,0271,0345,06,0220,032,0225,0227,'w','6',0363,0302,0222,'*','8','R','/',030,0330,'%',02,';',010,0242,01,037,0215,'k',0261,0372,'l',0305,0273,'"','x','L','B',0250,022,024,0270,'9','=','H',0341,0210,0227,032,0225,0303,0263,',',0265,'%',014,0372,035,'M',0245,'(',0234,0325,'z',0361,'a',0233,',',0261,'P','M',0302,0346,'p',0257,0211,0223,'A','t',0241,'J',04,',',04,'O','x',0247,0244,0345,0312,'L',0320,0274,'e','E','d',0374,'P','T','I',0233,010,'B','a','v','-',0265,033,012,0302,035,'?','E','T','S','p',0234,0326,'+',0203,0226,0324,0346,'#',0231,0214,0322,0310,0250,0331,'_',0212,'e','s',0242,'Q',036,'P','~',0363,0272,'S',0304,0212,'&',']','F',0350,025,0272,'Q',0221,0306,0221,'r',0222,'E','A','?','F','^','a',0244,023,033,0245,0361,0335,0265,0177,05,'o',031,0313,0330,'5','^',0306,0320,0320,036,0304,0325,'j','6',0300,0235,0223,015,0270,'m',0252,0345,'I','e',037,'j','Q',0357,'0',0370,0200,'9',0205,0203,'>',0325,'4',020,';',0225,0243,0230,022,'9',0267,0243,'a',0260,0263,0254,0307,'Z','m','o','-','o',0367,0326,'i','r','v',0225,'j',0330,0326,'.',0267,0355,0312,'H',0226,'5',0272,0252,0231,'u','$','^','v',0344,0361,0305,0262,0344,015,'@',0304,0366,')','z','6',033,013,'J',0324,'m',0226,0312,0356,0323,'#',0271,0273,'u',']',0255,'O',0304,'E',' ','"',0212,'m',0222,0366,0234,'8','#','T','_',0276,'<',0203,0207,'.',012,0331,' ',0347,'x',0273,0210,0261,'(',010,'p',037,04,'k','.',0271,0265,']',0211,0347,037,'F','^','Y',0264,034,'}',0256,0322,0352,0327,047,0272,0267,'W','}','h','{','S',0244,'0',0251,0267,0367,047,'e','{',0345,0214,'`','!','^',0272,027,'J',0306,'*',0221,07,'N','Y',021,0300,'.',0330,0355,0315,0271,0233,'Q','t',0251,010,011,0226,032,',','d','W',')','@',0245,0364,034,'8','M',0242,027,0333,0242,0226,0311,035,0324,0232,03,0253,'b',0261,'Q','-','a','Y','{',0226,'9','n',0231,'u','(',0363,0234,0337,021,0252,0254,'o',0203,0220,024,07,'Q',0242,'M','~',0266,'$',0221,0226,'Q',0263,'r',0266,'J','J','E','(',0246,'t','+',023,';',04,047,0243,0225,'o',037,'b',0276,0352,06,':','V',0310,0243,'v',0351,0264,'C',0334,0230,0223,010,0346,0346,'0',0234,0322,'O',';','t',0376,020,'K',0254,0251,010,011,021,0304,0201,0372,0355,'_',0225,0177,0207,',',010,0276,0224,047,'L',0377,0,021,0354,0373,'d',0316,'r',0246,'K',',',0361,0246,0236,'U',0354,0216,'*',0362,0321,'R',0215,0346,0243,0374,0371,'>',0347,0370,0374,'v',0354,'u','@','5',0221,'t',0323,'*',')',0373,0216,0134,021,0242,017,0236,035,0373,0207,013,0225,0272,'J',0252,'e',0224,0370,0214,0377,0,0262,'?',0356,0235,'"','d','U',0323,021,'0',0266,'v',0360,022,'H','G',0210,0352,'-',0227,037,0213,0255,0207,0252,'o',0214,'a','r',0374,'~','K',0315,';','2',0204,04,'T',0304,0263,0211,0311,'-',0264,032,'R',0226,0311,06,0355,0323,'h',0207,0273,'?',')',0336,0256,'#',0300,037,0273,0356,0225,0371,'E','N',0222,0211,'(',012,0221,'T','J',0260,04,'Z','`','q',0340,'B',0250,'n','e','4',0301,0237,'t',0240,07,0,0266,'X','>',0245,0250,0217,035,0230,0252,0341,0367,'Q',0336,0134,0253,'m',0373,0271,']',0265,0212,0343,0233,'D',0264,'D','S','h','H',0377,0,'v',0305,')',0333,'%',0251,'W',0237,'(',0242,'e',0314,0234,'I','@',025,0211,016,04,'Q','V',07,'E',0372,'J',0350,'V',' ',03,0347,0340,'r',0351,04,014,0341,'T','Q','*',011,0311,0276,010,0310,0367,0257,025,0220,'u',0262,026,'Y','x',')','8','Y','t',047,'b',0374,'y',026,0321,0370,0324,06,0324,020,'Q',0322,0324,'z',0222,'U','8',0217,'v','E',0361,'c',0333,',',0261,0234,'*',0371,0337,'j',0220,0217,021,0320,07,021,'f',0330,033,0244,0243,0324,0222,'8',0177,0272,'~',0260,'.',0263,0226,'G','o',0362,01,0314,',','Z','v',0251,'&','C','*','v','P',0210,'%',035,'v',0252,0251,'T',0231,0333,0210,'-','=',0214,0217,0210,'G',0200,'_',0254,0243,'f',0260,0355,0304,'4',0376,05,0367,'L','`','!','f','$',0206,'E',0312,0207,04,0210,0345,0300,0271,'W',0342,'<',0234,0356,'V','7','"','Q',0355,0205,'e',037,'9',0355,0322,0217,'O',0252,0345,0311,0200,0210,'|','E',0262,0345,015,'W','b','z',04,0325,0312,0260,0225,0252,025,0303,'u',032,'/',0261,'%','N',0202,0264,0353,011,'l',0320,036,034,0245,'d',0372,':',0366,0332,'m','h',0366,0231,0306,0355,0323,'h',0207,0273,'e',0223,0345,015,'J','<',0352,0237,0345,0212,0235,'7','?',0275,01,'A','2','*',0222,0356,0227,'h',0330,033,047,'(',0343,0217,0304,'s','>',0341,'M','@','D',0367,0212,0374,0346,032,0237,'(',0355,0304,0226,'O',0251,0234,0360,0344,'i',0377,0,0277,0263,0355,0306,'u',0177,0307,'`','}',0331,'7',0345,0216,'j',0241,0314,0251,0344,0236,'v',0351,0374,0,'s',012,'Q','@',')',0270,'l','f',0306,'d',0374,016,037,017,037,025,020,021,0346,026,0350,031,0312,0251,'$','T','S',0216,'`','y',07,'(','"','F',0351,'|',0275,'f',0224,0203,'K',034,032,0265,0331,0235,0211,0250,'d','T',0253,'M',0226,0305,03,0276,0377,0,'=',0370,0375,'c','n','7',0255,0376,'C','c',0367,'D','@',0241,'1','"','2','.',0227,'X',0255,0322,'Y','S','.',0247,0304,'k','N',0,0351,0321,'[',024,010,0264,0201,0306,' ','x',012,0316,032,030,0357,0326,'8','~',0364,01,0314,',','Z','v',0251,'&',0231,0225,'<','T','q','c',0233,'m',0314,'U',0276,0372,'3','n',026,0235,0350,0275,0337,0231,0247,';',0271,0215,0270,0312,0277,0364,'U',0237,'v',0313,047,0312,']','H',0273,0356,025,0370,'H',0274,0352,024,'9','J','-',0224,'x',0345,'4',0301,'2',0352,'U','0',024,0276,'"',0231,0360,0370,0256,'E','t','I',0271,0313,'t',0335,0267,0261,'C',036,02,'k','d','$',0241,0341,'e',0333,0270,'#',0266,0373,'W',0134,0215,0220,0227,0221,'<',0274,0246,0312,'D',027,0344,'6','P',016,01,0356,'I',0276,',','{','U',024,'2',0252,'J',';',0351,023,0345,03,'r','*',03,0314,032,'z',0364,020,010,0342,0237,0247,',',0247,02,'j','=',0237,'r',0246,0240,'b',0273,0325,0274,031,0246,07,0231,'=',0270,0236,'c',0354,0352,0233,'r',0254,0277,0325,0324,0266,0341,'h','N',0204,0177,0273,'7','#',0366,016,0334,'.',015,0222,'Q','A','T',0377,0,011,0267,'Q',']','(',0325,'D',0264,0335,0372,0210,02,0222,'j',')',0246,0221,0346,'9',0216,'r',0242,'G',013,012,0352,0240,0211,0234,'*',0212,'E','A','6',014,0216,0375,0313,'v',0344,'j',0217,0202,0305,020,'Y',0350,'E','R','2','*','l',0303,'r',0335,0225,0217,'n','k',0223,0353,'K','l','M','3','*',0244,04,'Y','a','a','}',0313,'$',0227,'n',0206,0244,035,0367,'*',0374,'1','i',0334,034,0244,02,0,0207,035,':',0214,0343,0240,023,' ',0242,022,'d','1',035,0274,'3',0223,0,'q',0323,06,0235,0252,'D','(',0234,0321,021,0241,034,0333,0305,0223,0341,0376,0246,0333,0262,012,'H','a',0346,'J','`','9','v',']','d','>',0322,0327,0263,033,'E',0375,0255,0303,0334,'t',0344,0215,020,'t',0344,0356,0334,'J',0273,0351,0227,0341,'2',012,0207,'E',' ','A','5','^',0235,'U',0377,0,0374,0227,0367,0247,015,010,0340,034,'#',0320,'S','Q','L',0376,'+','q',0134,0205,0361,0346,0250,0276,0274,'F',0332,04,0217,0332,'T','>','f',0237,0204,0134,'@',0217,021,0331,0204,'c',03,0227,0334,0262,'I','w',013,0271,'p',015,0221,'9',0305,'C',0374,'F',011,01,'i',05,0272,'H','E','!',0376,'J',0257,0312,'X',0243,034,0305,'p',0360,0210,0220,0306,023,0231,0213,'N',0351,'P',016,'P',0204,0213,0373,07,0,034,03,0307,'p',0214,0373,0212,0316,0334,047,'#',0326,0207,0371,0312,0217,';','J','^',0334,'a',035,0365,0364,0337,')',0327,'M','=',014,0223,'@',0327,0331,0264,0321,024,'"',0241,0342,0233,0221,0372,0366,0232,0220,'u',0334,0255,0360,0315,0267,'r',0253,0250,0361,'G','G','T',0312,03,037,0372,0256,0231,025,0310,0244,0221,'P','M',0321,0371,0327,'M','1','T',0355,0233,0203,'d',0232,'5',';',0305,0331,0264,'#','&',0376,'O',0336,0254,'1',0377,0,'U','9',0263,013,'<',024,'l',0177,'9',0275,0347,',','~',0300,016,'#',026,0314,0261,0361,0236,047,'.',0321,'h','G','v',0255,'/','*',0355,0316,0304,0225,':',07,0203,0233,0357,'|',047,'0',020,0262,'o',0206,'A',0334,0253,0276,0231,'>',012,'Q','9',0242,0322,024,0302,'M',0327,'(','i',0203,0340,'H',01,'b',010,'=',0220,016,']','F','3',0350,0223,'P','Q','}',0202,036,'l',0264,0313,0264,0271,0354,0307,'n',0373,'+',0237,0316,'m','w',0317,'5',0262,0254,0324,'^','Y','<','*','(','T',0211,'#','g',0322,0253,035,'s',0376,0264,0264,0242,')','i','I',0205,'M',0241,'~',0340,'t',0234,0223,0202,013,'7',0344,'u',0244,0324,'2','J','4','p',016,0333,'o',0263,0310,0362,021,0302,0300,0335,'%',024,025,'O',0361,030,0327,0224,0272,'|',0331,'B',0253,0262,'1',0237,'X',0372,0256,'E','u','O',0347,0316,015,0200,0257,'6','C','8',06,'r',0377,0,'9','u','p','Z',0347,0263,030,'7',027,027,'o',03,0371,024,0243,0222,0220,0224,'Z','D',0372,'u','$',0232,032,']',0332,0256,'v',0224,0302,'C','3','s',0335,'#','U','u',0316,0206,0347,0216,0212,0315,0262,0353,0231,0312,0322,'N',0373,0205,'[',' ','.',025,'Z','=','5',023,'9','y',016,0331,0351,0333,0351,07,'$',0134,04,'8',0203,0250,0336,':','1','D',0203,0246,0315,0305,0312,0251,0246,011,022,'*','8',0322,'.','S','!','R',047,0237,'6','#',0315,01,0265,0222,0235,'f',0177,031,'(',0374,0367,'}',0230,'l',0234,0326,0355,0362,'/',0311,034,0335,0323,0245,036,',','s',0202,'e','y','&','e',0274,021,0213,0364,0134,0302,':',0355,'$','w','Y','$','{',0207,022,0216,0372,')',0200,'q',026,'M',0273,'t',0344,035,'t','S','j',0330,']',035,0313,'C',0267,022,'(','d',0314,0326,'H',017,0257,0336,0244,0325,')',0324,0,0342,',','Z','v',0251,'$',0221,0226,'R','1',0201,'c',0233,'z',031,'q','.',0245,'3','m','M','Q','^',0257,0361,0177,'7','5',0313,'f',023,'K',0215,0217,'|',0313,0376,0375,0351,0214,04,'+',0327,0242,0350,0376,0,0377,0,'4',0335,'^',0262,'1',0256,0273,0306,';','&','d','>',0275,0232,0353,02,'D','Y','Q',']','H',0306,0274,'E','e','A',024,0316,'c',':','Y',0253,'p','n',0224,0233,0236,05,0321,0321,':','Z','I',0362,0211,023,0367,0250,0246,'|','~','+',0221,'}',04,0375,034,0250,034,'h',0333,'i',03,0306,0241,0361,'s','0',0236,0333,0263,010,07,0376,0323,'t',0212,0242,0213,015,'L','8',0340,036,'(','e',0270,0222,0252,0363,0201,0276,'D','x',04,0304,0207,0330,'<',0224,'u',0325,'P',0234,'9',0220,'1',014,0231,0212,06,04,0231,'&',0212,0256,0227,06,0351,034,0342,0241,0243,'Z',0365,014,0340,011,0322,037,0333,'&',0242,0351,'`',0,'(','A','E',0367,0356,'=',',',0234,'P','5',033,'m',010,'x',0323,0276,'/','e',0344,0270,'l',0302,'J','p',0234,0335,'*','^','x',0335,'I',017,027,0276,'&',013,'t',']','4','p','-',034,0220,0340,0241,'>',',',0262,'=',04,'$',']','v',0310,0374,'"',0271,0320,'3','W',0344,'_',0341,0323,'R',0271,'/',0327,0251,0327,'L',0200,0221,'$',0235,'u',014,'R',0211,0314,0321,0260,'5','E',0243,'S',0274,'p',0321,0251,031,0267,0364,0262,0230,0377,0,0360,0273,'h',0301,0302,0241,0361,0221,'I',0311,'u',0331,0206,015,0313,'l',0334,0241,':',0204,'1','D',0206,0224,'/','+',0317,033,'5',0272,0355,0353,'/',0272,0315,0264,0365,0331,031,'7','x',0354,'W','Q',0323,0201,'r',0267,0317,0353,'M','d',0204,0232,'!',0301,'@',0324,0203,0256,0202,'z',0212,'i',0310,']','A','E',0366,015,0375,'<',0260,'~','Z','N',0332,'i','y','*',0177,031,'U',0277,'F',0355,0263,023,0271,0355,0356,0233,0347,020,0350,'I',0315,047,0377,0,'?',034,':',0374,0252,'2','v','v','N','P',0221,'A','v',0323,'R',0243,'"',0264,0263,0256,'#',0271,07,047,'n','d',0344,0223,'2','K',',','+',0251,036,0323,0271,'W','U',0310,0276,0272,0236,0246,'h','p',')','U',0366,0304,' ',015,0242,0276,'3','C','a','N',0315,0262,0216,0357,0262,0267,'o',0266,'!',0301,'Y','T',0371,0332,'x',0323,'8',0244,0242,'J',02,0311,0351,0343,0236,0325,021,036,'a',0360,'$',0231,0226,'Q',0272,05,'n',0224,'k',03,'H',0272,'I','"',0242,0237,0251,0234,']',010,047,0261,0243,'q','x',0354,0245,0345,'/',0306,'q','l',';','Z',0270,'3','G','H',0250,013,'%',0272,0302,0337,0257,030,0251,':',0251,010,'p',037,034,'c',0320,'D','V','x',0222,05,'t',0344,0316,0224,0360,0305,0264,0350,0246,'R',0211,0315,023,034,021,0315,'}',0134,0312,0363,0257,'h',0331,'K','h','/','m',0237,'9',0205,0227,'s','R',0333,'D','~',022,'5',015,0307,' ','(','E',0222,024,026,0221,'K',0244,0357,0326,0215,'i',0334,'+',0252,0324,'_',017,'^',0362,0370,'$',0255,0333,'1',013,'0','u','p',0371,0271,'0',0373,':',0266,0334,'+','%',0327,0203,0337,'d','o',0321,0221,0231,'K',0376,'>',0252,')',012,0312,' ',0210,' ',0224,'<','h',0310,0272,')','@',0245,0365,'e',0237,026,'2',',',0306,023,0233,'f',017,'b','<',0277,'"',034,0301,'6',0303,0352,0346,'6','b',031,'N',0306,0327,0276,0320,0333,0250,0311,0352,']','f',0336,0254,'c','N',0212,'i','$','e',0324,0215,'b','X',0366,0276,0266,'^',0223,0354,'j','{','q','d','w','a','M',0331,0227,0242,0373,033,'^',0310,0267,0347,0213,0222,'l',0340,0216,0333,'n','r',0200,'9','n','b',0211,014,0361,'.',0213,0237,'N','1',0247,']','M','V',0342,0372,')',0372,0371,0226,'c',0274,0260,'l','l',0334,0356,0334,'G',0263,'$','s',015,0231,0236,'+',0272,0201,0333,0211,0346,0276,0322,0255,0276,0302,0333,0267,0222,0231,'K',0375,0364,0221,'H','W','Q',024,0212,0202,'p','q',0235,0373,0237,']',0323,0224,0331,0266,0227,0221,'<',0274,0246,0314,'_',025,0366,0227,015,0263,0221,0205,0231,0207,'U','#',' ',0256,0314,'O','9',0365,'V',0215,0366,0226,0335,'F',0217,0222,0353,'5',0364,0243,032,'t',023,'l',0334,0356,0227,'d',0320,0214,'[','z',0371,'v','s',0353,'k',0233,'p',0264,'?','o',021,0273,'(',0302,'}','=',0257,'b','J',0231,05,'j',0363,'e',0261,'@',0356,'t',0200,':','l','r',0211,014,0361,036,0203,0217,'B','1',0247,']',']','W',0243,';','D','=',0214,0215,'?',0367,0366,'}',0210,0242,'w',013,'@','E',026,022,033,'v','^',0203,0373,'*',0346,0334,'9','d',0355,'$','7',0330,0332,0366,0362,023,'(',0377,0,0236,'t',0222,025,0224,'A',020,'A','*',0374,'g','z',0343,0330,0310,0226,'?',0307,'+',0233,'q','<',037,0332,0332,'7',0270,'n',0233,0266,0366,030,'s',0300,'M','l','j',0345,'F','N','k','S',0251,'X',0341,'w','Y','Z',0365,0330,'9','K',0256,0207,0236,'-',0247,'I','6',0215,0216,0361,0303,'F',0304,'f',0337,0330,0311,'V','o',0310,0354,';','q',0215,0177,0350,0353,036,014,0317,']',0352,'#',0267,023,0332,0276,0232,'_','r',0211,0202,0251,0270,'D','[','/','$',0207,'E',0317,0226,'9',0247,'r',0256,0253,0361,0235,0223,0177,'c','(','Z',0276,0202,017,'m',032,0274,'6','[',020,07,0,0360,'H',0260,'J','Q',0204,0314,'Z',0260,0222,0233,'?','Z',0307,026,0337,0311,0241,'w','Z','Y',0362,'-','(',0207,'Y',0277,0221,'2',012,0207,'l',0200,'6','J',0275,031,0335,0257,0354,'>','z',0214,'k',';','=',0201,'k','4',0316,0334,'S','[',0372,'h',017,026,'a',0253,0367,'L',0366,0326,'l',013,0326,'f','#','$',0220,0227,'a',0266,'E',0240,'>','f','b',0362,0213,0306,0375,0262,0376,'8',0246,0234,0205,'f',0320,0357,0134,'6','n','F',0210,'{',031,'b',0345,0366,'N',0366,0320,'+',03,'g',0237,0,02,0207,0211,0303,'t',0335,0241,'o',0255,0251,'W',0233,0333,0215,'/',037,0216,0275,01,0342,033,'l',0254,':',016,0244,'Z',0367,010,0370,0230,'4',0356,0225,0324,014,'g','b',0337,0330,0311,'w',0177,0307,030,0210,0361,035,0205,'(',0234,0324,012,0267,0342,0320,'^','L',0211,'S',013,'D','!',0212,'%',035,0270,0266,0375,0326,015,0257,0232,025,0363,'U',0320,';','e',0244,0243,0307,0216,0377,0,0336,0233,'E',0250,0256,0222,'H',0250,0222,0275,020,'+',')',0354,0134,'m',0255,0352,'Q',0222,'2',013,0313,'>',0333,0210,0352,'?','`',0367,0315,0226,'i',0235,0203,0215,0245,'0',0220,0330,0343,'!',026,'y','=',0263,'p',0377,0,'`','C',0220,0311,0231,'V','(','*','#',020,0200,0353,0351,0222,0327,0323,047,0257,0245,'&',0202,031,'=',026,'%',02,0351,'4',023,'G','M',0243,0334,'<',030,0372,0311,022,020,016,01,0353,0330,0354,'m','+',021,0266,'+',013,0253,'4',0236,0332,0275,'u','{','<',0304,'t','z',021,'L','|',0317,032,'$',0375,0255,0322,0250,0265,'J','[','j','J',0235,05,'1',0366,'F','%',0204,0273,']','G',0267,'y',0243,0325,0331,0233,'_',0211,0241,0257,0304,0322,0320,0324,0213,0257,0304,'t','Z',0222,'z','N',0256,0320,0272,'B','%',0233,0177,'j',0307,'c','g','X',0216,0263,0331,0335,0332,0244,'v',0267,'n',0243,0265,0350,0225,04,0352,'q','>',0205,0252,0266,0336,0323,021,'-',024,0346,021,0376,0322,034,0311,0236,0203,0223,0311,'#',0374,'k','e',0305,0225,'I',0235,0206,0304,0362,0315,'!',0273,026,'Q','~',0265,'/','J',0375,'I','N',0330,0301,0313,'e','Y',0257,0272,0215,0225,024,0216,0323,'w',011,';','C',0370,'W','|',0224,0332,0270,022,'2','N','e',0235,0356,0305,0364,036,0375,'O','S','"','P',013,'d','A','D',0314,0212,0233,0252,0227,0211,032,0242,0265,0233,0204,'u',0251,0277,0276,0361,0352,021,0315,0356,'y','e','i',015,010,0211,0207,'v','9',0307,0306,0237,'T',0204,'*','d',0365,'r',016,'9','%',0210,0253,0240,0243,'e',0267,'5','t',0263,047,025,'<',0303,0246,0216,0320,'|',0207,0271,'j',0311,0261,0225,0355,'X','-','2','6','w',033,0361,0366,'9','=',0200,0310,0242,'F',0351,'z',0367,0254,'z',0205,0245,047,0361,0356,'"',0335,0357,0202,0263,'H',0326,0334,'V',0362,0373,011,035,'"',0262,'n',022,0366,',','y',02,'"',0265,0253,'6','M',0225,0260,0370,'h','8',0300,0362,02,'B',025,'2','{','6',0352,'c','+','k','K',035,'a',0365,']',0357,0202,026,0315,047,'^','V',07,'4',0242,0240,'E','O','G',0316,'%',0351,0256,0272,'m',0222,0234,0313,'P',0321,'z',0260,'d',0271,0251,0337,012,010,'(',0351,'j','.',',','$','p',0373,0222,0261,'-','&',0331,0134,0261,0223,0312,0357,0211,025,0324,'l',0254,'>','U',0235,0213,0324,'V','h',0214,'s',0250,0313,'L','L',0300,'y','^','H',0265,0216,'N','S',',',0300,0307,'j','c','3',0311,':',0324,0234,0333,0371,0245,'<','5',0352,0304,0205,0231,0335,'>',0204,0306,0246,0227,0277,'p',0305,015,'e',0306,'V',035,0344,'#',0277,034,'u',0236,'Z',047,'L',0362,0365,0201,0251,'Z',0347,023,'q','o',0232,'a',0224,022,'e',0212,0331,0364,0226,'K',0255,'-',0240,0277,0327,0207,'J','d','Z',0342,'`','|',0253,'Z','.',0234,0346,'8',024,'A',0336,'p','n',']','<',0315,'2',0353,031,0375,0376,0301,'$',012,0252,'u',0324,0361,024,0242,'s','T','q','+',0251,'-','G','F','5',0210,'i',0374,031,0210,'6','3',0315,'m',030,0205,0354,'v',0216,'C','$',0177,0340,'V','h','r',0266,0203,'U','q',0364,'e',0134,'?',0213,'b',0245,'E','Y',0313,'d',0304,0362,0220,0372,'9',014,0231,0275,0312,0375,'.','Z',0312,'j',0336,'%',0213,0211,0321,'J',04,'/',0362,047,'*','Q','V','"',0317,'a',0207,0215,0265,'%',020,0366,035,'o',']','4',0314,0261,0340,0361,0134,0334,0276,0253,0370,0266,032,023,'@',0,'P',0376,'c',0246,0210,'=','F','c',021,0302,'H',0352,'_',017,0314,0261,0324,0204,'C',0350,0243,0372,')','"','w',012,'E','c','K',04,0256,0241,0360,0253,'D','u',021,'[',0214,0202,047,0364,0224,'L',0252,0226,'C',035,0327,0244,0265,'!',0204,'Z',')',0247,0230,'j','m',01,'y','C',0260,'1',07,'1',0316,0331,'x',022,'E','G',07,'k','R',0232,'x','f','X',0232,0304,0357,'L','0',0201,0304,'c',0261,'=','}',0216,0230,0305,0263,0213,'O',0373,'B',034,'t',0274,'K',027,'@','z','d',021,0364,'4','*',0361,0264,'8',0346,0266,'a','.','?',0256,0227,'D',0244,'@',023,'M',0353,0261,'M','4','D',0210,0220,0177,07,0377,0304,0,'5',021,0,02,01,03,02,05,02,05,03,03,03,05,0,0,0,0,01,02,03,0,04,021,05,022,020,023,'!','1','P','"','0',024,' ','2','A','a','@','B','Q',06,'#',0201,025,'3',0221,'$','D','b','p',0240,0377,0332,0,010,01,03,01,01,'?',01,0377,0,0320,0305,0202,0367,0243,'p',0202,0215,0327,0360,'+',0342,'[',0370,0257,0210,'z',0370,0207,0257,0210,'z',027,047,0356,')',0134,'8',0310,0363,0317,':',0257,'j','i',0335,0275,0233,'n',0347,0316,';',0204,031,'4',0363,'3',0373,'q',0246,0305,0307,0233,0222,'A',030,0246,'b',0307,047,0333,0267,0217,0367,0237,'6',0356,020,'d',0323,'1','c',0223,0355,0303,026,0363,0223,0333,0315,0222,024,'d',0324,0216,'d','9',0366,0343,'B',0347,024,0240,'(',0300,0363,'s','K',0274,0364,0355,0355,0250,',','p','*','4',010,'1',0346,0347,0227,'>',0221,0356,'C',026,0301,0327,0277,0233,0236,']',0276,0221,0356,'A',026,'=','G',0315,0313,047,',','Q','9',0352,'}',0270,'"',0335,0352,'=',0274,0333,'0','A',0223,'N',0345,0316,'O',0267,024,'|',0303,'@','c',0240,0363,'r',0311,0314,'?',0217,'m','T',0271,0300,0244,'P',0203,03,0315,0317,'.','}',03,0334,0212,'>','X',0374,0371,0271,0244,0330,'0',';',0373,0220,'E',0217,'Q',0363,'n',0341,06,'M',0134,0334,010,0224,0313,'%','Y',0353,'I','+','m',0227,0245,02,010,0310,0366,'`',0213,'q',0334,'{','y',0262,'q','R',0311,0314,'5',0255,'A','q','2',016,'_',0322,'(',0202,'*',0307,'U',0226,0324,0341,0272,0255,'[',']',0305,'t',0273,0220,0374,0361,0307,0314,'8',0240,'0','0','<',0334,0362,'g',0322,'8',0353,026,0366,0240,'o','=',033,0204,'3',0311,03,'n','C','V',':',0302,'O',0350,0227,0241,0256,0377,0,'"',0251,'c',0201,'H',0201,06,07,0233,0232,'M',0203,03,0277,033,0211,0204,021,0231,017,0332,0246,0231,0356,0245,0334,0337,'z',0264,0322,0241,'K','}',0262,014,0223,'W',0332,'<',0226,0376,0270,0272,0212,0352,'*',0307,'W',0222,0337,0321,047,'Q','Q',0270,0221,03,0216,'0',0307,0260,'d',0367,0363,'n',0301,06,'M','3',026,'9','<','u',0214,0374,'#','b',0221,0266,'0','j',0264,0270,'K',0210,0203,'/',015,0134,'F','.',0266,0306,'+','N',0323,036,'Y',0277,0272,':',012,03,03,03,0204,021,'~',0363,0347,'%',0223,'y',0371,'&',0210,'M',031,'C',0367,0253,0253,'v',0266,0220,0243,'U',0265,0334,0266,0255,0230,0315,'6',0277,')','L',01,0326,0223,'t',0362,0214,0367,'5',032,0355,'@','8','E',036,0363,0370,0363,0227,022,'~',0301,0306,'y',0322,0335,'7',0271,0251,0277,0250,033,'8',0211,'j',015,0177,0256,'%','Z',0226,033,'m','R','<',0212,0271,0321,0256,'!','>',0221,0221,'B',0312,0341,0216,02,'V',0227,0245,030,017,':','n',0374,021,'K',0234,012,'U',010,'0','<',0334,0262,'l',034,'I',0300,0311,0255,'N',0364,0335,'J','@',0372,'E','A',0244,0334,0316,0234,0300,':','S','.',0326,0333,'Z','M',0261,0265,0200,0334,'=','Y',0352,'0',0335,0364,035,0376,'H',0243,0345,0217,'6','N',0321,0223,'N',0345,0316,'x',0352,'r',030,0255,'X',0212,0263,'A','-',0302,0253,'V',0255,'z','-','b',0344,0307,0334,0326,0225,'c',0361,'R',0357,'o',0244,'V',0251,'0',0202,0330,0326,0235,033,'I','r',0241,'x',0301,026,'=','g',0316,'O','&',0343,0264,'|',0232,0214,'F','k','f','Q','@',0230,0333,'#',0275,027,'{',0251,'r',0347,0275,'C','-',0255,0214,0,06,0255,'F',0374,0336,0311,0323,0351,025,0241,0331,0362,0327,0236,0375,0317,010,'c',0336,'r','{','y',0311,0244,0330,'0',';',0361,'$','(',0311,0253,0215,'w','d',0273,'c',031,025,'k','w',035,0342,'n','J',0324,0364,0226,0317,'6',012,' ',0251,0301,0256,0247,0245,'i',0272,'S',0314,'y',0222,0214,012,0,'(',0300,0244,'B',0347,02,0225,'B',0214,017,'6',0314,020,'d',0323,'1','c',0223,0307,'Z',0277,0377,0,0267,0217,0374,0326,0237,0247,0265,0343,'d',0375,'4',0322,'[','i','q',0342,0227,0372,0202,'"',0330,'+',0322,0276,036,0322,0371,'w',0343,'5',036,0235,'m',021,0312,0257,016,0365,024,'|',0261,0347,'&',0223,'y',0300,0355,0306,'W',0330,0205,0252,'G','2',0310,'Y',0276,0365,0361,'v',0372,'u',0250,011,0324,0324,0367,017,'p',0373,0334,0326,010,0255,02,'f',0346,'4',0177,'n','0','G',0373,0317,0234,0236,'M',0243,'h',0371,047,'N','d','l',0265,'"',030,0334,0253,'V','s','Z','^',0226,'g','<',0331,'{','V',0267,'$','[',0304,'Q',0375,0253,0372,'~',03,0226,0224,0360,0206,'=',0347,0257,'o','8',0354,020,'d',0321,'%',0216,'O',031,'n','a',0203,0375,0306,0305,'E','w',014,0337,'C','U',0336,0231,05,0331,0334,0335,015,'C',0242,0333,'B','w',0267,'Z',0277,0325,0243,0201,'y','p','w',0250,'b',0222,0356,']',0243,0271,0253,'h',026,0332,'!',032,0322,')','s',0201,'J',0241,'F',07,0234,0232,'M',0347,0361,0307,'R',0277,'[','8',0377,0,0362,'5',',',0317,'3','n','s','I','#','F','r',0246,0254,'5',0254,0342,';',0217,0371,0246,011,'p',0230,0373,032,0272,0320,0344,022,0177,'g',0250,'5','a','`',0226,'i',0371,0341,024,'{',07,0347,0316,0134,'I',0201,0264,'q',0222,'A',022,027,'5','w','p',0367,'s',026,'5','m',0246,'C','m',07,':',0344,'f',0212,0363,0244,0304,'b',0231,'J',034,'5','Y','j','R',0332,037,0344,'U',0264,0342,0346,'!',' ',0373,0360,0267,0217,0367,0237,'8',0357,0260,'f',0211,0311,0311,0343,0254,',',0315,'o',0266,'*',0321,0355,'y',0267,031,'a',0332,0265,0353,0242,'1',02,0326,0203,'k',0234,0316,'k','_','X',0327,'n',07,'Z',0263,0322,0344,0236,'E',0334,'=','4',0252,021,'v',0255,'E',037,'0',0371,0331,0244,0336,0334,'o',0356,0305,0234,'%',0376,0365,'c',0253,'G','u',0350,'~',0215,'I',012,'F','I','Q',0336,0265,'r','M',0333,'f',0254,'5','V',0263,'B',0204,'f',0256,'.',036,0366,'m',0315,'V',0221,0362,0340,'U',0240,013,034,012,'D',010,'1',0347,047,0223,'h',0332,'8',0263,04,033,0232,0265,0331,0204,0201,'6',0236,0225,0242,'X',0347,0376,0241,0377,0,0307,015,'W','L','7','_',0335,0217,0352,0243,'e','p',016,0322,0225,0246,'i',014,0254,'&',0237,0204,021,0355,033,0217,0215,'i',0321,'h',0334,0261,0355,0134,0347,0376,'h','N',0343,0357,'Q',0312,'$',0366,0335,0202,014,0232,'b','X',0344,0361,0327,'/',0211,'?',016,0237,0346,0267,023,0320,0326,0233,'w',04,0261,04,'O',0267,0313,04,'{',0216,0343,0343,036,'u','N',0324,0362,'3',0367,0371,'A',0307,'Z',0215,0367,0256,'}',0251,0244,0336,'p','*',0356,0345,'m','b','2','5','[',0353,'3','$',0231,'~',0240,0324,'m',0275,'C','U',0346,0237,025,0330,0353,0336,0256,0354,'%',0264,'>',0241,0322,0221,0332,'3',0271,'M','X','k','Y',0376,0334,0377,0,0363,'J',0301,0306,'W',0202,'!','s',0212,0,'(',0300,0361,'D',0201,0324,0324,0223,0226,0350,0276,0304,017,0265,0261,0354,0317,'&',0321,0264,'Q','8',031,'5',0253,'_','|','T',0273,'W',0351,025,0243,'X','s',0337,0234,0375,0205,'^',0336,'%',0224,'{',0232,0255,'/',0242,0273,0134,0241,0353,'O',032,0312,0273,0134,'U',0376,0212,'W',0327,05,'2',0225,'8','5',0243,'A','$','P',0356,0220,0367,0341,024,'{',07,0212,047,025,',',0246,'C',0370,0366,0221,0267,'(','?',';','0','Q',0223,'L',0305,0216,'M','k','W',0374,0245,0344,'F','z',0232,0265,0267,'k',0251,'D','k','Q',0244,'v',0220,0340,'v',025,0250,'^','5',0344,0333,0276,0337,'j',0320,0354,'N','~','!',0377,0,0307,010,0346,0216,'_',0240,0346,0247,0323,0240,0235,0303,0260,0353,'@','c',0240,0253,'x',0377,0,'y',0361,'w','/',0373,'}',0273,'f',0351,0267,0347,0236,'M',0307,'h',0247,0335,0264,0355,0357,'W',0261,0316,0223,036,'x',0353,'Q',0310,0321,'6',0344,'=','j',0343,'U',0226,0342,036,'S','V',0237,'f','o','&',0333,0366,0244,'A',032,0205,'Z',0326,'/',0276,036,'>','R','}','F',0254,036,'~','x',020,0236,0264,'3',0216,0265,024,'|',0306,0256,0336,'.','o',0367,017,0267,023,'m','q',0363,'M','&',0305,0343,'=',0264,'w','+',0266,'A','W',0332,'D',0226,0336,0270,0372,0257,015,'?','P','k','&',0374,032,0377,0,'T',0200,0300,'f',06,0247,0231,0256,'d','2','7',0336,0264,'{',017,0207,0217,0232,0343,0324,'h',014,0364,025,032,'l',0134,'x',0311,0307,0257,0334,0215,0267,0256,'~','B','p','2','i',0337,'{','g',0344,0357,'W',0372,'2','O',0353,0207,0241,0251,'a',0222,06,0333,' ',0307,015,036,0303,0342,'$',0346,0277,0322,'8','[',0307,0217,'Q',0361,0267,'#',0250,'>',0345,0263,'`',0355,0371,'.','$',0375,0203,0347,0271,0264,0212,0351,'v',0310,'*',']',022,'d',0230,'*','u','S','P','@',0266,0361,0210,0322,0241,0217,'y',0374,'x',0353,0201,0224,0367,01,0332,'s','J','w',014,0216,022,'>',0305,0315,'w',0366,'U','K',034,012,'E',010,'0','<','s',015,0303,036,0354,022,0355,0364,0232,'i',025,'{',0324,0216,'d','9','>',0324,021,0355,033,0217,0220,0231,'v',0271,0375,'<',021,0357,'9','>','F',0345,'{','7',0351,0225,'K',034,012,'U',010,'0','<',0214,0253,0271,010,0375,'4',021,0355,031,'>','N','E',0332,0304,'~',0222,010,0367,034,0237,')','r',0275,0233,0364,'j',0245,0216,05,'*',0205,030,036,'R','U',0334,0204,'~',0216,010,0366,0214,0237,'-','"',0355,'b','?','C',04,'{',0216,'O',0227,0271,'^',0315,0372,05,'R',0307,02,0225,'B',014,017,'.',0353,0271,'H',0375,04,021,0355,033,0217,0231,0231,'v',0277,0275,014,'{',0317,'_','5',':','n',0134,0373,0240,'n','8',024,0213,0260,'c',0315,0310,0233,033,036,0345,0274,'x',033,0217,0234,0232,'=',0353,0323,0333,0212,'=',0347,0361,0347,0246,0207,0367,'/',0262,0220,'3','w',0245,'P',0243,03,0317,0264,'H',0335,0305,'|',':','W',0303,'-','|','2',0377,0,'5',0360,0303,0371,0257,0206,'_',0346,0205,0272,012,010,0253,0330,0177,0360,0311,0377,0304,0,'4',021,0,02,01,02,04,04,04,05,04,02,02,03,0,0,0,0,01,02,03,0,04,021,022,'!','1',05,020,023,'P',024,'0','2','A',' ','"','@','Q',0201,025,'#','B','a','3','C','R','b','p','q',0240,0377,0332,0,010,01,02,01,01,'?',01,0377,0,0300,0317,'*','E',0253,0234,')',0370,0235,0272,0354,'q',0246,0342,0343,0370,0245,036,'-','/',0262,0212,0375,'R',0343,0372,0257,0324,0356,'~',0364,'8',0245,0307,0365,'I',0305,0337,0371,0255,'C',':','N',0271,0223,0277,'O',0304,0241,0213,'E',0324,0324,0274,'B','y','v','8',017,0352,0211,047,'S',0344,'p',0200,'s',0261,0366,0357,0223,0334,'%',0272,0346,'z',0271,0276,0226,0343,'M',0207,0224,01,047,01,'V',0220,'x','x',0202,0373,0367,0273,0253,0245,0266,0134,'N',0365,'$',0257,'3','f','s',0345,0360,0333,'O',0367,0277,0343,0275,0334,0134,'-',0272,'g','j',0226,'V',0231,0313,0277,0227,'c','i',0342,033,'3','z','E','m',0336,0244,0221,'b','R',0355,0265,0134,0334,'5',0313,0346,'>',']',0265,0273,0134,0276,'Q','Q',0306,0261,'(','E',0333,0275,023,0200,0304,0325,0365,0337,0210,'l',027,0322,'<',0270,0343,'i','X','"',0357,'V',0326,0353,'l',0231,'G','{',0342,'7',0231,0377,0,'f','=',0275,0374,0260,'1',0320,'U',0215,0247,0207,0134,'[',0324,'{',0337,021,0274,0351,016,0222,'n','|',0316,035,'g',0227,0367,0244,0374,'w',0273,0313,0241,'l',0230,0373,0373,'S','1','s',0231,0274,0276,037,'g',0326,'=','G',0364,0367,0271,0245,'X','P',0273,'T',0363,'5',0303,0227,'o','.',0316,0324,0334,0276,036,0324,0252,020,'e','^',0364,'H',03,023,'W',0267,'F',0345,0364,0364,0217,'.',030,0232,'g',010,0265,04,'+',02,04,'^',0367,0304,0256,0363,036,0212,'~','|',0260,011,'8',012,0262,0265,026,0311,0257,0250,0367,0273,0373,0276,0202,0344,'_','Q',0363,'8','u',0236,'A',0326,'}',0375,0273,0335,0304,0353,'o',036,'v',0251,0347,',','L',0262,'T','w','X',0350,0325,0277,0223,0303,0354,0372,0315,0324,0177,'H',0357,'l',0301,'F','c','W','w','&',0346,'L','}',0275,0252,0351,']',0266,0333,0224,'S',0264,'u',034,0253,' ',0323,0343,0264,0266,'7','/',0227,0333,0336,0221,'B','.','U',0333,0275,0361,'+',0274,0347,0242,0233,'{',0363,0271,'D',032,0373,0362,014,'W','Q','Q',0134,0343,0243,'|','1','F',0322,0270,'E',0336,0255,0340,'[','t',0310,0275,0357,0210,']',0364,023,'"',0372,0217,'7','|',0213,0215,'1',',','q','5',035,0272,0344,0371,0252,'[','v','M','G','(',0247,'d',0322,0225,0263,014,'y',0330,'Z','x','t',0314,0336,0243,0336,0347,0231,'`','B',0355,'R',0310,0323,'9','v',0347,'u',0376,'>','Q','8','u',0323,0224,0370,'g',0322,0241,0204,0273,'k','[','r',0341,0266,0230,0376,0373,0376,';',0331,'8','j','j',0366,0353,0304,0276,0236,0221,0360,':',0347,0134,')',0224,0241,0300,0322,0271,'C',0210,0243,'t',0344,'a','[',0232,'Q',0200,0303,0225,0215,0257,0211,'|','O',0244,'P',030,'h',';',0337,023,0273,0377,0,'B','~','y',0273,0204,030,0232,'k',0263,0355,'K','v',0177,0225,'2',0245,0300,0322,0236,0335,0322,0262,'7',0332,0240,0267,'*','s','7','(','a','i',0334,'"',0324,'1',',',010,021,'{',0335,0355,0317,0206,0217,'M',0315,023,0216,0247,0226,0325,'4',0235,'F',0245,0201,0330,'b','9','[',0246,'E','2',032,0216,'u',0223,0230,04,0234,05,'Y','Z',0213,'d',0327,0324,'{',0333,0272,0306,0245,0333,'a','W',023,0265,0304,0205,0317,';',0203,0204,'f',0220,'b',0300,'U',0304,0231,06,'E',0250,'"',0352,'5',0134,'6','X',0360,0250,0306,'g',03,0237,015,0264,0313,0373,0357,0370,0357,0234,'J',0353,0252,0335,'$',0330,'|',023,0256,'h',0315,'m','X',0226,':',0322,'4','q','&',0365,',',0246,'S','V',0261,0341,0363,0236,'V',026,0235,'w',0314,0336,0221,0337,'8',0205,0327,'A','2','/',0250,0363,047,012,'{',0277,0233,0345,0250,0344,022,0215,'*','{','r','>','e',0347,014,05,0316,047,'j',03,012,0202,06,0270,'p',0213,'Q','F',0261,' ','E',0357,'s','L',0260,'!','v',0251,'e','i',0234,0273,'s',0271,0227,037,0220,'T','Q',031,015,023,035,0270,0257,030,'>',0325,0222,')',0206,'4',' ',0215,'}',0271,0,'I',0300,'U',0235,0250,0266,'M','w','=',0362,0376,0353,0304,'>','U',0364,0216,'l','r',0251,'4','N','&',0272,0211,014,'x',015,0351,0230,0261,0304,0362,0264,'o',0233,016,'|','6',0323,017,0337,0177,0307,'|',0342,'W',']','5',0351,'.',0347,0340,'q',0231,'H',0242,'0',0345,04,031,0365,';','U',0311,0134,0330,'-','Z','.',0271,0271,'X',0332,'x',0207,0305,0275,'#',0276,0134,'L',0266,0361,0227,'j',0221,0332,'V','.',0333,0236,'m','"',0246,0346,0226,'T','m',0215,'I',02,0311,0255,'-',0252,'.',0246,0245,0270,012,'2',0245,'(','.','p',0250,0323,0246,0270,'T','0',0264,0356,021,'j','(',0226,024,010,0275,0362,0372,0353,0304,'I',0200,0364,0216,'s',0315,0323,032,'o','D',0223,0251,0255,0252,'+',0237,'g',0243,0204,0213,'O','j',0300,0374,0265,014,'"','1',0375,0320,030,0350,'*',0312,0327,0303,'&',0276,0243,0337,'8',0235,0326,'E',0350,0256,0347,0233,'6','Q',0215,';',027,'l','M','$','*',0211,0235,0353,'s',0247,'(',0346,'h',0366,0250,0337,0250,0271,0271,'p',0313,'O',0367,0277,0343,0276,0134,'N','-',0343,'.','i',0334,0310,0305,0233,'~','w','Y',0262,0351,'V',0351,0231,0352,0355,0377,0,0205,'Z','&',047,'5',']',0205,04,'a','Q',0302,0134,0320,030,014,05,'Y',0333,033,0231,'0',0366,033,0320,0,014,07,'|',0276,0271,0361,022,'i',0260,0347,'4',0235,'5',0306,0242,0270,017,0243,'P','@',0272,0212,0237,0374,0206,0242,0234,0305,0245,';',027,'8',0232,0210,'e','@','*','4','i',030,'"',0356,'j',0336,05,0267,0214,' ',0357,0234,'J',0353,0246,0275,'%',0334,0363,'$',01,0211,0253,0246,0315,0206,025,'k',026,'?','9',0345,'q',06,0177,0231,'k','#','}',0252,013,'s',0216,'f',0345,0303,0255,':','K',0324,'}',0317,'l',047,015,0352,'n','%',04,'z',015,'j','N','+','3','z',06,024,'o',0256,017,0363,0244,0342,027,011,0374,0261,0253,'[',0324,0271,0323,'f',0362,0347,0231,'`',0214,0273,'T',0222,'4',0254,']',0267,'<',0356,0245,0304,0344,034,0240,0221,'J',0345,037,017,016,0264,0353,'7','Q',0366,035,0262,0347,0210,'G',017,0312,0272,0232,0236,0352,'[',0217,'Y',0370,'U',0212,0234,0313,'V',0227,036,'&','<',0336,0376,'W',020,0272,0353,0311,0225,'}','"',0244,'q',032,0343,'I','p',0312,'q','4',0247,021,0215,'K',02,0311,'O',033,'F','u',0254,'p',0250,0256,'}',0236,0201,07,'Q',0312,0336,06,0270,0220,'"',0324,'h',0261,'(','E',0333,0265,';',0254,'c','3',035,'*',0357,0210,0264,0337,'$','z',017,'#',0207,'O',0322,0233,')',0330,0371,'<','F',0353,0244,0235,'5',0334,0326,0325,'<',0275,'F',0253,'x',0263,0234,'M','K','(',0210,'T','s',',',0233,'S','(','a',0201,0251,'m',0212,0352,0274,0255,'P',0205,0304,0320,030,0350,'*',0312,0333,0303,'G',0256,0347,'~',0324,0314,024,'f','5','y','v',0327,'-',0377,0,'_','$',034,'5',0250,'$',0353,'F',0257,0367,0370,0345,0221,'a','B',0355,0355,'R',0312,0323,'9','v',0253,0251,'p',0371,05,'"',0227,'8',012,01,'b','Z',0226,'N',0243,'c','V',0261,'b','s',0236,'J',0352,0333,'S',0300,0216,'q',0345,0303,'-','q',0375,0367,0374,'v',0276,'+','>',0,'B','<',0276,023,'.','*','b','>',0337,037,022,0271,0352,0277,'I','v',024,'q',0303,'J','p',0301,0276,'j',07,015,0251,0347,'g',0134,0246,0242,0217,0250,0330,'P',01,'F',02,0256,'e',0312,'2',0212,0217,'6','o',0226,0205,'Z','[',033,0231,'0',0366,0367,0240,02,0214,07,'k',0342,07,033,0226,0362,0354,0245,0350,0316,0247,0342,0277,0271,0360,0361,0340,'7','<',0336,'5',0220,'`','j','X',032,'=','y','E',')',0210,0351,'^','!','2','f',0246,'b',0307,023,'V',0321,'e',031,0215,'*',0227,'9','V',0255,'m',0305,0264,'y',07,'l',0342,'K',0226,0344,0371,0226,0223,'u',0341,017,0360,'3',04,'R',0315,'W','3',0233,0211,013,0237,0206,'[','`',0332,0245,025,'+',0241,0345,'o',026,'s',0211,0345,0303,'-','r',016,0263,0357,0355,0333,'x',0272,'|',0312,0376,'g',012,0233,'+',0230,0217,0277,0301,0305,'.','q','=',05,0374,0374,'r','D',0262,015,'i',0255,0234,'6',02,0221,02,014,05,'X',0332,0370,0211,'1','>',0221,0333,0270,0232,'g',0267,0307,0355,0346,'F',0346,'7',016,'=',0252,'9',04,0250,035,'}',0371,']',0334,013,'h',0363,'{',0373,'Q','%',0216,047,0311,0216,'6',0225,0302,'/',0275,'A',012,0301,030,'E',0355,0322,0247,'Q',012,'}',0350,0214,'4','>','g',016,0274,021,036,0224,0233,'T',0267,'p',0302,'1','f',0253,0233,0206,0271,'|',0315,0345,'p',0353,'^',0222,'u',033,'s',0334,'/',0343,0351,0334,'7',0367,0257,0323,0360,0373,'^',0273,0347,'o','H',0356,'<','^','=',026,'O',0307,0323,'E',033,'L',0341,026,0241,0211,'`','@',0213,0334,'n',0342,0352,0300,0313,0364,0334,':',0327,0242,0235,'F',0334,0367,';',0250,0272,'3','2',0375,047,016,0265,0353,'>','v',0330,'w','N','-',026,0253,'/',0343,0350,0342,0211,0246,'p',0213,'Q','D',0260,0240,'E',0356,0227,0221,'u','`','e',0372,'>',035,'k',0321,'L',0355,0271,0356,0327,'Q','t','f','d',0372,036,035,'k',0326,'|',0355,0260,0356,0374,'Z','-',026,'Q',0377,0,0257,0240,0212,'6',0225,0302,'/',0275,'C',022,0300,0201,027,0273,0334,'E',0326,0211,0223,0350,'8','m',0257,'I',':',0255,0271,0357,'<','B',036,0224,0347,015,0216,0276,'u',0205,0267,0210,0223,026,0364,0216,0365,0304,0240,0352,0303,0230,'n','<',0324,'C','#',04,']',0315,'[',0302,'-',0343,010,';',0335,0334,036,036,'R',0276,0336,'g',014,0265,0310,0275,'f',0334,0355,0337,'/',0355,0274,'D','x',0256,0343,0313,0262,0265,'7',022,'k',0351,025,0267,'}',0342,026,047,036,0264,'_',0237,'#','z',0267,0341,0262,'K',0254,0232,012,0216,'5',0211,'r',' ',0323,0277,0311,'g',04,0272,0262,0321,0341,'P',037,0275,'~',0223,017,0334,0327,0351,021,0377,0,0310,0327,0351,011,0377,0,'*',034,'"','?','v','4',0274,'2',0335,'w',0326,0243,0202,'8',0275,013,0207,0377,0,014,0237,0377,0304,0,'R',020,0,01,02,03,02,010,011,010,06,05,011,011,01,0,0,0,01,02,03,0,04,021,'!','1',05,022,023,' ','"','2','A','Q',020,'#','0','@','a','q',0201,0221,0241,024,'3','B','R','b',0261,0301,0321,'$','C','P','S','r',0202,025,'c',0222,0242,0341,'%','4','5','s',0223,0262,0302,0322,0360,'T','d','t',0203,0224,0243,0263,0342,0361,'D',0377,0332,0,010,01,01,0,06,'?',02,0373,'s',031,0325,0204,047,0246,'(',0313,'j','t',0357,'6',010,0321,'X','h','n','H',0216,'1',0345,0257,0255,0134,0202,'e',0346,025,0214,025,'b',026,'v','}',0266,'T',0265,04,0244,'m','0','Q',')',0375,0241,0370,'F','3',0213,'+','V',0363,0301,0246,0240,0236,0270,0260,0225,'u',010,0321,'k',0274,0305,0210,'H',0217,'G',0272,'5',0207,'t','z',047,0262,'4',0320,017,'T','c',' ',0305,'E',0377,0,'m',027,035,'4',036,0370,0267,'E',0241,'r',07,05,07,030,0256,0210,0326,0304,033,0223,026,0333,0310,'8','v','R',02,'E',0244,0331,0366,0312,0235,'p',0321,'#',0306,'1',0327,'`',0364,'S',0272,'1',0226,'{','7',0305,'5','Q',0352,0216,'J',0202,0370,011,0364,0257,'1',0225,'#','A',0253,'{','v','}',0260,0245,0254,0342,0245,'6',0223,025,0271,0244,0352,0246,'7',0250,0334,'#',031,'f',0247,0223,0313,'/',0362,0302,'P',0201,0214,0245,032,01,011,'h','Z','o','Q',0336,'y',0347,0322,0347,0345,0345,0317,0252,0267,05,'{',0241,'X',0217,0273,'4','F',0306,'Z','?',032,'G',0321,'p','Z',0334,033,0336,'w',027,0334,014,'q',022,'r',0214,0247,0332,012,'Q',0367,0210,0321,0234,'C',03,'s','l',0247,0342,014,'[',0205,']',0374,0241,'#',0341,026,0341,'y',0337,0312,0372,0207,0272,'?',0245,0347,0377,0,0352,'W',0363,0212,0214,'1','=',0377,0,'P',0277,0234,'Y',0205,0237,0374,0306,0276,0370,037,0312,'X',0335,012,'i',037,'(',030,0355,0311,0274,'=',0246,0310,0367,030,031,'|',022,0222,'6',0226,0336,0247,0302,'(',0363,'s','R',0275,'*','F','0',0360,'0',0234,0206,024,'c',030,0330,022,0341,0311,0236,0345,'E','R','B',0206,0361,0312,0344,0232,'<','B',0177,'z','1',0225,0330,'7',0301,'Z',0215,0247,0223,0252,0274,0330,0361,0340,0362,0227,'G',030,0255,'Q',0270,'s',0222,0354,0303,0310,'a',0261,'z',0334,'V','(',0202,0226,0134,'r','}',0301,0367,011,0321,0357,'?',010,0244,0214,0253,'2','i',0365,0227,0306,'+',0345,037,'I',0302,'S',013,036,0250,'^','*','{',0205,0234,0302,0262,0223,'o',0313,'m',0342,0234,')',0200,036,'q',0271,0344,'n','y',026,0367,0210,'J','g',0345,036,0224,'W',0256,0216,'1','?','8',0254,0214,0353,'3',033,'q','R',0255,'!',0331,0177,'"','e','Y','6','z','j',036,0350,'*','Q',0240,021,0214,'n',0330,'9','<','Q','v',0323,01,011,024,02,'<',0241,0321,0305,047,'T','z',0307,0234,')',016,'L',0371,'D',0300,0372,0231,'}','#',0362,020,0244,'`',0366,0221,' ',0337,0256,'t',0327,0362,0214,0254,0334,0313,0263,'+',0336,0352,0312,0271,0260,'R','I','J',0205,0240,0215,0220,0224,0371,'O',0226,0262,'>',0256,'k','K',0306,0370,'J',047,0220,0274,034,0351,0332,'t',0333,0357,0204,0275,'.',0352,036,'i','W','-',0265,'T',034,0323,'.',0311,0343,'N',0261,036,0214,'T',0305,023,0346,0305,0335,'<',0230,'B','E','I',0214,'Q','~',0323,0276,')','s','I',0327,'T',04,'$','b',0244,'X',07,'5',0251,'4',033,0341,'M','J',0237,0322,'3','#','c','G','@','u',0253,0345,012,'K',0263,'>','O','.','~',0242,'_','E','=',0273,0371,0346,'R','B','m',0311,'e','m',0305,'6',036,0261,'q',0204,0265,0206,'e',0361,0177,0336,'%',0305,0235,0251,0371,'@','~','N','a',0271,0206,0217,0244,0331,0257,05,023,'k',0312,0325,037,030,'*','Q',0252,0215,0244,0306,'I',07,'G','i',0337,0312,'U','^','p',0337,0321,011,'i',0261,'U',037,010,'K','H',0331,'y',0336,'y',0252,0232,'J',0274,0266,'t','}','C','F',0357,0304,'v','B',0222,0373,0371,')','m',0222,0355,'X',0236,0335,0377,0,'`',07,0344,0246,0134,0226,'w','z',015,0375,'{',0341,'R',0323,0322,'e','S',010,'M','r',0314,0352,0236,0261,0262,024,0353,0206,0252,'1',0222,'A',0323,'7',0364,'r',0231,'e',0213,'}',021,0,01,'R','v','E','U','k',0313,0326,';',0272,'9',0247,0224,'O','L','%',0224,'l',036,0222,0272,0204,'.','^','G',032,'B','H',0356,'<','b',0372,0316,0316,0316,'T','%',011,'*','Q',0270,010,0342,'p','T',0321,0351,'S','E','#',0274,0306,0224,0232,'X',033,0335,'u','?',010,0265,0351,'$',0365,0270,0257,0362,0306,0226,023,'`',036,0204,023,037,0322,0315,0377,0,'b','~','q','f',024,'g',0373,'#',034,'T',0334,0223,0211,0351,'R',0222,'}',0321,'T','6',0303,0375,015,0273,0363,0244,022,0274,024,0371,03,0356,0350,0277,'t','R','f',']',0331,'r','v',':',0202,0236,'M',014,'2',0234,'g',026,'l',0200,0312,'-','Y',0265,'k',0365,0214,'W',0323,'7',010,'$',0232,0223,0311,0345,026,'4',07,0217,0,0232,'t','i',035,'A',0273,0247,0232,'.','V','G',026,'r','~',0357,0325,0266,'z','w',0365,'B',0246,0247,'_','S',0357,'+','j',0266,'t',015,0334,0222,'[','i',012,'q',0305,0134,0224,012,0223,01,'^','I',0344,0210,'"',0270,0323,'*',0305,0360,0277,0302,'+','?',0204,0226,0263,0352,0313,0247,027,0304,0326,'*','0','z','_','V',0371,0202,'W',0340,'l',0200,0231,'v',032,'a','#','c','h',011,0344,0250,0240,024,'7',030,'V','_',06,'K',0225,'*',0365,0241,'8',0212,0357,020,0243,')','1','1','&',0252,'X','+',0216,0221,0361,0361,0202,0251,'U',0263,'>',0215,0311,'8',0212,0356,'?','8',0304,0235,0224,'v','X',0376,0261,'4',07,0250,0347,04,0244,'c','(',0330,0,0214,'w',05,'f',0334,032,'G',0325,0350,0202,0265,0134,' ',0255,0134,0237,0260,'/','0',0,024,02,'2',0316,0216,'%',';','=','c',0314,0326,0363,0356,'%',0246,0220,'*',0245,0254,0320,010,0134,0226,010,'R',0230,0224,0271,'s',027,'-',0316,0255,0303,0222,'J',0345,0245,012,030,'?','^',0366,0202,'?',0217,'d',05,0341,'9',0225,0316,'+',0356,0332,0320,'G',0317,0335,030,0222,'R',0214,0313,017,0325,0246,0204,0363,'"',0207,'P',0227,020,'o','J',0305,'D',025,'4',0311,0301,0356,0372,0322,0366,017,0331,0272,012,0345,'q','0',0223,'_',0252,0321,'_',0354,0237,0204,')',0267,'P',0246,0234,'M',0350,'X',0241,034,')',0237,0231,'N',0231,0363,'I',';',06,0370,0251,0260,'E',0236,'l',']',0311,0204,'&',0363,01,011,0200,0201,'b',05,0252,'V',0341,011,'m',03,025,')',0260,016,'d',0271,0271,0307,'C','L',0247,0274,0364,010,'(',0266,'_',07,0244,0350,'0',015,0375,'*',0351,0344,'R',0342,0233,0362,031,'S',0365,0257,0213,'O','R','a','+',0310,'y','d',0310,0372,0351,0213,'{',0205,0303,0234,'b','O',0312,'6',0376,0345,0334,0241,0324,'o',0205,'=',0201,0336,0362,0226,0377,0,0331,0335,0261,'}',0206,0343,012,'V',020,'a','l',0241,0205,'P',0264,0342,'h','T',0257,0227,06,'E',06,0317,'K',0223,0240,0264,0305,0276,'p',0337,011,'m',0261,'U',0252,0350,015,0246,0323,0351,'+','y',0346,'K',0233,0234,']',022,',','J',06,0262,0316,0341,05,0371,0223,0212,0332,'|',0323,011,':','(',037,0353,'o','!',0364,'V',0261,'%',0306,0264,0303,0226,' ','|',0341,'.',0255,'>',']',':','>',0271,0321,'b',0177,010,0331,0316,0361,0315,0253,'6','%',';',0341,'N',',',0343,')','V',0223,030,0251,0363,0212,0360,0345,'2',0313,032,'G','T','p','e',0134,034,'z',0377,0,'t','s','%',0316,'M',0256,0211,026,'%',03,'Y','j',0334,'!','S','S','J',0262,0346,0332,032,0255,0215,0303,'=',014,0262,0332,0235,'u','f',0211,'B',05,'I',0204,'M','a',0315,'5','^','$',0322,'l',037,0210,0374,'!','-','4',0204,0266,0332,'E',022,0204,0212,01,0316,0324,0353,0206,0211,'L',027,'W',0330,'7',010,'+','=',0202,'7',0251,'Q','V',0355,0213,'y',034,0242,0306,0200,0361,0340,023,'N',0215,021,0250,017,0277,0231,';','9','6',0274,'F','[',035,0375,02,014,0313,0347,025,0244,0330,0313,';',020,0234,0360,0304,0233,'z','#',']',0345,'j',' ','t',0230,031,'$',0345,0246,0310,0323,0231,'X',0322,'=','[',0207,'=',0311,0266,'x',0204,']',0355,035,0360,'I',0260,010,0257,0242,'.',020,'A',0261,'g',0203,'r',0267,0305,0242,0315,0371,0364,0364,'E',0346,02,'R','(',04,'i','y',0224,'k',035,0375,020,0,024,03,'g','1','q',0367,0226,033,'i',0264,0343,')','j',0270,010,0242,011,'F',017,'d',0361,'-',0357,0366,0217,'N','~','U','u',0226,0301,0311,':','O','m','W','B','a',0271,'I','6','C',',',0243,'`',0333,0322,'y',0351,0225,'h',0351,035,'s',0273,0243,0203,'"',0215,'Q',0177,015,015,0250,0336,'x','(',0241,'Q',030,0315,0332,'7','f',0204,'&',0363,01,03,0264,0357,0205,0314,'<','t','S','p',0336,'w','B',014,0270,0311,'<',0326,0213,0315,'m',012,0337,0324,'y',0222,0260,'<',0222,0376,0212,0321,0343,0326,0237,'M','[',0272,0206,'z','g',047,'B',0232,0301,0211,'=','E',0356,0201,0321,0323,010,'e',0224,'%',0246,0220,'1','R',0204,0212,0,'9',0355,0226,0274,0255,'Q',0361,0202,0245,032,0223,'i','1',0212,0237,'8',0257,016,020,0235,0360,0,0270,'F',0201,0240,021,'C',0242,0256,012,0215,025,'A','I',0331,0303,0214,0257,'8',0257,010,'R',0324,'q','R',0221,'R','N',0310,0321,0262,'Y',0273,033,'O',0306,033,0234,'`',0325,'7','8',0336,0305,0247,'t','3','9','*',0274,0243,'.',0212,0203,0360,0346,036,'E','*',0277,0345,011,0221,0262,0366,0321,0353,'g',0211,0331,0304,0224,0340,0306,0315,0337,'|','w','u','B','P',0204,0204,'!','"',0201,'"',0341,0317,'T',0353,0206,0211,'L',')',0325,0355,0270,'n',020,'V',0250,'+','U',0347,0204,'p',020,'x',022,'U',032,'&',0252,'1','^',014,0262,0307,0341,034,07,07,0313,0253,'@','y',0325,015,0247,'w',017,0221,'M','.',0230,'>','d',0322,0337,0253,'^',0303,0313,0314,'O','L',035,06,0223,'Z','z',0307,'`',0207,0347,'f',0225,0214,0353,0246,0275,']',031,0330,0316,0325,030,'9',0223,0306,0257,0326,0366,'D','6',0313,'(',015,0264,0330,0305,'J',023,'p',034,0373,'$',0331,0342,'Q',0342,'b',0261,'f',0240,0273,'1','*',0335,01,'B','(',0241,'X',0255,0264,0335,033,0200,0205,036,013,'|',0330,0277,0203,'"',0311,0372,'S',0242,0317,'d','o',0315,0375,033,'4',0272,0316,'J',0247,'D',0223,'k',0215,0377,0,016,'[',0364,'|',0272,0253,047,'(',0253,'H',0364,0334,0332,'{','.',0357,0316,'n','N',0134,'P','^',0343,0233,020,0235,0360,0314,0234,0252,'2','l',0266,'(',':','z','O','>',0362,'v',0317,032,0261,'i',0334,'8','2','(',0374,0334,'8',0251,0215,'5','T',0306,0202,0255,0351,0212,033,0267,'E',0370,0247,0246,'5',0204,'b','7','v',0323,0300,020,0230,010,'M',0302,036,0232,'R',024,0264,0266,'.',036,020,0343,0357,'+',031,0305,0232,0346,0313,0317,'K',032,':',0322,0253,0326,'6',0210,0227,0236,0227,'5','i',0324,0327,0250,0355,034,0242,0362,'J',0244,0344,0307,026,0316,0361,0275,']',0231,0315,0262,0322,'J',0335,'q','A',')','H',0332,'a','-','P',031,0307,'t',0237,'p','m',';',0272,0207,'>','S',0252,0277,0321,033,0314,')',0305,0232,0251,'F',0246,',',0327,'7','E','O',05,' ','z',0333,'c',024,0233,'x',022,0312,'w',0332,'b',0267,0247,0177,015,05,0361,'n',0271,0276,02,022,'1',0224,'l',02,027,',',0362,022,0350,'y','4','t',033,0225,0321,013,'b',0325,'J',0271,0246,0303,0233,0323,0273,0254,'g','+',04,'>',0256,'"','g','I',0252,0372,'.','n',0355,0370,'r','u','7','C',0317,'%','U',0225,'k',0212,'`','{','#','o','n','w',0351,0311,0244,'Z','t','e',0222,'G','z',0376,034,0370,0250,0232,01,0266,'*','<',0322,'l','@',0202,0245,'X',04,025,0236,0301,0302,0230,'Q',027,0322,'2',0253,0272,',',0326,'7','@',';',0255,0205,023,0273,0207,',',0261,'o',0242,'8','<',0245,0321,0306,'+','T','n',034,016,'J',0252,0211,'}',':','l',0271,0352,0252,034,'e',0344,026,0335,'m','E','*','I',0330,'s','P',0343,'j','(','Z',016,'2','T','6',030,0227,0234,0263,'+','L','G',0222,'6',',','_',0363,0355,0344,0225,'.',0322,0251,'5','9','V',0323,'K',0302,'}','#',0360,0355,0316,'f','P','T','0','4',0336,'^',0344,'C','l',0262,0200,0333,'M',0244,'%',')','M',0300,'s',0357,'$','l',0332,'u',0376,0134,031,'$',0352,'&',0376,0223,0230,0235,0334,026,013,04,023,0212,'b',0233,'v',0230,0311,016,0336,014,'e','y',0264,0370,0360,'e',0234,034,'J','?','x',0346,014,'9',',',0233,015,021,'2',07,0202,0276,035,0331,0306,'A',0325,'R','Z','w','D','W','c',0233,';',0356,0356,0344,0246,024,0205,'V','^','_',0211,'k',0262,0363,0337,0134,0344,0270,0362,'i','9','7','G',034,0255,0351,036,0212,0177,0326,0376,'|',0247,'=','+',0222,'7',0230,'R',0324,'j',0243,'i','1',0210,0235,'u','x','p',0320,'F',0231,0322,0213,'{',0343,021,0313,016,0376,034,'T',0332,0270,0251,0200,0204,0300,'B','n',020,033,'M',0202,0365,'+','p',0204,0266,0330,0242,023,'`',0314,'z','Y',0364,0343,0262,0352,'J',024,0236,0210,0231,0220,'w',0352,0325,0242,0257,'Y',';',016,'j',0134,'B',0212,'V',0223,'P',0241,0260,0304,0244,0360,0326,'Z','t',0306,0345,0213,0371,011,0247,0320,0254,'W',0334,031,026,0277,021,0371,012,0236,0314,0346,0262,0211,0254,0254,0267,034,0357,'N',0341,0337,0317,0211,'&',0200,'A','P',0363,'I',0261,02,012,0325,0262,012,0325,'y',0341,0312,'*',0375,0221,0355,'l',021,']',0221,'b',0355,0214,'R','c','[',0202,0202,0323,036,0331,0276,02,022,'1',0224,'l',02,02,'o','p',0332,0265,'g','7',0205,0231,'E','^',0225,0321,'v',0233,'[','?','#',0357,'9',0323,'X','%',0303,0242,0360,0313,'5',0370,0205,0376,036,0356,'A',0214,032,0205,'q','r',0251,0306,']',0276,0232,0277,0207,0277,'9',0225,'-','8',0263,'3','|','s',0233,0375,0221,0335,0317,0274,0221,0263,'i',0327,0371,'p','Q',':',0211,0273,0205,'#','y',0200,' ',0225,'h',0246,'(',0221,'A',0300,025,0264,'p',0345,0226,'-',0364,'x','<',0251,0321,0246,0255,'A',0270,'g',0270,0303,0311,013,'i',0304,0224,')',047,'h','1','7',' ',0277,0252,']',022,'N',0324,0354,'=',0331,0262,0223,0315,0353,'0',0340,'U',06,0321,0264,'w','C','o','4',0254,'f',0334,'H','Z','T','6',0203,0234,0343,0316,034,'V',0333,'I','R',0216,0340,'"','j','u',0315,'g',0334,'+',0267,'g','F','l',0244,0252,0223,0214,0315,'r',0216,0376,01,0376,0251,0333,0317,0224,0351,0265,'W','$','o','0',0245,0254,0325,'J','5','&','2','I',0326,'U',0375,'Y',0211,'=','1','Q',0301,0212,0235,'x','*','Y',':','[',0341,'(',0333,0301,'U','y',0264,0337,0323,0301,0225,'p','q',010,0375,0343,0310,0312,'a','v',0323,'j','x',0207,'z',0275,023,0357,0357,0316,'m',0225,032,0271,'(',0242,0311,0256,0353,0323,0340,'i',0331,0234,0372,022,'h',0344,0332,0203,03,0253,'o',0200,0316,0232,0302,0213,'N',0223,0352,0311,'7',0370,'E',0376,'>',0356,'}',0242,'x',0244,'X',0237,0234,025,0230,'*','U',0347,0207,'E','5',0215,'$',0305,'5',0223,024,'H',0244,'c',0273,0335,025,'6',01,05,'F',02,023,01,011,0270,'B','Z','G','i',0334,'!','-','6','(',0224,0362,'3',0222,'*',0247,034,0331,011,047,'b',0266,036,0370,'[','k',030,0253,'I',0305,' ',0354,'9',0256,0311,0250,0321,023,0215,0331,0370,0223,'h',0360,0306,0316,0222,0220,04,0321,0206,0313,0212,0353,'W',0377,0,'<','s','R',0204,014,'e',0250,0320,01,0266,'$',0344,'S',0365,'-',0204,0236,0223,0264,0367,0363,0337,047,'A',0343,034,0277,0240,'p','Y',0250,0233,0270,'j','u',04,'P',012,010,0266,012,0233,0356,0212,0334,0241,032,'z','*',0215,0310,0335,0301,'n',0271,0276,02,'R','*',0243,'`',021,'C','k',0252,0265,'g',0223,0231,')','M',032,0232,0343,0323,0333,0177,0215,'s','d',0247,'A','#','"',0352,'V','i',0273,'o',0204,05,013,'A',0264,'f',0341,'7',0366,'e',0212,07,'R','t','G',0273,'6','E','%','8',0315,0262,'r',0352,0374,0267,'x',0323,0236,0255,0325,0352,0244,'B',0335,'^',0262,0214,'d',0223,0254,'o',0341,011,033,'`','$','@','m',0236,0370,0264,0366,0360,'[','~',0370,'(',0255,'x','2',0313,0374,0274,036,'V',0350,0264,0352,017,0217,')',047,'>',0224,0325,'R',0356,'b','(',0373,'*',0376,' ','w',0347,'`',0307,'I','%','I','o','$',0252,0337,'T',0350,0374,'3',047,'f',0317,0324,'2',0247,';',0204,'T',0332,'s','p',0216,021,' ','V',0306,022,'|','U',0376,036,'{',0344,0350,'<','[','w',0364,0230,'+','=',0202,012,0225,'i','<','5','Q',0267,'d',032,'^','`',0270,'{',' ','6','6',0302,0252,'t','v','B',0255,0322,0335,04,0233,0314,'{',02,0370,0240,0272,'*',0261,0304,0243,'[',0247,0243,0225,0302,'2',0264,0306,'R',0232,'%',03,0332,026,0217,021,0235,'=','$','U','U','0',0350,'X',035,012,037,0372,0234,0311,0260,025,0212,0247,0224,0206,0207,'}','O',0200,'9',0322,'U',0,'-',0372,0274,'i',0322,'l',0360,0247,'-',0244,0342,'S',0326,'c',0371,0313,'_',0266,'#',0371,0313,'_',0266,'"',0250,'P','X',0350,'<',0236,0211,0343,'W','b','~','|',026,'j','&',0356,032,'z',';','c',031,026,0246,0,'Q',0255,'!',020,015,'h','c',024,']',013,'=','0',022,0233,'I',0200,0201,0332,'a','-','6','4',0225,011,'i',027,015,0273,0371,'i',0371,'L',0134,'P',0323,0312,'J','G',0263,'[','<','3','f','e',0375,07,0245,0311,0355,04,'|',0316,'f',014,0225,0373,0307,'T',0357,0354,0212,0177,0213,':','R','U','6','%',0226,0222,0330,0354,034,0236,'3',0316,04,016,0230,0244,0263,'_',0231,0317,0224,'i',0276,0252,'n',026,014,0314,'f',0324,'P',0255,0342,'2',017,'y',0355,0212,0365,0271,022,0245,032,'$','Z','L',')',0317,'F',0344,0216,0210,0311,047,'Y','W',0365,'p',0320,'Z','a','x',0302,0206,'2','i',0274,0337,0301,0210,0273,0267,0305,'q',0205,' ',0241,0263,'S',0277,0203,'(',0241,0246,0257,016,014,'u',0216,'=','w',0364,'t','r',0357,0257,0375,0241,0264,';',0341,0213,0376,034,0334,026,0262,0254,'P',0247,'2',0177,0264,010,0370,0346,'H','K','}',0333,030,0377,0,0264,0257,0375,'s','p','[','4',0306,0306,0231,'n',0243,0243,032,0336,'H',0251,'j',011,'H',0274,0230,'(',0224,037,0363,025,0360,0214,'w',024,'V',0255,0347,0202,0303,0224,'>',0314,'h',0204,0243,0306,'<',0351,0215,'|','n',0205,'E','5','W',0272,022,0264,0232,')','&',0240,0303,'n',0246,0345,012,0362,02,'U',06,0325,'Z',0276,0250,'+',';',' ',0255,'W',0236,034,0251,0274,0335,0300,0245,0233,'A',0315,0312,'+','Q','>','<',036,'T',0350,0320,'N',0240,0336,'w',0363,014,025,'1','K','V',0205,0240,0236,0242,'?',0315,0233,'"',0372,0215,022,0323,0350,'Y','=','J',0314,'u','5',0363,'M','!',036,025,0370,0346,0340,0373,'*',021,0216,0263,0373,047,0221,0306,'p',0333,0261,'"',0363,032,'f',0210,0330,0201,'p',0340,0242,'t',0327,032,'j',0263,'p',0273,'4',021,'a',020,025,0351,'m',0207,030,'7',0240,0343,016,0254,0365,0274,0273,0223,0343,013,'u','f',0252,'Q',0251,0214,'T',0352,'&',02,'D','P','h',0221,0266,012,'o',0244,'o','N',0350,0321,'=',0221,'l','c','7',0335,024,'"',0207,0200,' ','v',0230,011,'M',0200,'@','E',0315,0213,'V','z','!','(','H',0242,'E',0200,'s',011,027,'}','Y',0234,'^',0364,0237,0226,'s',013,0365,0220,017,0207,016,024,'>',0322,'G',0356,047,'5','g',0325,0226,'Y',0361,'O',' ',0134,'U',0246,0344,0247,'y',0205,':',0351,0252,0214,025,'(',0320,010,')','o','E',036,047,0220,03,0321,']',0220,0322,0275,025,'h',034,0377,0,047,'A',0342,0333,0277,0244,0306,'M',':',0352,0360,021,'H',0366,0215,0361,0212,'5',0214,'S','f',0370,0266,0324,0357,0212,0244,0320,0306,'+',0226,035,0374,030,0240,']','y',0212,'G',0266,'o',0204,0241,03,031,'J','4',02,03,'b',0325,'^',0245,'o','<',0305,0343,0352,':',0205,'x',0323,0343,0235,0202,'V',0243,'U',031,'V',0352,0177,'(',0341,0302,0337,0327,'f',0316,'9',0352,0312,0221,0336,0244,0374,0271,05,020,'x',0264,0350,0242,011,'6',01,033,0233,027,016,'I',013,0336,'!',0247,'v',0221,'o','^','i','P',0363,0212,0261,020,0247,027,0262,024,0265,'^','c','*',0241,'f',0310,'*',';','#','y','0',023,0267,'l','d',0205,0346,0376,015,'$',0322,012,'A',0340,0313,'+',0362,0360,'y','K',0203,0214,'V',0250,0334,'9',0226,020,0353,'o',0377,0,'"','s',0260,'G',0374,':','}',0334,'8',0134,0233,'>',0224,0340,0361,0315,0302,'G',0365,')',0367,0347,0314,',','X','B',015,'8',022,0310,0333,'i',0344,0326,0336,0353,'D','9',',','v',0351,0247,0343,0231,'X','*',036,'m','6','"','2','i',0325,'O',0276,06,'5',0320,'1',016,0214,'P',0332,' ',0254,'A','V',0335,0220,'T','o','1',0224,'V',0250,0203,0217,'t','Y','t','S',0321,027,0230,0,'X',04,'c',0254,'q','(',0277,0244,0356,0346,'x','N',0246,0226,' ',0377,0,0334,'N','v',011,0376,0240,'p',0341,'a',0372,0362,'s','g',0321,0276,'^',0277,0274,'>','y',0363,'#',0330,'<',016,'r','h',';',015,0206,033,'x','^',0223,'X','J',0323,'j','T','*','8','|',0235,07,'M',0313,0372,04,'Y',0256,0253,0270,'j',0223,024,':','*',0340,0266,0370,010,0245,0233,0340,'$',0134,'#','&',0223,0242,' ','$','Z','L',04,0355,0332,'a','-','"',0365,'x','B',032,'E',0311,0361,0346,'x','G',0376,'_',0376,'D',0347,'`',0217,0370,'t',0360,0341,'Q',0372,0300,0177,'t','f',0274,'=','i','E',0217,0336,'N','z',0222,'v',0212,'A','I',0274,'Y',013,0351,0267,0224,'B',0266,0355,0203,'.',0243,0246,0335,0335,0134,013,'u','w',015,0233,0341,0307,0335,'6',0233,'L',025,0236,0301,0233,0212,0345,0243,'|','U','&',0243,0203,024,'k',036,014,0262,0257,':',0274,030,0353,034,'r',0357,0350,033,0271,0244,0330,0365,0226,0330,0375,0341,0235,0201,0307,0373,0253,'g',0367,'x','g','U',0261,0324,0266,0261,0373,' ','|','3','e',0223,0367,0310,'[',0177,0273,'_',0207,' ',0370,0330,0243,0215,0337,015,0257,'x',0247,'(',0246,0217,0245,'h',0204,'<',0213,0306,0315,0361,0227,016,0,0215,0265,'7','E',023,'c',010,0325,033,0372,'c','"',0237,0315,0237,'T',0236,0310,'*','6',021,0262,012,0214,'T',0352,'&',0376,017,')','p','h',047,'T','o','<',0325,0206,0307,0326,'M','$',036,0254,'U',0177,014,0351,'&','@',0240,'m',0224,'&',0235,'C',0206,']',0332,'h',0271,',','-',0351,012,'?',0303,'7',04,0271,0372,0364,0243,0366,0264,'~','<',0203,016,0357,030,0246,011,0365,'M','y','D',0254,'^','!','+',027,036,02,0257,'K','d','T',0337,0310,0204,'&',0363,01,011,0200,0330,0261,'7',0251,'[',0204,'%',010,024,'J','E',0,0346,0270,'&','_','a','.','8','|',0,0367,0234,0326,'X','M',0212,'u','a',03,0264,0300,02,0341,0303,0202,'f',0,0321,0343,020,'O','u','>','9',0254,0276,0215,'v',0226,026,':',0304,'!',0304,0334,0241,'Q',0236,0263,0265,0275,'8','R','7',0212,'E','9','L',0232,0316,0201,0270,0356,0212,0225,0216,0241,030,0307,0260,'n',0344,0262,0212,0327,'W',0200,0200,0224,0212,0250,0330,04,04,0375,'b',0255,'Y',0346,0315,'1',0215,'T',0261,'.',0221,'M',0304,0222,'~','Y',0270,'%',0241,0376,0320,0225,0366,'$',0327,0341,0231,0226,0333,'.',0372,'W',0337,0243,0361,0316,0301,'n',0326,0244,'2',033,'5',0336,0235,037,0206,'z',0220,'n','P',0241,0205,0266,'o','I',0244,'/','q',0267,0233,0343,'+','Q','>','<',036,'V',0340,0376,0254,'|','y',0276,024,'x',']',0226,'(',037,0227,'G',0341,0232,0207,010,0376,'n',0312,0334,037,0335,0377,0,026,'f',023,0227,011,0307,'Q','a','E',')',0366,0205,0243,0304,'g','M',0311,0225,'U','R',0357,'c',01,0271,'*',037,'0','y',02,0275,0216,014,'h','m',0316,0316,'l',020,0233,0314,04,'&',0341,024,'>','i','6',0254,0300,0,'P',015,0234,0332,'n','m','z',0254,'4',0247,';',0204,025,'(',0343,'(',0332,'I',0315,0302,0223,0207,'T',0342,'2',0237,'y',0370,'f','P',0335,023,0262,0224,'#','"',0362,0220,'+',0272,0266,'f',0371,'9','U',021,'6',0331,'E','=',0241,'h',0367,036,0376,'A','.',0213,0333,'>',06,026,0235,0264,0250,0346,0330,0352,0327,'W',0200,0204,0266,0201,'U','(',0320,010,'K','B',0323,'z',0216,0363,0315,0324,0300,'$','.','m',0304,0267,'f',0355,'c',0356,0361,0316,0225,'%','8',0253,0230,'*','x',0366,0233,'<',0,0315,'3',0,'h','M',0266,034,0257,0264,',','>',0341,0337,0233,'+','8',0336,0273,016,'%',0301,'m',0364,'0',0323,0355,034,'f',0334,'H','Z','H',0332,016,'{',0215,033,0226,0232,'A','I',0260,0213,'!','i',0331,'[','9',0246,':',0265,023,0343,0301,0345,'N',015,'5','j','t',016,'p',0314,0212,'M','Q','(',0335,0277,0211,'V',0373,0261,'s','Z','a',0261,'W',034,'P','B','G','I',0211,'y','V',0354,'m',0226,0322,0330,0354,031,0262,0363,0311,'N',0224,0253,0264,'Q',0366,'U',0374,'q','s',0220,0302,0215,'^',0223,'V','H',0376,033,0323,0362,0354,0344,026,'F',0253,0232,'p',0207,'?',')',0346,'a',011,0274,0300,'B','n',021,0214,0261,0304,0243,'[',0247,0243,0234,':',0373,0252,0304,'i',0244,0225,0251,'G','`',021,'5',':',0346,0263,0356,025,0365,'t','f',0312,0222,'*',0334,0265,'_','U','z','.',0361,'#',':','r','I','W','>',0331,'E','w',035,0206,026,0332,0306,'*',0320,'q','T',016,0303,0232,0231,'u',0252,0214,0316,0247,'$',0177,027,0243,0362,0355,0344,020,0360,0275,0263,'o','Q',0205,0215,0267,0216,'g',0216,0255,'u','x','B',032,'l','U','J',0204,0264,0213,0206,0335,0347,0234,011,'4','*',0217,'N',0253,023,0362,015,'o',0200,0355,0316,0232,0302,'*',032,'S','+',0304,'G',0341,'O',0361,0257,'v','{',0353,'J','h',0314,0337,036,0233,'6',0235,'o',037,'~','j',034,'m','X',0253,'A',0306,'J',0206,0303,022,0223,0311,0326,'q',':','c','r',0205,0376,'9',0356,'4','}','1','H',')','U',0204,'X','a','i',0331,0263,0230,0343,0253,'Q','>','<',031,'g',07,032,0347,0200,0347,'3',012,'B',0253,'/','/',0304,0265,0331,'y',0357,0315,'C','M',0247,031,0305,0220,0224,0244,'m','1',047,'"',0217,0251,'l','$',0235,0347,'i',0357,0317,023,0210,'M','^',0222,'V','=',0336,0201,0326,0370,036,0314,0347,'p','C',0312,0342,0346,'t',0332,0350,'X',0277,0274,'{',0271,02,0261,0252,0356,0227,'n',0330,'C',0275,0207,0230,04,'&',0363,01,011,0331,031,'U',0216,'%',0277,023,0316,'^','[','j',0244,0323,0374,'K','=',04,0336,'{',06,'r','f',026,0232,0263,'$',0234,0251,0374,'^',0217,0317,0263,0220,'q',0227,'R',026,0323,0211,'(','R','N',0320,'b','n','A',0177,'R',0272,'$',0357,'N',0303,0335,0232,0324,0303,'*',0304,'u',0245,05,0245,'[',0210,0211,'i',0346,0254,0307,032,'i',0365,'U',0264,'g',0345,06,0263,'F',0275,0220,0264,'o',034,0303,'(',0255,'e','{',0241,015,'#','Y','P',0206,0221,0252,0236,'r',0260,0322,0253,')','+',0305,'5',0323,0353,'+',0375,'n',0316,'i','N',047,026,'b','o',0216,'_','W',0242,';',0271,031,'|','2',0322,'m','o',0211,'{',0253,0321,'=',0366,'v',0347,034,036,0372,0251,')','8','h',011,0364,0134,0331,0337,'w','v','z',0220,0253,'R',0241,'C',013,'i','W',0244,0322,016,0345,'[',0313,'T',0352,'&',0376,014,0252,0307,034,0347,0200,0347,'&','Y',0225,0322,'v','l',024,'"',0227,0245,'>',0222,0263,0245,0345,0210,0254,0272,'8',0327,0277,0,0371,0335,024,027,'r','/',0312,'>','1',0231,'y',05,012,0211,0231,027,0374,0343,013,0305,0353,0334,'s',0202,036,'U','g',0245,0250,0207,'}',0255,0312,0317,'D',0300,026,'/','E',']','q',0214,'5',0221,'o','*',022,0233,'I',0200,0201,031,'g',07,024,0337,0211,0347,'/','M','L','/','&',0313,'I',0306,'R',0241,0371,0347,'l',012,'4','m',036,0242,'6',014,0357,'+','u','4',0231,0235,0323,'5',0330,0217,'D','|','{','y','4','a',0226,023,0306,0261,0240,0375,'6',0243,'a',0354,0316,'f','y',0213,'q','l','Z','=','t',0355,020,0314,0344,0262,0361,0331,'u','8',0311,'9',0316,'5',0264,0335,0327,05,'*',026,0334,'D',')',';','/',034,0246,'Y','W',0233,0241,015,'"',0363,0267,'t','!',0246,0305,022,0236,'s',0372,'"','Q','u',0225,'a',0134,'r',0222,'u',0327,0273,0263,0337,0234,0323,'k','M','e',031,0343,037,'=',033,0273,'~','q','A','`',034,0233,0214,0274,0200,0343,'N','$',0245,'I','7',021,017,'J','*',0245,0235,'f','V','}','$','g','y',024,0343,0237,0311,0317,0233,0317,0325,'+',0177,'V','~',']','#','A',0333,0372,0342,0315,'t',0335,0311,0333,0250,'/',0340,0307,'X',0343,0234,0277,0240,'n',0347,'>','G','(',0277,0345,027,0305,0377,0,'t',0237,'[',0257,'t','T',0337,0232,022,0220,'T',0243,'`',03,'l','!',0267,0,0362,0307,0270,0307,0317,'N',0356,0316,'U','Y','$',0375,':','^',0253,'d',0357,0336,0236,0330,' ',0212,021,0260,0347,'7',0201,'p',0202,0364,0305,0222,0317,'+','o',0260,'~',031,0313,'e','[','n',';',0214,')',0247,05,024,0233,' ',0272,0330,0257,0254,'9',032,0257,0213,'O',0214,04,0240,'P','@',0231,'t','q','i',0325,07,0322,'<',0344,0276,0345,027,'2',0273,031,'g',0326,'?','(','z','n','e','y','G',0335,'V','2',0225,0235,0372,'b','e',037,'G',0227,'4','d',021,0254,0275,0375,0234,0277,0351,0231,'D','R',']',0343,0307,0245,'>',0212,0375,'n',0337,0177,'^','p','R','M',024,'-',04,'B','0','v',020,'X','N',021,'@',0320,'Y',0372,0341,0376,'l',0354,0243,'v','>',0237,0336,0202,0225,02,0225,013,0301,0212,0251,0261,']',0342,'=','!',0333,032,0313,0215,'u','G',0234,'1',0256,0250,0271,'J',0353,'1',0240,0200,0230,0342,0232,'R',0206,0375,0220,027,'2','r',0212,0365,05,0321,'A',0316,027,'7','6',0256,0204,'6','5',0226,0255,0302,034,0234,0232,'6',0233,022,0201,'r',023,0270,'g','3','$',0315,0211,':','N','9',0352,'#','i',0206,'e','%',0221,0223,'a',0244,0342,0244,'r',0356,0313,0276,0200,0343,'.',0247,025,'I',';','D',')',0205,'U','r',0316,'i','0',0357,0254,0237,0230,0316,'K',0215,0250,0241,0304,0232,0245,'I','6',0203,011,0220,0237,'!',0254,'$',06,0212,0266,'=',0374,'z','3',0270,0346,0202,0316,0375,0261,'a','q',035,'J',0217,'<',0347,0204,'y',0365,'w','G',0363,0223,0373,021,0374,0353,0376,0337,0361,0213,'f',024,'z',0223,032,'E',0305,0365,0230,0320,'a','5',0336,'m',0347,'J',0232,0233,'_','B',033,032,0313,';',0204,031,0251,0243,'@',',','m',0241,0252,0330,0335,0234,0333,',',0240,0270,0353,0207,025,')','M',0344,0300,'B',0250,0251,0347,0264,0237,'p',0177,'t','t',016,'b',0344,0233,0332,'+',0326,'i',0332,'j','+','|',';',047,'6',0336,'M',0346,0315,017,'O','H',0316,'J',0320,0242,0225,'$',0324,'(','^','!',0254,037,0205,0226,033,0233,0325,'n','`',0352,0271,0327,0270,0375,0215,0224,'|',0345,'&',027,0346,0245,0323,0254,0257,0220,0205,'M','N','.',0246,0344,' ','j',0240,'n',031,0351,0302,0363,0355,'R','i',0301,0304,'6',0257,0253,'N',0376,0263,0314,0361,0232,0243,'x','E',0221,0305,'/',0326,0366,'L','8',0313,0310,'-',0272,0331,0305,'R',025,'x','9',0355,0310,0341,'u',027,0245,'n','D',0305,0352,'o',0257,'x',0204,'<',0313,0211,'u',0245,0212,0245,'h','5',04,'}',0206,0271,'I','<','Y',0254,'%',0273,0320,'k',0361,'|',0241,'s','S','o',')',0367,0327,'z',0225,0236,0214,'/',0204,033,0372,'*',015,'X','i','_','X','}','n',0256,'j','g','d',0322,021,0204,0333,037,0333,015,0335,'p',0244,'-','%',013,'I',0242,0222,0241,'B',016,0177,022,0254,0264,0241,0326,0226,'p',0350,0236,0255,0306,'1',0345,034,0243,0311,0327,'a','v','-','?','`','-',0371,0227,0220,0303,'(',0275,'k','4',020,0271,'L',014,'U','/',',','l','T',0315,0313,'_','V',0357,'|',022,'M','I',0333,0236,0234,'!','>',0202,0234,034,0203,0242,0223,0365,0307,0345,01,')',01,')',02,0200,015,0234,0331,'S',0362,0,'7',0204,0200,0322,'M',0301,0357,0343,0323,013,'i',0324,026,0334,'A',0242,0222,0241,'B',016,'z',037,'a',0305,'2',0362,015,'R',0264,032,021,010,0226,0303,0211,0350,023,'m',0217,0357,017,0224,'%',0371,'w','P',0373,'*',0271,'h','5',07,0236,0255,0226,'U',0345,0323,0243,0352,0233,':',')',0374,'F','2',0263,0317,0343,01,0252,0322,'l','B',':',0207,' ',0211,0351,0364,0226,0360,'p',0325,'M',0305,0357,0341,010,'i',0244,06,0333,'@',0242,'R',0221,'`',034,0340,0314,'K',0342,0261,0204,0222,',','^',0307,':',025,0363,0207,'%',0246,0331,'S',017,0242,0305,'!',0134,0206,'V','F','a','M',0372,0315,0233,'P',0256,0261,011,'g',011,0243,0310,037,0373,0301,'k','G',0345,011,'q',0245,0245,0306,0325,'h','R',015,'A',0347,'*','C',0257,'y','D',0320,0377,0,0363,0261,'j',0273,'w','B',0232,'B',0274,0202,'P',0375,'S','&',0323,0326,0256,'E',0274,'!',0205,0320,'[',0225,0326,'n','X',0336,0347,'^',0341,01,010,01,')',026,0,'6','s',0254,'G',0206,'J','e','>','j','a','"',0324,0374,0304,031,'y',0306,0350,016,0243,0251,0324,'X',0350,'<',0216,'4',0214,0332,0331,033,'[',0275,07,0262,022,0336,026,0225,',',0253,0357,0245,0355,'O',0354,0377,0,0366,'2',0222,'3','m','L',015,0311,'6',0216,0261,0263,0232,')',0307,0234,'K','M',0246,0365,',',0320,010,'R','%','J',0260,0213,0343,'c','V','#',0366,0276,'U',0205,' ','=',0344,'R',0347,0352,0245,0354,0357,'U',0374,0212,032,'e',012,'u',0325,0232,'%',010,025,'&',032,0237,0302,0351,016,'M',015,'$','K','^',0226,0372,0367,0236,'z',0271,'Y',0306,'R',0363,'*',0330,'v','t',0210,0134,0314,0246,'4',0346,017,026,0343,015,'v',0377,0,020,0370,0362,'I','q',0247,024,0323,0211,0271,'h','4','"',022,0227,036,'L',0373,'C',0321,0230,025,'?',0265,'|',04,0317,'J',0275,'$',0255,0252,'O',030,0217,0237,0204,017,'$',0302,014,':','M',0270,0230,0324,'W','q',0267,0226,'+',0232,0231,'j',']',033,0335,'X','L',024,0264,0353,0223,0313,033,030,'E',0235,0346,012,'0','|',0263,'R',')',0365,0325,0306,'/',0345,030,0363,0323,'n',0314,0233,0364,0325,'`',0352,033,'9',',',0204,0223,'8',0324,0327,'u','V','!',035,'f','1',0323,0364,0211,0345,012,'.','a','C',0301,';',0276,0300,0134,0326,014,')',0222,0233,'6',0226,0376,0255,0177,0345,0205,'K','N',0313,0256,']',0321,0261,'[','z',0267,0362,0211,0362,'L','#','0',0312,'S','`','F','=','S',0335,'t',0,0342,0345,0346,0372,']','j',0337,0335,0244,01,'1',0202,'E','6',0251,0247,0276,024,0200,035,0226,0234,'g',0247,025,'$','{',0342,0331,0267,021,0326,0312,0276,'Q','f',023,'H',0374,'M',0254,'|','#',0372,'Z','_',0276,'-',0302,0255,'~','T',0250,0374,'"',0311,0365,'+',0251,0205,0374,0243,0213,023,'S',07,0330,'n',0236,0363,037,'F',0301,'n','9',0375,'k',0241,'>',0352,0307,0321,0345,0245,'e',0321,0322,012,0317,0276,010,'w',011,0274,0224,0356,'g',0213,0376,0354,025,0270,0265,'8',0263,'z',0224,'j','O','&',022,0221,'R','l',0,'B','&','p',0266,'4',0234,0265,0341,0217,0254,'W','_',0253,010,0226,0223,'e',',','0',0213,0222,0237,0260,0214,0274,0364,0272,'_','o','e','o','O','H',';','!','o',0340,0245,031,0351,'{',0362,'G',0316,0247,0374,0320,0244,'-','%',013,'I',0241,'J',0257,037,'`',0205,'0',0326,'F','W','l',0313,0266,047,0263,'|',07,022,0237,'*',0235,0333,'0',0350,0273,0360,0215,0237,'c',023,'7','/',0212,0375,',',0230,'k','E','c',0347,0333,012,'v','K',0371,'J','X','}',0330,0343,07,0345,0333,0331,05,'*',05,'*',026,020,'v','s',0321,0344,0222,0304,'3',0367,0356,0350,0267,0337,0267,0262,022,0354,0367,0362,0224,0300,0330,0261,'F',0307,0345,0333,0333,01,')',024,02,0340,'>',0311,0372,'l',0242,026,0346,0307,'S',0242,0261,0333,012,'s',05,'L','&','m',037,'r',0366,0212,0373,0356,'>',021,0222,0235,0225,'v','Y',0177,0254,'M','+',0325,0277,0234,04,'!','%','k','U',0201,')',025,'&',022,0267,'Z',030,'=',0203,0351,'L','k','~',0315,0375,0364,0204,0270,0362,'?','H','L',017,'M',0375,'Q',0324,0230,0240,024,03,'`',0373,'5','M','L','2',0207,0332,'U',0350,'q','5',020,'U','.',034,0301,0356,037,0271,'5','O','q',0370,'A','T',0242,0232,0302,015,0373,07,021,'}',0307,0347,030,0263,0222,0217,'K',032,0323,0215,'A',025,0346,'A',0266,0220,0247,034,'U',0311,'@',0251,'0',010,0222,0362,'V',0317,0247,'2','q','<','/',0360,0200,0274,'%','8',0271,0223,0367,'l',0214,'D',0367,0337,0356,0212,'H',0311,'5','.','n',0307,03,'H',0366,0337,0366,0231,'J',0322,026,0223,0261,'B',0261,'U',0340,0326,0332,'V',0366,'8',0277,'t','V','K',010,0274,0311,0334,0362,'B',0307,0205,'!','Y',07,'e','f','S',0262,0213,')',047,0274,'E',0134,0301,'S',07,0372,0241,0224,0376,0355,'c',0351,022,0257,'1',0375,'k','e','<',0206,'#','H','S',0213,0365,'R','*','`','%',0254,025,'6','z','K','$',016,0363,032,'l','5','+',0375,'s',0243,0341,'X','I',0235,0302,'i',033,0320,0303,'u',0361,'?','(','I','q',0207,047,026,'6',0276,0347,0300,'P','F','$',0244,0253,'2',0311,0334,0322,02,'~',0334,'!',0351,'9','w','A',0365,0332,06,'-',0300,0362,']',0214,0244,'G',0364,'L',0277,'`',0212,0376,0213,'o',0261,'J',0371,0307,0364,'S',035,0265,'1','f',010,0224,0355,'l',030,0342,'p','l',0243,'_',0201,0204,0210,0242,022,022,':',07,0330,'_',0377,0304,0,'*',020,01,0,01,02,04,04,07,01,01,01,01,0,0,0,0,0,01,021,0,'!','1','A','Q','a',' ','q',0201,0221,020,'0','@',0241,0261,0301,0360,0321,'P',0341,0361,0377,0332,0,010,01,01,0,01,'?','!',0377,0,'s','q',0134,0361,0251,'?',0310,'6','t',0253,0261,037,0313,'5','3',04,0344,0311,0333,0217,012,0221,'w',030,0202,0321,0377,0,'l','"','4',0257,01,'X',017,'d',0376,037,0332,'t',0355,0233,'>',02,'H',0333,0253,033,'_',0326,'5',0236,035,0341,0245,'{',0324,0264,0276,0212,'?',0360,'4','?',0262,0202,'H','n',0232,0274,0341,0231,0231,'H','I',02,0342,0177,0265,013,'V',0300,'b',0264,'*',0345,0314,0276,0261,0273,0253,0340,0223,'d',0313,017,'z','m',0216,0214,0367,0244,0231,')',0315,0362,'6','j',036,0177,0246,0214,0331,'p','5',0177,0331,0321,06,'s','Z',024,0251,0241,0260,0340,'j',0304,032,014,'h',0223,'/',0321,0177,')',0300,'%','0',05,'j',0332,0356,0364,0347,0250,0356,0177,0211,0351,0376,0300,0345,024,0214,0253,032,0255,0276,0347,'z',0220,0276,0353,0247,0315,0177,'.',030,'.','G',0346,0223,',',' ',0315,0250,0244,0301,'=','O','X',0304,'=',0300,'g',0312,'R',0326,033,']',025,'=','b',0242,0246,'|','#',':','|',0212,0375,031,'J','`',0366,0251,026,0326,'_','y','C',0332,'~','[','S',07,0337,0206,0342,0224,0240,013,0225,'5','c',0263,'L','n',0362,'>','&',0227,0244,'L',0334,'~','t',0254,021,0214,0263,0331,0240,034,0272,0342,0272,013,0371,0251,'"','t',0376,0354,0373,'T','*','K','s',0256,0226,032,',',0323,0202,'H',0371,0200,025,'`','1','Z','D',0210,0370,0231,0365,0345,'N',0257,'8','j','*','p','^',0327,0226,0221,0327,'o',0273,'J',0,0,'@','e','Q',020,0316,0357,'{',0233,0352,'J',0305,0310,03,0325,0245,0350,0220,0226,0235,0241,':',0252,'M',0262,'I',035,0224,0303,0330,0323,0311,0371,013,0233,0267,0354,0364,023,0220,0314,0257,016,0360,0336,0227,0221,0267,021,035,010,'}',0346,0226,'U','Y','P','w','p',0354,032,'*',0302,05,023,0230,0354,0352,'y','2',0255,0373,'g','6','}',0324,'o',0224,0255,':',0260,'m',0246,'y','f','-',0342,0323,'*','7','J',012,0213,0277,0356,0376,' ',0365,032,011,0357,033,0242,0374,0215,'H',0277,0220,0271,0234,0322,035,0236,'u',0210,'S',0210,0204,0351,'8','r','=','2',037,'y','8','V',0243,'N',0246,0344,'[',0267,0366,0215,0252,0304,0364,'c',017,'!',047,'R','7',0243,0242,0322,'A',0266,'N',034,024,'}',0223,0373,'@',0311,01,'u','i',0247,0241,'l',0371,'y','r',0232,'V',0240,027,0361,'j','(',0215,0367,033,032,033,0264,06,0307,03,'#',0322,0271,'0',022,0246,02,0262,0212,0326,0257,0370,0315,'M','-',0252,030,0321,'c',0324,0306,0336,0262,'S','&',016,0366,0373,0205,034,'L',0263,037,0221,0371,'j',0331,'|',0305,0263,0243,0263,0341,'c',0203,0344,0356,0244,0270,0331,030,0255,'I','[','0',0263,'i',0345,0241,01,'+','`','(','#',0244,0177,0341,'R','|','8',0344,'5','h','k',0265,0331,0271,0313,0351,'A',0303,'D','8','}',0237,'s',0265,'+',047,'n',0330,0375,0335,'~',0337,0340,07,'!',0246,'6',014,06,0315,'6',02,0233,'z','s','|',047,0221,'S','{',0375,015,0212,0226,0260,'n','2','y',0221,'K',0256,'&','[',0322,06,'t',03,025,0250,0330,012,'~',03,0322,'5',0301,047,0272,0351,0214,0265,0220,0226,'p',0255,0214,033,'w','>','k',0264,'x',034,0253,0312,0243,0201,0377,0,0344,01,'P',0335,037,'G','d',0276,0325,0371,']','m','D',0215,'l',0177,':',0210,0357,'-',02,'c',0271,0207,0335,'s','p',';','R',0177,'4',0365,0271,0225,026,0254,'x',0371,025,0354,0332,'/',0205,0244,0217,'s',0313,'e',0321,03,0355,0332,0242,'7',010,0357,0374,'4','+','1',',','}',0325,'8','e','*',0371,'y',0324,0254,'9',0377,0,0236,030,033,0367,0362,'}',0275,'%',0217,0261,'H',0316,0352,'b',0331,0325,'+','?','@',026,032,030,015,0217,')',0210,0244,':',0215,0202,0243,0226,021,0375,0335,'S',0365,'2','`',0367,']',0212,'F',0316,'C','5',0352,'|','(','"',0224,06,03,0220,'y','L','^','r','d',0241,0365,0360,'g','m',0251,0365,'7','!',0334,0232,'!',0252,'a','-',0366,'i','v','O',04,0276,0300,'z','q','?',0324,0200,'J',0272,'T',07,'j',024,'4',0375,0323,';',036,0346,0325,0212,0203,0201,0241,0247,0227,033,0271,'s',0352,0243,014,'(',02,0263,'{',0331,'v','9','z','4',0270,0350,0341,0325,'j','Z',0204,0336,'l','?',0365,';','y','X','x',035,'d','5','&',0343,0221,0256,'p','N','-',0227,027,'9',0244,0241,0274,'a',0346,034,'^',0276,0210,0306,0274,02,0234,0306,0206,'B',0347,0367,'W',0302,'*',0303,'N','v',06,0351,0362,'i',0303,0324,'2',0355,0307,017,034,01,'y','7','[',0273,0225,032,'$',027,'V',0222,033,'0','z',0357,0345,0223,0263,0354,'o','X',010,030,0272,0272,0324,0331,'~',010,0316,0217,0230,0240,'z','#',027,0270,0270,0271,06,'n',0325,0211,'A',0364,0303,'g',0354,'=',0337,'#','2','m','8',016,0363,0326,015,0350,',',0365,0200,0213,0257,0322,'N',0364,020,'A','c',0323,0311,0310,020,0347,'F',0331,'Z',0364,'R',0201,0371,'/',035,'j','{',0254,026,0221,017,0376,0253,012,0232,0260,0342,'3','t',0362,0334,02,'K',01,'A',0232,0305,0351,0265,'L','6','@',0255,'q',0337,'D','^',0310,'X',0354,0365,0370,0316,0256,0347,0307,0375,04,0353,0233,0333,0310,0305,'X',0211,'|',0203,0233,'c',0332,0263,0214,020,0344,0354,0363,']',0337,0325,0275,0203,0233,'O',0345,'=','5','H',0253,0377,0,'b',0333,'5',0254,'|',0270,'M','P','d','k','A',',',027,'k','!','E',0307,0261,0375,0364,'^',0326,0240,0210,0265,0370,0306,0243,0254,'%','?',0304,0305,0317,0216,'R','X',02,0364,02,0262,0362,'{','`',0261,0344,0266,0355,'F','m',0322,016,0200,'z',0270,0274,'i',0177,0225,'j',0303,014,0275,'*',0274,0216,'Z',0215,013,0366,'E',0335,'*','f','X',0134,'i','X',020,0236,'N','z',';',016,'o',014,'}',0315,0363,0350,0206,0366,'i','s','Y',06,'k','L',0272,'a',036,'[',0233,0233,0237,'C',0215,'r',0270,022,'5','Z',0233,'b',0324,'Q',0303,'s',0300,0370,07,'Y',0365,0213,04,0266,'+','?',016,017,0303,'j','@',0341,'J',0264,0257,05,0252,0231,034,0202,0326,'4',0201,0215,0245,'F','6',0234,'a',0306,0327,'4',0212,0202,0202,0200,'*','v',021,0247,0342,'(',023,032,01,0200,'z',027,0347,0307,' ','W','V',0245,0313,02,'[','y','j',0366,':',0361,0215,'h',0204,'|',0331,'q','w',0300,0366,0240,0345,0320,'c',0255,'L',0327,'W',0326,0340,016,0333,0311,0375,'x','O','%',0333,0314,0335,'<','l',0224,']',017,05,0244,'M','j','r',0200,0212,0204,0207,0200,0225,0232,0256,0243,0236,0242,0242,0230,026,'q',0312,024,')','a','-',0376,0246,'C',0323,'/','E',02,0355,0312,0303,'}',0347,'w',0227,034,0203,0320,030,0243,0261,0253,0240,0324,011,0347,0205,026,0,'z',0331,0374,',','~',0367,'*',0177,017,0221,0212,0325,0302,0261,'m',0232,0370,0251,'v',0226,'4','Q',0300,'S','g','#',0200,0326,0273,'6',0271,0370,'L',06,0351,0235,'>','0','Q','o',0,0226,013,0265,'l',',','_','f',0224,'h',0324,'J',0,'g','W',0225,'S',0250,0325,0356,0324,032,0246,'{',0273,'[',0350,0344,0321,0317,0205,0330,0232,0255,021,0262,'z',013,035,026,'J',0321,'<',0316,07,'W','.',';',023,0222,0254,0216,'M',0231,0275,'5',0203,0334,'c','`',014,0,0365,0260,0210,'R',0357,0265,'-',0367,0263,'#','(',0254,0205,'0','5','t',0246,'V','[',0305,0227,0264,'h','A','(',']',0262,0310,0353,'C',030,'S','B',0256,'S',0245,'7','B',0310,0332,0221,0223,'+',0341,'0',0264,'1','>','|','1',034,'o','?',023,'=',0371,'x',0250,0305,'4',0340,0300,0331,034,036,0216,'U',0217,0235,0204,0322,013,'|',0227,'u',0265,'_','K',0255,016,'C','`',0267,023,0242,'%',035,0245,0214,0332,0271,0350,'s','(',0373,0364,'X',026,0,'z',0354,'r',0276,047,'z',0201,0223,01,'u','i','y',014,0353,0277,02,0233,0232,0227,0231,032,0202,0241,'W',0361,'Q','#',0220,0255,'(','_',06,0224,0352,0265,0332,0200,0,0200,0260,024,033,'F',0177,'}',0277,0345,'"','U',0225,0305,'x',031,' ',0346,0334,07,'v',0301,0351,0347,'c','$',0214,06,07,'"',0341,0304,0220,'a','z','n',0327,0321,0233,'B',0336,034,0315,'g',0250,0255,0327,0327,'`',0356,0312,0375,0313,0341,0212,0334,0347,0307,0210,0220,0227,'Z',011,'&',0306,024,0231,'1',0242,0221,'u',0336,0301,0241,'I',0332,'R','X',0231,0316,0235,'4',0257,0,0204,0273,0213,0241,0255,023,0261,0356,'o','S',014,022,'3','u',0211,'9',022,0227,0253,0241,0,0344,'h',033,034,'0',0321,0250,0345,0234,0354,0222,'U',0200,'e',026,0371,0316,0343,047,'O','0',0237,'w',0220,0344,'{',017,'t',0342,0306,'&',0207,0263,0,'S',030,0361,'|',0331,0275,03,0253,0237,0256,0271,0306,016,0314,'U',0353,0370,'Q','K',0243,'?','t',0214,0222,0267,'W',0301,010,']','h',03,'5',0325,'v',0307,0224,0240,':',0324,'A','d',0334,0245,',',0332,'T',0272,0370,'8',04,0253,01,'G',0234,0276,0376,0251,'M',0256,06,'m','*',0364,033,' ',0221,0321,'K',0233,0202,0214,0314,']',0207,0243,0237,025,0252,0326,'U','`','>',03,0270,0327,0313,06,'H',027,'V',0220,0332,0356,'-','%',0372,0322,0362,0215,'8',0203,'9',0330,'(',0303,0344,035,'u','=','p',02,024,0253,0,0244,'l',0235,021,0257,'Z','Y',0241,0312,0325,0257,'L','4',017,020,0235,0201,'z','l',034,0262,0220,0134,015,0247,'6',0205,015,035,021,033,0342,'5',0202,0246,0252,'Y','|','"','/',030,0231,032,0370,'@','Z',0227,0273,0334,0337,014,'E',01,'d',0341,0321,0301,0347,'X',0325,010,0362,'a','8','H','!','Q',0204,031,022,0202,0357,0344,021,0216,015,0207,0225,0237,0217,'o',0374,'k',0304,'`','@',0273,')',0277,'W',03,0235,025,'J',':',04,'@',036,0273,'y',03,'2','2',0360,0134,0233,0227,034,01,'%',0262,0263,'H',010,'n','5',026,0213,' ',0246,'A','^',011,0300,'*',030,0273,0240,0330,0270,'_',0301,'n',0256,'_','v',0225,0205,'g','~',0260,0366,'9','p',014,'z',0202,0263,0303,0343,'_',0365,0305,0202,0231,0221,'b',0307,0356,0334,0371,'E',0313,']','6','E',0356,'b','i',034,'Y','j',0340,0377,0,0204,031,'w','^',0271,0313,013,0246,')','&',0310,0315,0253,0311,'k',0263,'_',027,020,0225,0312,0246,'(','<','#','*',016,'a',0310,'Q',0224,0207,05,0235,014,0370,'3','A',0264,0312,0235,'R','V',0263,0300,0305,0320,0326,0211,'X','/',011,0344,'P',0275,0220,'p',037,'T',0313,'4','C','R','b',0267,0263,036,0347,0314,0367,0236,023,0364,0367,'.',014,0211,'Q',0336,'C','=',0241,0356,'=','<',0206,0277,'(',0315,0360,'d',0342,06,'T','|',0230,'A',0367,0375,0203,0353,0215,0260,0245,0134,0212,'R',036,0314,0327,0255,'`',0215,0223,'W','J','S','%',';','x',0332,0373,0260,'T',0345,0272,0242,'`',0301,0233,0201,'A',0230,0274,0225,'*',0244,'d',0334,0250,0223,023,'k','R',0252,'[',0264,0340,022,'0',05,024,'M',0357,0277,0252,'C','k',0201,0233,'V',0333,'b','3','t',0344,'q','h',0220,0245,0331,0216,031,0235,0270,0205,0300,030,'<',0203,0326,017,0221,0272,'t',034,0350,023,'h',0367,0361,'a',0256,'&',' ',011,0354,'B',0332,0257,0256,0336,0216,0314,0214,0274,027,0353,'+','s',0257,0217,047,'J',022,'0',012,013,'Q','b',']','(','<','C',0302,'&',0334,0307,0306,031,'x',0300,0374,0370,'C','X',0327,';',0334,0336,'1','R',0243,0310,'H','J',0233,0226,'l',0312,0277,'Y',034,'3','a','!',0374,03,'#',0255,024,0314,'8',0200,0221,0342,'$','(','.',0,0225,0251,0214,0265,0324,0301,'m',0320,'A',0323,0206,0327,0216,0327,025,036,'v',0240,0,010,013,01,0353,'a','b',0206,'2',011,0301,0233,'W',0326,0325,0306,0134,01,0177,02,0206,')','#',0341,'8',0345,'{','T',0312,'%','%',07,'0','2',0370,'Z',0357,0220,0322,0202,010,',','V','v','[',0217,'c',0373,0344,0235,0326,0254,0231,0245,'N','L',':','8',0231,'N',0336,027,0370,0234,'@',0235,'T','F',0277,0274,':',0361,'Y','z','r',0306,0370,0347,'g',0255,0254,022,0330,0251,'O',0223,0365,0352,0254,0273,0360,'5','t',0246,0372,'^','_',034,'w',032,0321,'r',0241,0255,'t',024,034,0250,'x',0355,0323,032,05,'<','c',',',0351,0315,0245,']',024,0212,0307,021,0305,0320,0326,0204,0330,0367,'*',0332,'S','|',0274,0346,0242,'1',0240,'>',0374,0234,':',0300,'&','+',0364,0200,0322,'s',0177,026,06,023,0206,025,'U',06,0263,'q',05,0262,0224,'M',0246,0202,0332,0207,014,0211,'@',0307,0223,0201,'Q',0251,'~',0204,'Y',0367,0244,0365,0365,0270,032,013,0317,0315,0377,0,0265,0205,'Z',0336,'V',0355,0374,'S',010,0304,0336,0213,0230,'4',0241,'0','$',0242,0300,0332,0226,0206,0340,0254,0235,014,'5',0250,0301,'c',012,'"',0,0225,0300,'(',0344,031,0357,'M',0251,'|','6',06,'+','G',0242,0263,':',0351,0310,0362,0355,0351,0210,0310,047,0370,0327,'^',035,'H','F',011,'l',0353,'#',0255,';',0260,0344,'3','8','W','3',0337,'g','8',0354,'8','a',0211,')',0362,'.',0365,0255,033,0211,0134,0364,')',023,0231,0134,0264,'*',0353,0331,0274,0310,0361,0307,'q','U',0252,0,0246,'J',011,0206,0223,0177,010,0272,0241,04,0214,0225,'k',0343,'(',0244,'p','C','3',0302,'f','+','d','~','|',' ',',','k',0331,036,'b','v',021,'&','A',0213,0320,'q','.','(','Q',0312,'V','O',';',0272,0360,'L',0323,04,030,0252,'!',0336,0221,0221,'K',0253,0237,014,0345,'%',035,'s',0365,0331,0353,'q','$',0227,0237,0233,0177,'j',0364,0211,'m','F',0237,'i','R',0276,'-',0200,'G',025,']','L',0222,0200,0306,0233,'S','1',027,'5','1','H',0315,'L','@','E',0215,0324,0341,0312,'J',0322,'B',0332,0353,0372,0243,0,0200,'@',024,0330,0263,0225,0252,0200,0,'@','`',036,'d','|','U',0317,0337,07,024,0201,'"',0231,'e',':',0367,'8',037,0235,0224,'$',0207,020,'n','{','N',0306,0366,0371,0337,'b',0274,0245,'/',0373,0267,0241,0332,0315,0362,'a',047,0227,'9',0360,'~',0275,024,0270,0253,0325,0253,'c',0312,0335,0277,0215,0303,'a','u','S',0357,05,0367,')','d',0214,023,'@','!',0322,0225,0250,0264,0242,026,'E','A',0270,'4',013,0245,0300,'U',0356,0134,'u',032,0223,0342,'c',0220,'f',0264,'_',0333,0276,'e',0232,0371,0250,04,'n','4',0267,0327,0306,0347,0325,0303,'-',0313,'#','5',0343,0333,0201,'+',0374,0366,047,0205,'B',02,'V',0300,'Q','#',07,'6',023,0353,0313,0320,'s',0312,0357,'#',':',022,'f','~',0260,0177,'i',0306,0345,0237,0355,024,0263,0342,'0',0263,05,0206,0225,020,0200,0234,'/',0375,0371,'#',0340,0262,'2',')',0357,'&','5',0225,'.','e',0254,031,'x',0215,034,0230,05,01,0334,'s',0253,0335,0340,':',012,0350,0250,'a',0265,'M',026,'`','Y',0321,0341,0225,0242,0303,0222,0202,'X','.',0326,'J',0231,0333,0363,0300,024,0304,'&',0230,0234,'!',0224,025,0336,'&',024,0356,'8',0,0351,0276,0334,0256,034,' ','d',']',' ','>',0301,0362,0203,'#','J',0340,'+',0260,0221,'|','?',0264,0335,'7',025,0226,0224,012,0260,031,0265,'4','6',0216,016,0365,0201,'g','u','c',0275,030,'*','E','c','B','h','[','c',0317,0237,'*','d',0304,03,'&',0260,'"','p',0321,0314,0362,'5','6',0203,',',0207,'Z',0301,0277,01,0253,0245,'7',0222,0362,0370,0226,'3',0200,0320,0250,0212,'(',047,'L',0236,'2',0353,0341,'c','o','X','s','x','E','^',0227,'?',010,0371,0345,0350,012,'X','n',0342,'4','=',0334,'2',0324,0214,0310,07,0353,0200,'G','%','m',0270,0134,'w','s','z',04,'~',0351,0344,0336,0231,0326,'d',0321,0317,0356,']',0360,0225,0345,'F',07,'6',0234,0370,'7',011,03,0225,'"','Q','`',0202,0307,'z',0221,0336,0341,'c',0357,0363,0307,0201,0241,'1',0253,'"',0257,'B','b',0256,'&','Y',0273,0255,0,'V',0315,0320,0240,05,02,0302,0257,0321,'$','I','N','D',0357,0252,'G','s',':',014,'B','J','9','Y','s',0253,0225,06,0276,026,')',0317,'@',0242,0372,024,024,014,0236,'D',0377,0,'M',011,'3',0300,0310,0364,05,05,'{',0356,'o',0213,'p',0346,0377,0,0314,'>',';',031,0333,07,0327,017,0356,'4',0276,0374,0213,0345,0270,0212,0275,0206,'8','4','(','h','c',0226,0256,'k','_',0310,047,027,'3',0317,'*',0221,030,'N',0213,0377,0,'c',0216,'*','B',0341,0374,0333,016,0365,'q',',',0336,0204,'!','u',0243,0277,0256,0252,0375,0375,'e','=',0224,014,'i','g','4',015,022,'`','i','Q',0177,06,'h','A','%',0312,':','i',0250,0204,011,'[',01,'D','#',0256,0376,0251,':',0302,015,'j',033,0323,0320,0240,0227,'&',';',0210,'s','F',0134,'o','x',0310,'7',035,0200,0363,'J','T','i',022,0331,0266,0275,'i',03,0201,'*',0324,'X',0270,0377,0,0243,0344,0245,011,'d',0250,'g','S',0256,'u','x',0246,'/','*',0317,010,'%',0313,0267,0327,0245,'#',026,0271,0325,'k',026,0203,0265,'e',0311,0236,0260,07,0244,0265,0273,0261,'@',0213,0342,'[',0321,0343,'=',0205,04,0265,021,'$',0365,0251,0260,011,04,0345,'J',0245,'n',0265,'2',';',030,037,0237,010,0313,'v',0367,0177,0257,0242,0220,'h',0274,'D',0323,'o',0304,'b',0310,0270,0320,'a',0361,0302,032,0340,'8',0354,015,0320,0321,0217,04,'A',0371,0301,0345,0311,0255,0337,'A',0375,0357,'R',026,0335,0306,'O',0216,0334,0,0311,0200,0272,0264,0215,0262,0255,0265,0353,'W',0372,0375,0367,0246,'n',0276,0361,'P',0374,0202,010,0244,'A','&','M',020,'7','p','4',0245,'F',0301,0253,'H','L',0244,0325,0234,0321,0335,0247,0271,022,'S',027,010,0225,0212,01,0206,0366,0325,031,'P',' ',012,0316,'7','2',0351,'S',017,'D','+',0,0225,0270,0234,'I','+',0361,'>','?',0266,0315,0370,'J','N',0347,036,0134,'c','<','/','v',047,0301,'v',0220,'{',036,0134,0222,0302,'t',0232,0303,0265,0303,'S','3',0265,'?',020,011,0250,0370,0301,0332,'X',0177,'7',0376,0325,0221,0345,'l',0337,0306,0332,'Z',0231,'4',011,0310,0134,0374,'!','R',06,015,'F',0213,0235,'1','C',014,05,'s','p',0306,'m',033,'2',0240,'(',0203,'|','z',0315,022,0362,0330,0344,'3','Z',04,0340,0261,0315,'f',0276,0216,015,0324,0361,'q',0355,0317,'o',035,0354,0356,027,0357,0207,0366,'@',0277,0134,'a',0202,0231,'u',0243,'v',035,'F',0365,'"',0320,'{','<',0315,0235,'G','5','k',0340,0357,0177,0317,0347,0202,'7','f',0331,0226,'E','f','W','-',015,'*',0300,0206,032,07,0,0252,'K','5',033,0362,0342,0202,0221,'3','<','.',017,0327,'X',0325,0221,0267,'c',0221,0255,'c','Y','F',0347,0331,'z','G',0347,0245,0276,0270,0277,'i',020,0370,0263,0217,0340,'&',0353,0204,0327,034,'[','K',0274,0216,014,'"',07,0335,0363,'5',06,0264,'}','?',0367,0314,0220,026,0356,017,0336,0325,0210,0203,'}',014,0312,0261,0235,0233,047,'k','W','^',0217,0350,'U',0372,0261,'u',0276,0234,'x','`','f',0260,'i','0',0215,0216,0232,'<','r',0322,0255,0316,'v',0355,0250,' ',0202,0243,'/',0373,0335,0336,0237,'>',0225,016,0366,0201,'>','x',0220,'2',0324,'d',011,0343,0205,0367,0232,0201,'}',0236,020,'+','0',0266,'<',0201,02,0230,0355,0312,0347,0313,'Z',0300,037,'O',0277,'3',034,026,'J',0301,0245,0237,03,0315,026,';',0323,0242,'J','e','_','$','D',0227,0212,0300,'X',0305,0325,0326,0247,0234,')',01,0326,'0','d','z','P',0254,'u',0344,'8','`',0363,'H',0355,020,'>',0350,0260,0221,07,0212,0313,'c','f','o',0370,'p',0243,0316,0343,0352,'I',0361,'W','X','?',')',047,0216,':','%',0201,0323,037,'e',0243,'K',':',0210,0312,0311,'g',0314,'a',031,'%','3','T',0223,034,0222,'V',0224,0333,'0',0321,'y','V','B',0315,0250,0177,015,0201,0212,0323,0346,033,'G','7','N','G',0246,'q','9',0220,0241,0355,0303,0266,0205,0365,0265,037,'e',0301,0244,0271,0254,0224,'=',0275,0270,0211,'M',0247,0213,025,0306,'&','e',0201,0263,'X',0302,0367,0321,0250,0206,0317,0257,0375,0237,'O','l',0265,0367,'i',0341,03,036,0331,'=',0375,';',0335,036,'@',03,0303,0236,0227,'%',',','}',0234,013,0277,0274,0303,0361,0234,'^',0305,0351,0303,0361,0307,0310,0217,013,'~',0254,037,0217,'z',0230,031,'3',0372,0373,0364,0301,0344,0247,'j',0346,'l','j',0353,'@',0211,':','#','N',0264,011,0205,0,0300,'=','3',0245,010,':',0215,'?',0204,0250,'J',0272,0360,0214,'"','D','g','$',0374,0274,023,'P',0224,'B','S',0307,0222,0330,0240,0245,0332,'8','c',035,0242,0354,'K',0330,0362,021,0333,'7',0330,0371,0212,0207,0257,0334,017,'M','o',0254,0320,0324,'c',05,'C',0217,0247,'I',0212,0220,'T','[',0354,'Z','q','"',0263,'q','v',027,014,0234,'s','K','0','/','s',0205,'*',020,'A',014,'D','u',0302,0217,016,036,'`','H',0373,0361,0343,032,047,0245,033,0262,0324,'h',0325,0233,0213,0234,0217,0244,0263,0227,0373,0264,0360,0310,0237,'c',0335,0353,0361,0352,0,0257,02,0355,'/','g',013,'p',0225,0202,'A',0356,0321,0357,04,'v',03,0353,0206,'2',035,0244,0266,0373,'x',0227,0337,')',0242,'s',034,0241,0362,030,'a',0,016,'n','>',0363,0336,0243,031,0217,0374,'>',0375,031,0331,'s',0265,031,0226,';',0326,'|','9',0334,0312,0201,04,026,'=','8','>',0300,'H',011,'Z',0222,'I',0270,0263,05,0267,'A',07,'N',030,'K','$','$',0351,0367,0336,0234,'V',0243,015,0250,'=',0206,036,0224,0220,0335,0304,0201,0204,0341,0302,0257,'&','#',';',0357,'>','C',013,'0','?',0206,0261,'P',0331,' ',0352,036,0216,0316,'[',0354,0322,0244,'@',0240,0333,'z','1',0354,0337,'6','c',0352,'2',0362,'@',0334,0270,0270,0205,0212,0344,0317,'x',0346,0207,031,' ','m','f',06,'C',0234,027,0243,0205,0242,033,0210,03,'#','Q','L','A','=',0261,0354,'x',0360,0307,'Y','i',0243,'B',0364,0264,'4','j',0302,0304,0247,0221,0364,'6',02,0377,0,'v',0236,030,'e','+',016,':','}','}','N',0236,032,'l',0213,0334,0225,0364,0216,026,025,0215,0241,030,012,0203,0204,' ','#','7',0255,047,0257,036,'-','B','I','-',0201,0370,0305,0305,'k',0214,'o','%','g','C',0365,0362,'!','d',024,0177,035,'z',0324,0300,'0',0377,0,0227,0337,0240,')','%',0342,0260,'6',030,0352,0353,'X',0242,'I','G',0244,'z',0235,034,'9',0210,'>','Q',0347,034,'X',0224,0344,0204,'e','=',0347,0310,'H','x',0211,' ','!','*','|','U',023,0235,'~',0262,'8','^',0310,0245,0230,0221,0250,0222,0263,0321,0355,0336,0366,0216,';','a','=',0305,'g',0351,0351,'Z',0351,'c',0236,'T',0220,0303,0347,0332,0253,'v',0332,0202,034,0244,'N',0206,'m',012,'p',021,'9',0256,'o',0250,0302,0202,0343,'t',033,'9',0367,037,'a',0305,0255,'b',0313,0210,0366,'!','m','W',0311,'i',0312,010,'u',0276,0312,'z',032,'q',014,07,012,'[',011,'q',0202,0332,'@',0266,'k',036,0316,0367,0251,'8','e',0376,0374,0353,013,0235,0273,'o',014,021,0204,0337,034,0243,0324,0205,0372,0244,0372,'e',0254,'n',0355,0305,')',0261,'.','R',0134,0352,0216,0252,02,010,026,03,0311,0213,'y','-',0223,'-',0350,'l',0274,'n',0234,0215,0222,036,0274,'"',0241,030,'L',0350,0241,0267,'!',0271,0373,'s',0334,'x',0360,0276,':',014,'=',0276,'*','t',047,0330,'g',0373,'o','4','v',0227,01,'Y','7',0342,0352,0326,'9',032,0303,0333,0351,0352,'L',02,0316,0310,'*','c','v',010,'~',0335,0327,0212,'>',0317,'D',0277,0375,0207,0376,036,']',0372,0300,01,'y','=',0323,0331,0333,0213,020,'C','L',0277,0236,'a','A',0250,0357,0240,0350,0230,047,023,0227,012,'^',0203,012,'x','`','2',')',0241,'o',0354,0371,0226,0222,0335,0272,032,0321,'7','v',0371,06,'m','F',021,'A',0276,0376,0246,'r',0364,'-',0203,0361,0375,'[',0211,0213,'C',0312,'%',0267,'Z',0334,0266,'Q',0220,01,0,'e',0345,0221,0300,'>','T','B','4','_',0241,0326,0254,':',0230,';',0234,'M','f','c','{','?',0265,'g',0337,'Z',0,'F','F',0342,'q',')','m','&','Y',0373,0343,0336,0257,'f','o',0356,0324,0362,0324,'!',0236,0365,0332,0202,0,013,'i','X','>',')',0227,'K',0324,0202,033,0207,030,0255,0236,'f',035,0331,'R','2','*',0272,0274,'/',0374,'@',0345,'Z',024,'R',0341,0213,0222,0303,0245,'n','r',0347,0346,0300,012,'#',027,0377,0,0225,0334,')',033,':',020,0204,'x',0260,'K','&','0',0374,0232,0272,'i','<','6','e',017,0300,'5','2',0217,'"',0201,026,'7',034,0267,0362,01,'P',']',0247,'A','w','q','t',0250,'"','u',02,0366,0223,'u','9',036,0246,0377,0,013,'>',0372,0356,0203,'7',0355,0247,0217,'4',0265,0323,0220,'@','r',0342,0221,0225,0205,'7',0327,0371,0362,0363,0311,'O',02,'k','7',0303,'?',020,0220,031,'!',010,0353,'P',0224,'-',0220,'G',0303,'3','<','L',0343,0204,0241,0301,0333,'f',0224,0355,0302,05,011,'H',0244,033,037,025,0206,'<',0277,0370,0247,047,0274,0177,')',0313,0366,0353,0377,0,014,0254,0323,0362,0212,'j',0377,0,0211,0225,'w',0302,013,0327,'I','K',035,0315,0250,0307,0205,0362,0374,0365,0240,' ',0200,0260,036,0242,0321,'R',0351,0262,0375,'Z',0263,0243,0355,0266,0375,'_',0210,0220,'Y',0242,017,0374,015,0322,0211,'`','G',0320,0327,'W',0177,'=','c',0243,017,'J','R',0244,030,'t',036,0303,0321,0317,0210,014,0352,'(','+',0210,0353,'Q',0333,0226,011,0231,0232,'k',0315,0211,0230,'p',0344,'d',0214,0275,0305,'{','M',017,0311,'N','A','s','(',0345,037,'3','Y','1',0347,0377,0,'U',011,0323,'@',033,'f',0301,0367,'K',0316,0316,'!',0354,'R',0203,015,0223,'?','z',010,' ',0261,0352,'a',034,'|',013,'>',0362,0253,0226,'S',0374,0213,'}',0134,0373,034,'A','R','#','J',0254,05,032,'&',032,0206,'I',0271,0326,0357,0241,0204,']','@','r',0371,'5','3',')','o','C',031,014,0223,'1',0327,0210,0320,'1',0330,'C',04,'h','{',':',0261,'.','G',0376,'W',0237,0370,0326,0253,0227,'7','u',0371,037,0226,0276,0276,0241,0263,0364,0361,0256,03,'!',0272,030,0314,0203,0261,0317,0321,0337,0364,0225,0260,'>','7',047,047,0255,'!','~',0211,02,0304,'x',0340,0312,0205,0356,0313,0347,'b','o',0221,0252,'q',0205,0263,023,0374,';',':',010,'q',0246,0354,0335,0235,'b',0223,0320,'K',0375,0215,015,0216,'4',0303,0360,0270,'9',0215,'9','j',0354,'_',0322,'`',0373,0216,0,'g',0370,'=',035,0222,'}',0242,05,'d','L',0236,'1','d',0362,'z',0341,0362,0216,0243,'V',0231,0237,0134,0346,'n','[',0374,03,0254,'S',036,'P',06,'"',0317,0370,0275,0375,0224,0345,0221,'*',0305,0343,0311,'`','T',0206,0134,0271,0271,0341,0255,02,0367,07,0,'2','=','6',0225,0237,014,0311,0323,'O','C',0222,'"','~','E',0213,021,'8',0344,'W','"','+','f',0211,'!',033,'|',027,0371,0354,0241,'v','2',0177,'X','z',0322,'F',0266,0305,'=',0223,0221,'/','*',0232,0207,'O',0356,0215,'Y','w',0362,027,0267,0316,'*',0333,'M',0371,0345,0255,07,012,0305,05,0200,036,0243,033,'g',0344,021,0207,0325,0222,0233,'$',0300,0334,0376,0233,0236,'D','Q',0253,'?','H',0275,'q',0336,0257,0225,'Z',0363,'y',0343,0327,'m',0350,'R',0244,'0',032,0211,0352,'y','s',0200,0235,0330,'c',0315,0232,'/',07,'K',0343,0357,'<',0210,'6',0362,'m',0375,'6',035,'7',0342,0342,0354,'b','j',0134,016,01,0240,'z',0253,014,'|',0322,0321,0370,'>',')','!',0334,'_','j',0276,0214,'O','$',0304,0373,'2','u','.',0331,'c',0215,'`','k',0257,'z','U',0316,0215,'-',0306,0345,0356,0366,0375,'G',0244,034,0221,'&',0223,'u',0243,0246,'0','1','M',0326,'[',0212,'n',0253,0225,0247,'q',0354,'m',0344,0313,024,020,'N',0200,'T','e',0262,0315,031,':','M','0','7',0365,0242,'=',0357,0216,0265,'1',035,0312,'o',036,0300,0222,0330,0304,0331,0326,'<',0246,015,'R',0313,0266,'L','*',0326,0344,'`',0335,0204,'K','v','h',0306,0216,0204,0355,024,047,023,'`','L',0336,'!',0333,0316,'8',0233,022,036,0355,'4',0311,'G',0363,'!','9','M',012,0301,0220,0350,0211,'0',';','5','~',0337,01,0337,'h',0350,'<',0240,'J',032,0,0327,0350,0306,0213,021,0216,0230,0330,0311,0356,0347,0353,0322,'H','n','R',0376,0265,0345,0376,'F','-',0313,'m',0235,'e','b','"',0303,'U',0200,0334,0363,'!',0200,020,030,0234,0363,0354,0250,0342,032,'%',0335,'@','*','h',0236,0313,0357,'S','1','1',0215,'v',0237,0265,'~',0201,0373,'*',0374,0235,0372,0324,'9',':',0210,0372,0245,0313,'#',0360,0224,0374,'C','w','5',0312,0314,'?',0205,'A','_',0265,0211,0354,0243,'K','j',0321,0336,0260,'=',0251,0212,0206,'m',016,'V',015,' ',0303,0224,0271,0205,0362,0322,03,0240,'%',']','*','w',0246,011,'c',0370,'=',0366,'(',0202,0345,0234,'u','u','w',0177,0302,0304,'m',0241,0275,0325,'.','U',022,0257,'D',033,'e',0321,016,0324,0364,0,'$','!',0210,0237,0340,0310,'7','l','X','s',0324,0371,'w','*',0332,0362,0311,'+',0261,0363,0337,0374,'c',0241,'e',0310,'+',0374,'%','Y',0366,'N',01,0357,0375,034,0212,'C',0346,0207,012,'1',023,0326,0311,0134,0306,0325,0377,0,0206,0252,0225,'x',0353,0207,0267,0364,'a',0201,'A',0,0320,010,03,0374,0227,0344,'b','=',0232,0337,0243,'j','P',0223,'r',016,'Y','A',0246,0363,020,'s','0',0350,0365,017,0177,'.',0201,0240,'U',0254,0201,0302,'F',0306,0204,0340,0337,'B',')',0331,0357,'.',0364,'l',0306,0200,' ','?',0315,026,0321,0,'?','F',0223,0277,0224,0335,'~','-',0221,'K',0200,0260,'>',0221,0354,0253,05,'f','B',0255,0226,0317,'O','D',0326,'R',035,0344,02,0244,'`','3','m',')','.','O','e',0351,0205,'J',0351,'K',013,01,'K','-',0335,0335,'_',0364,0361,'{',0324,'C',0322,0234,0335,015,0366,'0','z',0225,'5',')','M',0272,0322,'l','{',0323,0340,'/',0254,'P',035,0352,030,0315,0237,0222,0206,0311,'s',037,0322,'<',0203,')','X','-',':',024,0274,0267,0370,0270,024,'$',0217,0226,'3',0245,'G',035,0213,0327,'c',024,035,015,0231,0320,0376,'K',0225,0317,0235,0223,0267,0373,'`','!',04,0321,0254,'@','(','M',0367,'+',03,037,0262,0305,'c',0235,'T',0373,0251,0302,'}',0235,'0','V',0344,0371,032,0304,'G',0354,0275,' ',0257,0271,0245,0354,'V',0320,'8',0217,0360,0277,0377,0332,0,014,03,01,0,02,0,03,0,0,0,020,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,01,'%',037,0235,0344,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0220,04,0367,0377,0,0377,0,0300,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0200,0257,0377,0,0377,0,0377,0,0214,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0221,0177,0377,0,0377,0,0376,'`',0222,'I','$',0222,'I','$',0222,'I','$',0222,01,0,0200,'H',04,0202,'I','$',0222,'I',' ',0323,0377,0,0377,0,0377,0,0365,0304,0222,'I','$',0222,'I','$',0222,'I','$',0200,'I','$',0222,'I','$',0220,'@','$',0222,'I',05,0277,0377,0,0377,0,0377,0,0314,'$',0222,'I','$',0222,'I','$',0222,'@',0,0222,'I','$',0222,'I','$',0222,'I','$',022,'I',',',0377,0,0377,0,0377,0,0376,0361,'$',0222,'I','$',0222,'I','$',0222,'A','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','?',0377,0,0377,0,0377,0,0360,01,'$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,011,'?',0377,0,0377,0,0377,0,0342,011,'$',0222,'I','$',0222,'I','$',022,'I','$',0222,'H',' ',0222,'H',' ',0222,'I','$',0222,'I',0377,0,0377,0,0377,0,0377,0,'p','I','$',0222,'I','$',0222,'I',04,0222,'I','$',0220,'@','$',0222,'I',' ',0200,'I','$',0202,']',0377,0,0377,0,0377,0,0376,020,'I','$',0222,'I','$',0222,'A','$',0222,'I',' ',0202,'I','$',0222,'I','$',0222,010,04,0201,0217,0377,0,0377,0,0377,0,0374,022,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',0222,'I','$',0222,'I',0,02,0177,0377,0,0377,0,0377,0,0260,022,'I','$',0222,'I','$',0220,'I','$',0222,01,'$',0222,'I','$',0222,'I','$',0222,'I','$',023,0177,0377,0,0377,0,0377,0,0,0222,'I','$',0222,'I','$',0220,'I','$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ','H',0277,0377,0,0377,0,0365,04,0222,'I','$',0222,'I','$',0202,'I','$',02,'I','$',0222,'I','$',0222,'I','$',0222,'H',0,0356,'M',0377,0,0377,0,0241,'$',0222,'I','$',0222,'I','$',022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0366,'B',0307,0375,0240,'$',0222,'I','$',0222,'I','$',0222,'I',0,0222,'I','$',0222,'I','$',0222,'I','$',0222,'@',027,0355,023,030,0341,0200,04,0222,'I','$',0222,'I','$',0222,'H','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','W',0341,0262,0235,0362,011,' ',0222,'I','$',0222,'I',04,0222,'@','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,013,0277,0340,'-',0217,'v',011,' ',0222,'I','$',0222,'H','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'K',0377,0,0243,'5',0177,'p','I',' ',0222,'I','$',0222,'A','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0220,'=',0374,'k',0261,0364,0,'I','$',0222,'I','$',0222,'A','$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',01,0277,0323,'.',0221,0314,020,'I','$',0222,'I','$',0222,'I','$',0200,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0220,0177,0337,0247,0316,'T',022,011,'$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',037,0364,016,0222,0245,04,0222,011,'$',0200,'I','$',0220,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0223,0362,0271,0360,'c',04,0222,'I','$',0220,'I','$',0220,'I','$',022,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',0237,0377,0,0235,'?',0230,'$',0222,'I','$',0220,011,'$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',047,0377,0,0323,'t',0375,' ','$',0222,'H','$',0222,'I','$',0202,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$',0222,'@',033,0374,030,0351,0376,0311,'$',0222,'H',04,0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'@',0257,0363,'>','*',034,011,'$',0222,'I','$',0222,01,'$',0202,'I',04,0222,'I','$',0222,'I','$',0222,'I','$',0222,01,0277,05,0364,07,'R','I','$',0222,'I',04,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'D',0277,0347,' ',0200,'"','I','$',0222,'I',04,0222,'I','$',022,'I','$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'k',0375,0275,'/','n',02,'I','$',0222,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I',' ',0222,'I','$',0222,037,0304,'^',')','x',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0223,0331,0301,022,'I','$',0221,'?',0303,0377,0,0217,0244,0222,'I','$',0222,'I','$',0222,'H','$',022,'I','$',0222,'I',0,0211,0377,0,0377,0,'2','I','$',03,0302,0222,'8','~','d',0222,'I','$',0222,'I','$',0222,'H','$',022,'H','$',0222,'H',' ',0337,0377,0,0377,0,'2','I','$',0207,0220,'g','I',0303,'$',0222,'I','$',0222,'I',' ',0222,'I','$',022,'I','$',0222,'H',05,0377,0,0377,0,0377,0,020,'I',' ','c','W','9',0244,')','$',0222,'I','$',0222,'I','$',0222,'H','$',022,'H','$',0222,'A','7',0377,0,0377,0,0377,0,0352,'I','$','|','N','u',011,0370,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'A','/',0377,0,0377,0,0377,0,0364,'I',' ',0374,'i','k',07,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',022,'I','$',0222,'H',037,0377,0,0377,0,0377,0,0377,0,011,025,0377,0,0202,'n',0276,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',022,'H','$',0222,'H',027,0377,0,0377,0,0377,0,0377,0,01,'?',0377,0,0377,0,023,0252,'I','$',0222,'I','$',0222,'I',' ',0222,'H','$',022,'H','$',0222,'I',027,0377,0,0377,0,0377,0,0375,0251,'w',0377,0,0377,0,0375,0200,'I','$',0222,'I','$',0222,'I',' ',0222,'H','$',022,'I','$',0222,'H',04,0377,0,0377,0,0377,0,0377,0,0315,'?',0377,0,0377,0,0377,0,02,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',01,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0364,022,'I','$',0222,'I','$',0222,'I',' ',0222,'A','$',022,'I',04,0222,'I','&',0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0234,0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',022,'I',04,0222,'I',04,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0376,0200,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I',0,0222,'I',0,0177,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,'$',0222,'I','$',0222,'I','$',0222,'I',04,0222,01,'$',0202,'I','$',0222,'I',' ','_',0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0252,04,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0230,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',022,'I',' ',017,0377,0,0377,0,0377,0,0377,0,0377,0,0377,0,0311,'$',0222,'I','$',0222,'I','$',0222,'H','$',0222,'I','$',0222,'I','$',022,'I','$',03,0377,0,0377,0,0377,0,0377,0,0377,0,0355,0311,'$',0222,'I','$',0222,'I','$',0222,'A','$',0220,'I','$',0220,011,'$',0222,'I','$',035,0177,0377,0,0377,0,0377,0,0377,0,0370,011,'$',0222,'I','$',0222,'I','$',0222,01,'$',0220,'I','$',0222,011,'$',0202,'I','$',02,0377,0,0377,0,0377,0,0377,0,0377,0,0200,'I','$',0222,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,011,'$',0200,'I','$',0222,0177,0377,0,0377,0,0377,0,0370,0342,'I','$',0222,'I','$',0222,'I','$',0222,011,'$',0202,'I','$',0222,'I','$',0222,'I','$',0223,'O',0377,0,0377,0,0377,0,0375,0222,'I','$',0222,'I','$',0222,'I','$',0220,'I','$',0202,'I','$',0222,'A','$',0222,011,'$',0222,'o',0377,0,0377,0,0377,0,0302,022,'I','$',0222,'I','$',0222,'I','$',0202,'I',' ',0222,'I','$',0222,'I',04,0222,'I','$',0222,03,0377,0,0377,0,0361,'@',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I',' ',0222,'I','$',0222,'I',04,0222,'I','$',0222,01,'G','A',0310,04,0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I',' ',0222,'I','$',0222,'I','$',0222,'I',04,0222,'A',' ',02,'@','$',0222,'I','$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'I','$',0222,'I','$',022,'I',' ',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',04,0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'@','$',0222,'H','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0220,01,'$',0222,'A','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,01,'$',0222,'I','$',0222,'I','$',0222,'I','$',0,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'H',04,0222,'I','$',0222,'I','$',0222,'I',' ',0222,'I','$',0220,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',04,0222,'I','$',0222,'I','$',0222,'A','$',0222,'I','$',0202,'I','$',0222,'I','$',0222,'I','$',0222,'H','$',0222,'I','$',022,01,'$',0222,'I','$',0222,01,'$',0222,'I',0,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',0,022,'I','$',0222,'H',04,02,010,' ',022,'I','$',0222,'I',04,0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,01,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,01,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'A','$',0222,'I','$',0222,'I','$',0222,'I','$',022,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',022,'I','$',0222,'I','$',0222,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0202,'A','$',0222,'I',' ',022,011,'$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I',' ',02,'H','$',0222,'I','$',0222,'I','$',0222,'I','$',0222,'I','$',0377,0304,0,',',021,01,0,02,01,03,03,02,06,02,03,01,01,0,0,0,0,01,0,021,'1','!','A','Q',020,'P','a','0','q',' ',0241,0261,0301,0321,0360,'@',0201,'`',0221,0341,'p',0240,0377,0332,0,010,01,03,01,01,'?',020,0377,0,0301,0212,0267,'S',024,0334,017,0372,0305,0360,047,0267,'<',0277,'(',037,020,0377,0,'j',']',036,0375,0243,0352,'f','!',0243,0304,'U','m',0364,013,'f',0335,0362,0334,0315,047,07,036,0220,'+','D',0252,0335,0277,'{',0274,'9',0330,0226,047,'_','O',0354,0277,0236,0371,'1',026,'o','O',0202,020,'+','C',0275,'8',0300,'K','K',033,'z','t',0267,0367,04,'b',';',0322,0201,'l','J',0260,'z','b','3','2',0226,0357,'v','o',0323,0177,'L',025,0242,05,0331,'?','k',0275,0320,0335,'~','^',0245,'J',0365,0333,0275,0205,0273,0270,0210,0234,0236,0235,0235,0227,0317,0275,0271,0222,'?','N','J','v','3',0,030,';',0322,0201,'l','}',034,'1',0351,0231,0220,0236,0367,0134,0331,0337,0323,05,'h',0207,0253,0226,'{',0337,'8','>','^',0245,'M',0375,0273,0333,'9',047,0332,037,0265,027,025,0227,'F',032,'K',037,'G',0202,'_','>',0366,01,0134,'D',0267,'c',021,0323,'V','@',0314,'F',0222,0230,01,0374,020,017,0364,0267,0370,0333,0205,0274,02,0300,'w',0273,0373,'f','z',0247,'O',01,0274,0250,'*',0223,'+',0275,0307,'f',010,',',0307,0300,013,'3',011,0367,0273,0234,035,'v',035,'D',0217,'j',0204,'*',015,'_',0304,'a',0373,0211,'5','x','H',0301,0367,022,'c','E',0351,0231,0313,016,0366,0246,'H',0363,'=','J','o',011,'@','l',0334,'e',0366,0327,0303,020,'J','c',0201,034,0327,'0','j',0205,'K',0347,0210,04,024,035,'.',0371,'?',0236,0366,0240,'[',033,'O',06,'>',014,'K',0210,'=',0343,023,'@','O',033,'J',0275,'9','M',0324,'H',0315,0354,035,036,0367,010,0,'Q',0336,0376,0353,0370,0352,0222,0220,'K',0220,'W',0231,'y',0321,'r','K',010,'.',0311,0222,'"','}',0252,0134,'%',0373,'A','a',0342,'q',0320,'L',0214,0367,0270,0264,0362,0342,'*',0266,0364,06,0300,'G',0347,'`',0374,0312,012,'6',0134,'f','Y',032,0227,0373,'i','a',0343,0376,0300,'m',0256,',',0243,0240,'+','D','=',0134,0271,0357,'f',0230,010,0315,0365,0312,'5','T',0307,'*',0303,0215,0245,'Z','l','F',0363,'#',0345,0201,0346,0226,'Q','9',034,0270,024,'W','J',0233,0273,'w',0316,'0','>',0277,06,'W',0253,'H','q','(','B',':',0265,0227,'h','U','(','5',0254,0254,0272,'h',0300,'}',0342,0270,'p','{','t',0343,07,'|',0347,'g','W',017,'A',017,'M',0271,'y',0366,0227,'S',0334,0206,'e','c',0222,'R',012,'e',0362,'!',':',0316,0316,0360,0301,0320,'@','r',05,0210,0357,'n','d',0217,'3',0325,0306,0317,'w',0332,'c',0340,0313,'6',0247,0301,0226,'X',0231,0312,024,0222,035,0367,0225,0303,'~','u',0200,05,020,025,'D','*',0134,0271,0357,0234,'H',0353,'w',0354,',','f',0265,'R',0313,024,'`',0347,0314,'m','i','c',0220,'B','%',0324,'_',0367,0326,0263,0375,'?',0236,0371,0314,017,0323,0340,'A','w',030,'Q','R','1','Y','0',0300,0321,0301,0314,0255,0345,0347,'_','I','@',0264,0301,0323,'W',0301,0373,'S',035,0355,'L',0234,'f','z',0343,017,'t',0322,0311,0224,03,0310,'M',0246,0271,0304,'d',0303,0206,0230,' ',0275,'T',0325,0233,'c','}','`',0231,023,0304,'w',0315,014,0303,0255,010,0327,01,0367,0215,0257,',',013,'Y',0203,0270,'~',0265,0213,'[','|','L',0265,'+','[',0344,0224,0340,0267,0226,05,0264,'C',0327,0313,'=',0363,0226,0234,0373,'u',0305,010,'F','j',0355,0240,0361,020,0330,'U',0323,021,'r',0335,02,'%','*','I','L',0277,013,06,':','9','t',0267,0344,0376,'{',0341,';',0216,0331,036,0254,0202,0307,'5',0304,'l','[','_',0367,0,'W',0226,02,016,'4','%',0260,0207,0231,0232,0246,0253,0342,036,012,015,010,0224,0270,'3',0,012,';',0346,0204,'`',0353,'Z','o',0,0363,'*','u',0317,0364,0302,0316,'9','N',013,'b','T',0225,0264,0336,0223,0240,'D','o',' ','C',031,030,'L',0367,0316,'b','~',0235,'_',0245,06,0363,'Y','%',015,'W',0217,0323,0323,0204,'[','s',',','b',0375,0241,'1','U',0203,0363,0323,0226,037,0227,'l','Z',0325,0232,'`',0333,0342,'b',0201,025,0206,0367,'{',0315,';',017,0246,0246,'J','3','=','p',010,'2',0347,0304,'N','-',0204,'S',0351,025,'O','Z','3',0323,0206,017,0257,'l',0322,'5','3','+',0323,0217,0205,020,'3',014,0267,'o',0351,'q','!',023,0274,'c',0313,035,0353,0214,'M',035,0253,'.',0231,'o','5',0265,0217,0365,'9','A','4',0222,035,'?','W',0230,'u',0254,'z',023,'0',0306,'#',0265,03,'e',023,'i',017,0257,0241,0250,0260,0351,0370,0364,'y',0261,0372,'@','l',04,'K',0256,037,'>','b','R',0361,'y','f','Q','.',011,0356,0340,'7',0215,',',014,0264,0327,'8',0211,0316,0222,'[','g',03,0202,02,0264,'B',0327,0313,0236,0324,02,0334,'O',0,'z','#','M',0223,0311,'?',032,'<','D','g',0275,'=',0346,'^',011,0276,0326,'|',020,'V',0221,0307,033,':',017,023,'`',0215,0237,'x',0240,'[',',',')',0244,0320,0316,'o',0337,0336,0,'0','K','~','G',0347,0265,0320,07,0335,0364,0354,'K','m','~','>','$','>',0263,0330,'-','=',0342,0252,011,0316,0337,0324,031,'P','C',0372,'N',0357,'0',0241,'4','j',0276,'!','E','A',0244,0325,0217,0262,'K',0354,0263,0373,'p',0200,';','b','Q',0261,0230,0,0243,0265,0273,0375,'6',0364,0356,0233,':','|','Z',021,0227,0253,'[',0207,0322,']','}',0310,0211,'Z','1','p',027,0230,0233,'+',0230,0336,0346,0275,012,0201,0370,022,'D','f','F',011,014,0357,0333,'*','~','k',0324,0255,0335,0360,03,'`','#','3',0370,020,024,0313,'/','i',0331,0216,030,0211,'m','T',0322,017,0272,0300,0255,'%','-',0347,035,0266,0277,0350,0372,0226,0253,0177,0202,0347,0375,0237,033,'?','`',0356,'M','`',0206,'x','<',0302,0202,0202,'j','n',035,0272,0325,0343,0324,'p',';','A',034,'O','C','m',0333,'E','U',0276,0210,',',0314,023,0333,0253,'^','q',')',0247,0324,07,'n',0214,'>',0327,0246,0223,0232,037,0247,'p',0367,0226,0277,0307,0340,'C',0270,0351,0177,'G',0361,0201,0346,'a',035,0257,0360,'r','9','9',0372,0177,0203,0331,0301,0307,'t',0326,017,'o',0341,0223,0336,0204,0366,0277,0301,0310,0344,0347,0374,036,0316,016,';',0276,0230,'{',0177,0,036,'f',021,0332,0356,0376,'i',0376,07,'0','?','N',0363,'}','X','u',0365,0265,0234,016,0365,0244,0262,'~',0276,0253,0206,'F',031,0236,0367,'w',0263,'o','S',0222,0234,'w',0315,'c','#',0323,'m','|','3','1',0337,'Z',0322,0367,'=',014,0307,'/','I',0363,0200,0207,'N',0376,0205,0301,'n','g',0235,0371,'~',047,0231,'<',0350,'o',')',0222,0266,'m',027,0377,0,014,0237,0377,0304,0,',',021,01,0,01,02,03,06,07,01,01,01,01,01,0,0,0,0,01,021,0,'!','1','A','Q','P','a','q',0201,0301,0321,020,'0',0221,0241,0261,0341,0360,' ','@',0361,'p',0240,0377,0332,0,010,01,02,01,01,'?',020,0377,0,0301,0212,0203,0304,0326,'&','p',035,0342,0204,0342,'q','~',0237,0232,'~',023,0325,0352,'R',0237,'O',0272,'S',047,0241,'@',0306,0134,0276,0350,0215,0244,0335,047,0314,0324,0337,0223,'3','3','s',0267,'p',0244,'^','U',0207,0257,'i',0247,023,'q','Y',0357,0215,'#','$',0276,'D','7',0220,'9',0315,0272,0355,0311,'#',0300,0315,0341,'H','3',0334,0235,0134,0376,'7','y','@',0202,'V',0215,0234,'W','x',0375,'a',0266,0361,0370,0360,':',0273,0251,0214,0305,0375,'m',0336,0134,'P',034,035,'{','z',0351,0266,0333,0342,'d','j',0376,0306,0222,011,'_',0320,'n',0362,0336,'3','S','{',0247,'z',0,'A',0206,0332,'B','`','S',0233,'a',0201,0241,0337,'_',',',0315,0263,'7','C',0366,024,04,0300,0333,'@',0311,01,'K',0303,0215,0373,0336,0236,'Y','3','*',0200,0337,'s','u',0177,'a',0266,0345,0251,'f','-',']','8',036,0357,0226,0210,011,'Z',030,0355,'M',0306,0235,0366,0335,0305,0326,'t',';',0276,0307,'/','2','8','W','p','i',0277,0213,0226,0333,0314,0347,0203,0257,02,0222,0244,0255,0327,0313,0262,0366,'`','j',0366,'>',0265,0333,'k',0235,0217,'}',0305,'f',0327,0201,0241,0247,0227,047,'X',0342,0364,0342,0320,'P',0200,0260,'m',0247,'M',01,'P',0215,0300,0352,0361,0366,'<',0261,0316,0357,0266,0366,0262,'{',0305,0325,0327,'m',0312,'=',0214,'Z',0272,'r',0317,0177,017,',',0321,'J',0324,0243,'x','z',034,'=',0335,0267,'{','z',06,0275,0276,0253,033,0276,0134,'A',0335,0203,'C','^','.','[',0270,0355,0267,0134,0243,'W','J','a','%',0177,'A','D',0360,'h','A',047,0223,'j',0272,0217,'c','?','M','v',0332,'u',0200,0273,'O',0260,0233,015,0332,0361,'~',0250,'A',0270,'x','!',030,0225,' ','W',0376,0307,0213,014,'Z',035,0334,0250,'q','@',0261,0266,0345,0322,0317,'S',0247,03,0347,0207,0215,0211,'m',036,014,'I',024,'q',0266,0353,'B','7','?',0201,'N','U',033,0346,':',0272,0355,0273,0223,0320,'5',0355,0365,0342,'L',0362,0245,'x',0215,026,02,'V',0263,020,0360,0272,0256,'P',031,0317,0300,025,0202,0202,07,'S','q',0247,0177,0255,0267,0226,0326,06,0256,'E','(','r',0276,'2',0224,'P',0303,'4',')',0246,'4','K','*','&','0',024,0,0203,0302,'p','6',0311,0327,0267,0256,0233,'l',012,0220,024,0334,0221,0337,0237,0307,0360,'(',0363,0247,'9','U','4','j',0311,023,'D',0357,0232,0213,0360,'/',025,'7',0356,0357,0272,0200,0201,01,0266,0361,023,0213,0247,0177,'M','|','e',0315,'-',0266,012,0235,02,0325,'-','W',0244,'0',0222,0206,'`','U',020,0357,0247,0206,'3','o',0261,0255,015,'v','=',0367,0273,'l','d',0321,035,0371,'|',0322,'5','%','|',024,022,0323,0243,0221,0205,'E',0353,'R','C',024,0232,'f',0325,'h',0301,0250,'<',011,04,0255,'s','H','z','r',0371,0333,'n',0314,0134,'k',0224,0231,0241,0247,0354,0374,'V','&','t','L','a','G',0233,'t',0244,0231,0300,0240,'a',0235,0251,0300,0242,0336,020,0201,0273,0203,'C','^','y','n',0343,0267,'.',0246,0266,0367,0261,0363,0313,0370,'`',024,'*',0222,0231,'%','v',0207,05,'&','9','e','N','=',017,013,'W',0324,'t',0357,0367,'A',026,'6',0335,0361,0350,0232,0366,0372,0361,01,'-','!',01,'j',0236,'Q',030,'d',0254,'<','#','L','P',0,025,0234,'V','.',0206,0264,')',0300,'m',0274,'"',0317,'w','"',0230,';',0277,0243,0227,0214,0354,0223,032,0215,030,'T','$',0306,0204,'o','e',021,022,0234,0222,0201,026,'(',0321,'J',0324,'G','z','z','p','6',0345,0344,0321,0336,0346,0366,0335,0307,0307,'v',024,0210,0264,024,0262,0252,'D',0337,0301,07,0225,0361,0212,015,0334,033,0265,0347,0226,0353,0355,0313,0337,0255,0270,0373,0370,0376,034,'L',0351,022,'>',010,0353,'@',026,024,0353,'Y','x','4','V',0246,0367,'N',0373,0270,0320,01,06,0333,0311,013,03,'W','"',0224,0231,0361,'2',0252,0221,0212,0226,0310,0322,022,0317,0204,030,'K',026,0204,015,'c','6',0373,031,0264,'I',0330,0367,0337,0266,0326,'.',0325,0351,0310,'7',0352,0366,0335,0342,021,'b','S',0262,'P',0252,'J','r','=','j',021,'1',032,0316,'a',0251,'S','z','"',02,'V',0216,']',0363,'v',0356,'_',';','r',0344,0352,'n','4',0347,0361,0307,0304,0235,0345,'N',0263,0251,'@',0362,0250,0264,')',021,0206,0231,0272,0324,0,010,0360,0221,0203,0203,0257,'o',']','6',0347,'*','3','W','#',0366,'T',0321,'J',0273,0342,024,'M',0263,0250,'y',0300,0251,'P','T',0243,0312,0240,05,0350,0250,0226,0242,',',02,0247,015,'e',0323,0213,'D',0212,03,'m',0254,']',0253,'c',0312,'7',0352,0363,0370,0361,0263,'1',0312,0243,'m','4',0322,'1','4',0226,'J','!',04,0225,0233,0346,0245,015,'(','Y',0232,'9',0351,0272,0272,0355,0313,0317,0251,0270,0373,0370,0361,'t',0220,'P',0251,'$',0251,'9',06,036,010,0263,0251,'&',025,'5',0,'6',0323,0302,0327,'i','n',';',0271,0377,0,0335,0230,02,'T',025,'"',0263,0335,0207,0256,036,0223,'V','@',036,0257,0275,0275,0253,033,0134,0240,0370,')',0271,0261,0243,0177,0277,'z','2','|',015,'x','y','y',011,'{',0271,024,0204,0317,0210,0231,'A',0215,'M',034,0260,0236,'0','x','X','n',0263,0330,0317,0323,'f','K',0360,'s',03,0213,0320,0366,0245,0262,'t',',','z','w',0237,0344,':','B',0134,0240,034,0253,'&',0377,0,0274,'|',0253,0221,0243,0275,0315,0355,0367,'N',035,'K','I',032,0206,0204,'M',01,'8','5',030,'4','%','%','9',0363,'P',0262,'I',0341,0314,011,0320,0327,0366,'t','$',0300,0331,'H','c',014,0351,047,0252,0275,0215,0336,0276,'D','Z','d',0363,0313,0336,0334,0374,0233,0327,0323,'>',0360,'9',0322,0202,'Z','K','X',030,'V',0237,025,'1',0316,0211,0325,0245,'@',0231,'+','<',0312,'D',0263,'R','k',034,012,'F',04,0255,014,032,0256,0316,'[',')',032,0300,']',0250,'Y','a',0201,0325,0337,0361,0344,0242,06,'%',010,0271,'=',0363,0367,0376,0360,0313,0374,0216,'u',0214,'[',0372,'9','T',')','o',0235,011,0316,0250,0311,0201,'H',0317,014,0251,'2',03,012,0302,0261,034,0320,06,'P',01,05,'J',0202,0337,0223,0333,0376,'l',0267,'G',0215,0336,031,035,'}','<',0271,'y',0212,'N',016,'>',0377,0,'?',0335,0360,0327,0336,0375,'a',0353,'W',0231,0351,0324,'o','H',0345,'^',0202,'P',0204,'h',0306,01,'Z',0366,0323,0200,'w',0251,01,'8',0321,014,0273,0255,0332,'q','~',0350,0301,0300,'X',0331,'k','7','(','=',0217,'.','q','l',0331,0340,0366,'a',0376,0256,0256,'Q',0273,'W',0226,'[',0374,'b',015,'Y',027,'<','%',0230,032,0231,06,0372,'R','<','f',0255,0335,0332,':',022,0266,'(','&','&','+',0253,0333,'M',0231,'!',0324,037,'`',0351,0346,'j',024,'C',0304,0307,0277,'?',0341,0362,0200,'%',0254,016,0262,'4','2',0375,0257,0360,0203,'f',0262,0311,0322,0230,0202,037,015,034,'<',',',0265,0336,0203,'^',0177,034,'v','l',047,0314,'O','K',0365,0363,047,025,0256,'8',0230,0372,0237,037,0305,0331,0261,'~',',',0216,'X',0273,0370,0177,'p','#','@',0256,016,'t','N',0246,0211,0324,0337,0273,0276,0352,0,' ',0331,0262,0207,026,'=',':',0371,0230,0270,0251,0254,',',0204,0376,0341,0340,0347,'2',0303,0177,0326,'4',0341,0245,'|',0222,'N','Z','d','%',0213,0253,0233,0263,0205,0354,0211,0353,'H',0334,'C',0314,'D',0220,0360,'t','{','>',0315,'D','c',0240,']',0177,'z','R',0333,'F','F',0207,0354,'|',0253,'W',0247,0270,0373,0307,0323,'h','G',014,',','s',0307,0336,0177,0317,'i','z',0256,'G','W',0357,'h',0312,'|',0256,0347,'s',0257,0371,0204,';',0277,0247,0225,'`',0226,'{',0271,0273,'F',')',0306,'$',0342,'_',0353,0374,0326,0207,0246,'i',0317,027,0226,0323,0211,'p',0231,'8','7','?',0311,'c',0372,0356,0235,'_',0275,0251,020,'8',0276,'N',0277,0343,0306,'m',0366,0337,0312,0260,0233,'=',0367,0363,0332,0221,'F','!',047,022,0376,0370,0177,0216,0307,0364,0315,':',0277,'[','Z','8',0302,'d',0340,0334,0355,0376,033,035,0327,'r',':',0277,'{','^','p',0260,0273,0344,0353,0376,01,'N',0377,0,0236,0325,0206,'Q',0356,0346,0363,0332,0345,0236,0245,0270,0342,'{',0322,'#',017,0237,'`','t',0367,037,'x',0372,'m',0231,'`',0311,'s',0307,0337,0316,0262,'Y',0256,0367,'#',0276,0355,0265,'`','3','y','g',0337,0227,0232,0134,'J','A','Y','1',0342,0352,0346,0376,0313,'m',' ',0220,0323,'B',0335,'s',0203,0333,017,'2',0301,0374,03,'^',0177,034,'v',0345,0244,0317,'7',0352,'~',0317,0313,0231,015,'N',0334,0376,'(',01,06,0335,02,011,034,07,0311,0327,0327,0207,0366,012,0202,0232,':',0333,0313,'.','~',0215,037,0200,'6',0373,0310,'e',0314,0267,0305,'a','H',0340,0235,'F',0234,0257,'X',0355,'N','O',0261,0332,0234,0227,0350,'W',0321,024,0364,0207,0211,0355,025,0201,0334,0227,0365,0307,0377,0,0206,'O',0377,0304,0,'*',020,01,0,01,03,03,03,03,04,03,01,01,0,0,0,0,0,01,021,0,'!','1','A','Q','a',' ','q',0201,'0','@',0221,020,0241,0261,0301,'P',0321,0360,0341,0361,0377,0332,0,010,01,01,0,01,'?',020,0376,'q',0231,0366,02,'K','`',0312,0360,'^',0242,0246,'X','o','9',0225,0344,'*','F','>',0355,036,'W',0302,'T','s','2','}',0340,'A',0326,'*',021,0204,0302,'Q',0230,'q','2',0333,015,0224,'p','-',0307,0214,0177,'5',02,0311,' ',034,0255,'$',0302,0377,0,0351,0337,0317,0303,'Z',0316,0362,0236,0273,023,0203,0203,0351,0263,0352,0204,'^',0306,0265,'.',06,0321,0177,'0',0240,'(','&',0202,0373,01,0374,0327,0330,'^',0237,0222,0261,0217,'k',0373,0264,0266,0303,0301,'F',']',0377,0,'N',0215,013,'k',0265,0257,0357,'4',033,'G','-',0227,'d',0322,0236,'C','D','!',023,011,0374,0326,0360,'x',0332,'p',0325,0377,0,0326,012,0274,0351,0257,'0',037,'s','M','"',0224,011,'l','R',0256,0331,'I','k',0317,0364,0232,014,0230,0305,0327,0234,0251,0365,0351,')','+',0347,0320,'a','T','$','h',0246,'O',0200,0371,'R','c',04,'y','F',03,0347,0371,0230,'c','k',013,0350,013,'U',0377,0,'X',0253,0367,0232,0323,0265,'7',']',']','{',0,'"',0271,'o',0233,'`',0375,0325,0305,0374,'.','N','Z',0376,'8',0364,0222,0341,'@','J',0256,02,0205,'H','l',015,'^',0236,',','x',0251,'=','^',05,0226,'a',0334,'g',0301,0277,0363,012,017,0251,0330,024,0210,'N',0253,'p','k',0314,0373,026,0345,0261,'3','7','n',0267,'v',012,0324,0360,'.',03,'`',0320,0343,0323,'{',025,'K','o',0237,0353,0363,0265,01,0342,'e',023,0375,0232,']',0303,'l',0211,'r',0354,'X','8',017,'x','P',0214,0240,'i',0235,01,'&',015,'i',0301,0355,014,0230,0305,0245,0216,'f','6',0232,'X',0364,'d',0343,'H',0231,0327,'E',02,'#',014,0223,'.',05,'@',020,011,0226,0227,0237,0200,'i',020,033,0376,'c',0250,';','k','5',')','I','Y',0335,0257,0240,06,036,'t',0201,0370,0250,0312,0273,022,0244,0362,0227,'v','_',0304,0224,032,0300,'Z',026,0267,020,0363,036,')','t',020,032,015,'Y','c',0302,';',0225,027,0340,026,'D',0330,'~',0303,0250,0240,'J',034,0244,'@',031,0332,013,0351,'E',0274,0344,'0','p',0226,'}','@','l','e','D',01,0273,'H',0307,'a','!',0327,0303,'C',0316,0320,0273,'h','6',0372,07,0366,0324,0322,0244,0360,'4',015,0203,0323,0230,0302,0373,0216,017,0357,0376,0321,0220,04,0,0200,')','p',0202,0333,0276,0255,0203,0340,0266,0251,0356,'[',0365,0215,0311,'u',0134,012,0314,0260,0266,'"','e','|','a','9','^',0364,0261,0265,02,'[',0206,'$',0331,0376,0346,0225,021,0222,'s','>',0300,0215,036,'L',06,'Q','p','F',06,'f',0203,'&','(','c',0134,0226,']',0315,0373,0342,0237,0202,0242,0317,'H',02,0235,0277,'j',0226,0272,'!',0215,'-','m',0205,0260,'a',0364,'r',0267,'/','g',0253,'l','|',0261,0211,0222,'I',',','?',07,'-','N',036,'`',0267,0367,':',0276,0234,0212,036,05,0277,0273,'b',0211,04,'1',0373,'y','j',0361,026,'&',0302,0345,0335,'>','[','h',0236,0335,'@','U',0200,0326,0214,0324,0201,01,021,'f',0211,'|',033,0233,'5','$',0251,02,0224,0262,011,'S',' ',0304,0332,0311,0244,0322,0352,'P',0232,'R','d',035,0202,0305,0255,0355,0201,0230,'T',0230,0310,013,0210,0352,'R',047,'`','$',0227,'K','t',',','H','K',035,0221,'S',0220,012,'*',014,021,033,0302,0246,'&',0366,'M',033,0215,'<',0306,0252,'G',0246,0320,0361,0325,'w','0',':','3',0340,0276,0245,030,0223,'(','@',032,0253,'S',0341,0263,022,0337,0372,0343,0277,0246,0244,'!',0206,0333,0257,05,'F',0243,'a',0337,'s',0266,0305,'6','e',0302,'i',0243,0375,05,0335,'(','5',014,'8',0,0200,'=',0253,0250,'p',0240,031,'U',0301,'I',0335,0264,'G','d','Q',0354,'1',0205,'*','@',0222,'L',0202,'H',014,'h',0302,'5',0203,017,'x',0365,'-','2',0255,021,'`',0371,012,'M','k',0204,031,0273,0250,0264,'J',0236,015,'Y','"',0241,'B',0330,'.','Z',0200,0233,'}','%',0343,0341,0256,034,'!',0261,0241,0253,0346,022,0236,'S',0224,'2',0253,'Y',0356,0341,0330,'4','p','}',0337,0277,0244,0201,0234,01,'*',0354,'T',016,']',0231,0206,0337,0337,'=',0252,0316,'"',0227,'p',0332,01,0376,0232,0263,012,0224,0134,'}',0327,0330,03,'O','j','~',014,0204,'!',0330,0272,'3',022,05,0336,0352,'q','R',0206,'2',0261,'t',0230,0273,'I',0270,'a',0374,04,'u',0200,'R',03,'S','7',015,0224,0342,0213,0300,04,'F',0260,'e',0353,04,0260,0263,0,'E','_',0250,'N',0306,0201,0240,026,012,0261,025,0346,0273,0376,0337,0261,0343,0324,0304,0363,'"',0305,0327,0313,0247,037,'c',0234,'c','e',014,0,'j',0255,'G',021,07,'x','d','M',0215,'w','|','{','K',0276,0242,0221,'$',0305,0370,'D',031,'P',0275,'7',0,'1',027,0223,':',022,0336,'i',06,'=','Y','>','b',0373,'p','.',0275,0252,0306,'0','D','~',0302,0237,'4',0372,012,0221,0323,0212,':','*','-',0314,0324,0371,'i','R',')','`',0207,0205,'e',0361,'N',0260,0354,030,0254,0207,0370,0353,016,0225,0221,0273,'<','>',025,'1',0230,0356,0336,0242,'>',0364,015,0302,'~',010,'U',0360,'T',0247,0322,0325,0231,0200,0227,0323,0202,0313,'.',015,0323,'@','J',0272,05,035,0360,0214,0204,';',0274,014,'h',034,0252,0276,021,'5','z',0273,0270,')','3','1',0226,'W',0323,0203,0321,'m','`',0375,'5',0337,033,0326,'*',0327,'S',07,'w','2',0344,'c','b',0372,0333,0331,0341,06,'+',0253,']','H',0263,'w','D',0260,033,026,0263,0264,'a',0261,0320,03,'.','W',0322,0327,'I',012,':',04,0253,'m',012,024,033,06,0317,02,0,'{',0212,0217,016,'/',0347,'R','.',0305,'D',0243,'0',026,032,0310,017,'c','E','5','G',011,0200,020,036,0226,'r','8',026,0360,0322,'%',0361,'%',0333,0267,'{','f','j','w',0264,'^',0271,012,'b','7','6',0351,'A',024,0343,0314,0354,06,'3','d',0264,0336,']',0273,0314,'M',0303,016,0251,':',0237,025,'N','I',0200,06,'U','b','*',04,'4',0333,0325,0217,0305,0224,'e','5',02,0240,0212,0260,'e','h','9','i',0267,0320,'6',0332,'C',0323,016,0354,0343,0333,'g','-',07,'d','a',0200,0245,031,026,0366,0307,0367,015,'w',0306,0360,0,0,'@','{','!','O',0324,'E','%','E',0202,0220,035,0240,'F','l',0341,'T',0233,0353,'h',0221,0364,'c',0355,',',0220,022,'(',0231,'%',0301,'Z',0336,0267,021,026,'+',033,'6','d','-','M',0263,'J',0361,021,'&','K',01,'t',0276,0311,0202,0300,'#',0354,04,'N',0365,0216,0371,011,'R','`',0225,013,0351,'l','f',0202,025,0317,'A',025,'n',0230,0210,'[','%',0253,0206,'h',0264,'!',012,0341,'>',0266,0264,0327,0230,'1',':',036,03,'9','H',013,0341,'P',0200,014,0255,'K',0225,'(',0266,0344,0371,'~',0307,0237,'N','|',0212,0353,0201,0252,0340,0241,0337,'Q','K',0353,'*',0265,0313,0214,0264,0230,'9','`','<',0340,'h',0254,027,0,07,0345,0347,'_','e',0222,':',0271,0203,0271,0276,0203,0361,'-',015,0134,0341,0220,0301,'[','Z','8','I','g',0321,'1','3','r',0252,0275,0214,'d','2',0206,0312,0207,02,024,0362,'l',0220,0254,'8','D','#','*',02,0,010,03,07,0267,0222,0202,0304,'[',023,'g',0200,0260,0303,027,032,0260,'1','1','/','v','-','v','e',0345,'T',0177,0214,'a','B','2',030,010,0256,'$',04,0213,0,0,0,013,01,'Y',0226,'o',0260,'~','&',0274,0366,0364,0322,0372,'@','%','W',01,'R',0342,04,'F',0374,017,07,0335,0361,'K',0220,0262,0375,0327,'`','%',']',02,0240,0251,'q',0341,0324,'{',030,015,017,'>',0312,0345,'m',010,0307,0224,'[',0255,'[',02,'T',02,0324,0335,'r',0242,0367,06,047,0264,0204,0255,0,07,'X','A','A',026,0357,011,04,0234,'6',0324,0264,0301,0232,020,'H',023,0210,'$',0347,0270,'(',0221,0227,013,'{',0273,0266,'2',0337,'+',0303,'+',0330,0312,'S','y','n','M','_',0301,0306,0224,';',0266,017,'7','v',0337,0362,0225,'J',0262,0271,'_','O',07,04,0203,'6',0256,']','8',0357,'H','@',0243,0,'e',0240,0214,0307,0201,'t',0271,0336,0331,0360,'4',0277,0261,0310,0333,0370,0250,'W',0262,0241,'W',0,'R',02,0323,0331,0234,0313,'.','@','r',0266,'V',0352,0355,0200,':',0210,0211,037,0247,0,'*',0321,0256,'.','k',0363,'u','~','.',0340,0310,'0',034,0215,03,'i',0,0,06,0307,0273,'1',0362,0366,0256,0300,0325,'X',03,'v',0235,0325,'-',0331,03,'a',0371,']','U',0253,0246,0214,0213,0351,037,0355,')',0373,'s','t',07,0350,012,02,0327,0270,0227,'r',0233,'#',0241,022,'#',0321,0201,0221,'l',',','z','v','5',0370,0336,0261,'Z',0307,0243,'b',0326,'l','8',0346,0372,023,0354,'u',0347,0267,'>',0332,0342,0200,'7','j','w',0,0272,0246,'a',0274,'C',0235,06,0,':',0222,031,013,0134,020,0313,'C',':',04,012,016,'D',0225,0312,0304,';',0337,',',0327,0202,'J',0376,0360,031,0,'%',0134,024,0231,0255,022,0266,05,'q',0223,0204,0272,0330,0342,0241,0206,03,'-','_',0214,0365,'h','n',0362,0377,0,'[','Q','2','|','a',0246,0306,0324,' ',0221,0221,0250,0350,0206,0301,0236,0364,0221,0312,0300,'Y',0353,0231,0250,0303,0370,016,']','?',0345,021,0303,0264,'b',0242,0271,0201,0264,0264,'M',0335,'v',';',0224,033,0204,'l',0,0200,015,017,'b','~','=','Y','5',07,0,015,'I',0325,0226,0311,0215,0210,0300,0346,0202,0352,'z',0246,']','y','x','6','B','4',026,':',0222,0224,0213,05,0322,'u',010,0276,'r',0212,0373,0335,0341,'%',0312,'c',0310,0317,026,0326,0325,0273,014,0330,0377,0,03,0363,0333,0350,'0',0311,'f',0256,0347,']','}',0216,0277,'B',0240,0220,0202,0202,0237,0235,0326,'S',0225,06,'G',0242,'@','6',03,'C','u',0340,0242,'&','E',0301,'}','E',0253,'d','Q',027,0376,'J',0277,04,0255,0206,0205,0364,0311,0213,'%',0236,'`','/',03,'b',0203,0330,0240,'K',011,0323,035,'L',0212,0373,';',031,0352,0205,022,02,0254,0272,0346,'R',02,0371,0271,'4',037,0225,014,'"',0,0260,07,0275,'F',0340,0256,0274,':',0206,0322,0362,0301,0275,' ','B',0243,'(','e','W','y',0254,'?',0272,031,0302,0367,'h',0177,0312,'Y','e',0317,0321,0247,0324,'l','5',0241,0351,031,'N',032,0366,0207,'t',0321,0342,033,0205,0273,'*',0311,0271,'D',0211,06,'+','w','R',0134,'3',012,0372,'!',02,0214,01,0226,0212,047,021,0237,0200,0376,0371,0355,'P','2',0303,'B',0225,'.',0,'&',0222,0313,0240,0223,'h','x',',','h','A',0231,0226,0270,04,'q','i',0306,0325,0240,015,0311,020,017,0364,0256,0340,':','"',0214,'"','{',01,0205,0244,0277,'3','e','q',0207,035,0340,0322,0365,'F',0237,'r',032,0335,0363,'1',07,0254,0213,0312,0207,'_',07,0226,0200,',',0,0,036,0367,0275,'2',0305,0240,0335,'X',016,0365,01,06,0202,0310,'0',0366,0373,0252,0353,'N',0324,0206,047,0276,0220,0253,0247,'i',0330,'4',016,014,'}','B','Y','1','T',0251,0204,0212,'U','#','!',0330,'-','#',024,0211,0251,'L',0355,0312,0263,0331,'S',0373,0203,031,0226,0253,0332,0237,022,0245,']','_',0246,'b',0213,'L',0277,0355,0276,'v',0372,']',017,'g',0323,'!','v','W',0340,015,'S',0364,0272,0204,'G','.','$',0360,0276,'p',024,0210,04,'D','n',047,0255,016,0247,04,035,'i',0272,0240,'m','2',0330,'i','(','.','G',024,0372,030,06,0305,0345,0227,0251,0310,0345,'%','[',033,'*',024,'f',0234,0310,021,'s',0311,0250,023,0,036,0367,025,0230,06,011,'l','o','0',0270,'y','u',0240,04,'e',010,0,0312,0323,'9',0243,0277,'p',0134,0277,0216,0214,0324,0202,0362,'k','F','8','s','m','8',0244,0272,'P',0271,'(',0343,'9',0221,0244,'R','Z',0336,024,02,0210,034,0224,0371,0372,'H',' ',0243,0212,'Z',036,0372,0354,'x',0240,'L','`',010,0,0300,'T',' ',0314,022,0273,'Y',0134,0344,0345,'.',0305,033,'9','Q','*',0356,0364,'?',0253,0261,0201,027,027,'Z',0255,'E',0252,0257,0254,'A','7',0260,'%',022,':',0203,0310,0225,0304,0352,'q',017,025,'&','N','s','x',0324,02,0327,'A',037,' ',06,0261,0333,0246,0241,'}',0364,0306,'`','[',0265,0274,'`',0340,0227,'S',0351,0363,'*',0276,'?','w',0343,0177,0253,'S','L',0350,';',0323,0326,0247,'-',0242,0320,',',0134,032,0277,0350,0337,0344,012,0216,0207,0313,0305,0373,0322,'c',0215,'S','X','o',0201,0324,0330,0372,0134,0315,0312,'c','Y','p','T','y',05,0327,'+','U',0313,'G',0341,',',0344,02,01,030,0212,0261,':',0260,',',031,'-',021,0201,'h',020,06,0307,'J',0201,014,0234,'c','r','Z','p',0311,'p','j',',',0326,021,0306,0203,'`',0350,'o',0352,04,'h',0316,'%','l',0315,0226,'F','"','+',0236,0241,'#',0200,'I','a',0267,'T','*',0361,'(',0331,015,0241,'M',0347,04,0254,022,0275,0364,'7',0236,'l','+',0366,'5',']',01,0247,0304,0362,'u',']',015,0203,01,0240,'S','4',031,']',0243,0252,0340,0374,0305,'$',07,0250,'J',0256,'W',0350,'n',0312,0200,'5','i',0232,011,0330,0353,0265,04,'K','(','F','c',0275,010,0270,022,'M','*',0250,04,011,0205,0241,0332,0237,'I',0246,'x',0357,'K','Y','_','?','D',0272,0320,011,'U',0300,'Q',0310,03,03,0246,0303,0203,0356,0320,0252,030,'r',0243,0,'P',';',0321,'l',012,016,0221,'C',0313,'i',0242,'a','W',013,0371,'Z',0310,'n','`',0,'u','$',0332,0272,0230,02,0326,'#','g',0,'%',0372,'a',' ',0252,020,01,0225,'i','!',' ',011,'h',0200,0224,0233,0356,'d',0134,':',0235,0316,0344,0232,0272,0325,0360,'G','y','=',0363,0312,'S',0260,02,'U','v',0212,0226,0303,'6',0334,0231,0274,047,0202,015,'(',0353,0251,0376,032,0324,0225,'&','E',0217,07,0373,'_',0250,0311,0231,'c',0274,'P',0301,'*','a',0275,031,0327,'o',0271,'x',0245,'@',0202,015,0271,0251,'y',016,'F',0365,030,0350,'D','`',0265,'0',0356,0317,0323,015,']',0246,'O',0315,0323,0216,0377,0,'K','}',0333,0373,0271,0236,0301,0360,'w','~',0203,'x','H',0204,0231,0202,0307,035,0264,0262,010,'/',04,0350,'l',0256,'D','N',0230,'P',0222,06,0222,0321,020,'G',0212,'%','7','d',020,0200,0304,0260,'X',017,0244,'6',0203,0250,0200,'E',010,0226,02,'a','.',0235,'G',0332,020,'x',0250,0216,0216,0234,0322,0210,032,03,0212,'p',030,'c',0,01,0357,0264,0316,017,0362,'y','l',0274,'A',0253,0364,0314,0233,0201,'`',0375,037,0231,0343,0241,037,0221,'3',0315,'#',0,020,0233,0325,0205,0302,0207,'S',0262,'`',030,0245,'e',027,'{',0216,0335,0252,'R','C',0224,0337,'C',0350,0230,0234,'C',0215,016,0315,0377,0,0355,0,0,' ','0',025,01,'*',0315,0330,0356,'r',031,'w',0261,0275,'c',0353,013,06,0270,07,0337,0337,'u','|','2',0352,0331,'^','^','z',')','`',0202,0260,'J','m',0364,0234,'C',0243,'I',0264,'d',0243,':',04,'O',017,'U',0261,']',0231,02,0355,0204,0220,016,013,0241,0357,0263,022,0377,0,'T',0267,0203,'/',07,'%','(','7',0345,0321,0225,0254,03,'p','#','|','/','v',0207,0235,0276,0257,0221,0320,015,'i',0321,0306,'F',035,0365,025,012,'e',0231,0243,0263,'d',0213,017,0356,0200,010,0210,0352,'U',0216,'(','M',0204,']',047,'}','>',0305,0312,0272,0264,07,'C','t','v',0326,'U','`',015,033,0273,0257,'.','j','E',0364,025,0201,0273,0337,'@',0335,0240,'@','X','v',0335,0335,'r',0272,0257,'F',0243,0347,0262,0256,'h',0336,0316,0214,'4','D',0270,0220,015,' ','C',')','1','`',015,036,0230,0305,'+',0243,010,'h',0210,047,'j','p','K',0316,0302,'3',0364,0230,'n',0207,'_','@',030,034,' ',023,'n',0246,'P',0301,0324,0331,0326,')',0314,'}',0242,'M','i',0204,020,'c',0336,0271,04,'?',0,022,0253,0265,03,04,0210,0266,'W','f',0350,0236,0320,'i','L','-',0253,014,0351,016,'Z',0270,'9',0235,0206,0201,0300,'}','J',0375,0262,0306,015,0353,03,'/','s',0232,'z',0322,0233,035,0232,0341,'`',0260,'+','h',']','p','8',0244,0316,'l',0306,0352,'p',0212,']','Z','K',0341,01,'*',0270,012,032,'$',01,0350,0350,'8','?',0272,05,'C',036,'T','`','(',0323,'c',0330,'<',037,01,0345,0327,0253,031,'F',0347,'j','(','K','y',0220,026,0343,0252,025,0255,'`',0,0301,0336,'V',0330,'h',0375,04,'>',0277,'H','H','H',031,'&','3',0241,'n',0241,0312,0350,'W','9',020,'K',0245,'c',0337,'<',':',01,0373,0345,0356,'9','x',0215,0332,'X','%',0305,'%',0372,0354,030,0326,0375,'N',';',0375,'x',0314,0373,0250,'C',0201,01,'V',0276,0314,0350,'p','P',0354,06,012,021,0250,014,'"',0366,'?',0134,'8','6',0330,'?',0276,0234,'_','_',0245,0206,0255,0335,0324,0370,0206,'6',';',0275,'a',0345,0244,'*',',','r','"',0224,0212,0276,'q','F',0307,011,'E',0214,'*','i',0322,0247,0332,'q','&',0305,0373,'C','?',024,'i',0235,0,0204,022,'h',0210,0365,'3',0244,0266,020,')',0330,05,0245,0322,'j',0230,'M',0233,'h',016,07,'H','5','.','P','#','&','h',0374,0342,0201,'1',0200,' ',03,01,0357,'e','t','^','9','K',035,0213,0257,03,'K',0225,031,0304,'e','k',021,'o',0245,0366,0273,0277,0211,0343,0243,012,'I','h',0246,012,'D',0250,012,'r',02,0305,0253,'6',0314,02,'[','o','G','V','a','[',07,0321,0344,023,012,0370,017,0357,0216,0364,04,0,020,06,012,'{',0310,'(',',','7',';','K','>',06,0266,0,0,' ','4','=',07,01,01,0331,0234,0214,0200,0221,'b',0360,0315,0216,0246,'}','u','r',0313,021,0240,04,0336,0374,0345,0351,'V',0354,0,0233,',',0374,'3','{',0236,0254,'9','%',0250,'Y','f','A',0344,';','}',0350,'2',0,'J',0270,')',0244,0314,0300,'b',0377,0,0270,'-',0300,'U',0350,'c',023,0335,0360,'?',0330,0232,0226,'~',047,0350,0340,0307,0326,0347,0261,0205,0276,'k',0202,',','$',0243,'e',03,0376,'3','X','.','Y',0277,0302,0201,01,'(','e',0134,0323,':','`',0273,'i','V',0204,026,'6',015,'(',0323,0277,'w',032,0313,0265,'F',0221,0304,0271,'Z',0257,'-',07,0220,0272,0222,014,0237,0200,0325,'B',0203,'n',0357,0235,0326,0352,0312,0273,0276,0211,0134,030,037,'a','o',0370,'*',016,0362,0264,'"','G','"',047,0216,0231,'D',0212,014,0331,0267,01,',',0362,0247,0236,0225,0216,0335,'/',0303,035,0206,0213,0243,0214,0275,'!','/','c',0224,0200,015,'U','B',0213,0330,0212,0302,0372,03,'T',0367,0262,012,'k',0310,0276,'7',0315,0307,'c',0205,'(',025,'@','.',0255,'*','2','t','L','=','|',0364,0343,0352,0360,0324,0335,0273,'b',0210,0320,'@',012,'n','V',0310,0223,'L',0356,'w','K',0332,0247,0365,0263,025,'!','E',0311,027,';',')',02,'>','a',0313,'H',0331,0300,011,'W','j',020,'$',0317,0260,036,0337,0237,024,'-',0302,014,0241,0200,016,0364,'l',020,0134,'8',027,0223,0313,'.',0276,0231,035,023,0234,025,014,0341,'p',0332,036,0222,' ','D','b','&','2',0210,021,0315,0301,'!','"','x',0351,0314,0265,'2',06,0,'<',0272,'9',0351,'1','#',0325,0,'%',0346,0361,034,0373,0331,0216,0203,06,0357,01,0312,0300,'w',0251,0206,0203,014,034,07,01,01,0332,0261,'6','R','<','}',0337,0307,0177,0251,0247,'$','(','O','.','N',0356,0253,'E',0316,0324,0223,';',0370,0240,0200,0270,0201,0336,0215,0211,'.','&',0264,0240,022,0302,0271,'K','h',0370,0237,'H','k','T',0206,0313,0257,0352,'y','v',0372,'f',0243,07,0317,'g',0275,0301,0304,0272,0236,0244,0273,0225,0266,0267,0356,01,0234,0362,0352,'P','L',0310,0200,022,'Y',0201,0223,'x',023,'~',0200,'8',' ',0224,'$',047,'T',07,0232,0177,'"',0245,'*','r',0256,0257,'H',035,0227,0326,'`',024,0354,0315,0277,0323,0336,0301,0315,'y',026,0306,0370,0270,0356,0360,0250,0223,05,0306,'|',037,0355,06,0230,012,0316,0337,0352,04,0224,'4',0246,0240,0320,'_',0215,0265,0243,036,'s',0332,032,0264,0215,023,013,0265,031,0242,0200,0272,035,'i',0230,0276,0366,0210,0321,0204,'j',0321,'s','a',037,'m',07,'/',0367,'A','t',0240,' ',03,01,'S','(',023,020,0314,027,0234,0273,035,0312,04,0306,0,'@',032,07,0250,'*',0257,'D','H','e',0323,0250,0216,030,0213,'c',0301,'m','1','7',0345,0321,';','5','"',011,021,0356,'g',0211,0352,0221,0322,'~',0212,'H',0305,0337,0260,0215,'=','f','Q',0203,'$',017,0313,'I',011,'f','A',')',06,'&',0344,017,0315,032,'}',0376,0362,037,'L',' ',0304,0302,'7',0267,0354,037,0224,0247,'Y','e',0272,0237,'v',0225,0244,'*','f',026,0276,'z','q',0365,'r','D',0260,'3',033,'P','n','_',015,032,'>',0217,05,'b',0260,'D','f',0367,0242,'6','0',0272,0212,025,0340,0312,0272,0356,0264,'9',0244,0216,0305,0251,0263,0377,0,'h',';','T','v',06,05,0337,'/',0373,'J',0260,'b','%',0375,'$',027,0250,027,']',05,0337,0312,'_',0353,'O','T',0312,01,010,0341,'*','G',0322,'T',0330,0312,'v','S','8','z','T',04,0225,'h','#',0376,0236,':',05,0242,'h',0230,0,047,0226,'Q',0331,0351,'H',0316,0,0225,0134,01,'J',0225,'D','U',04,0312,0335,'w','z','j',0257,06,0241,0330,'.',0270,012,0276,'K',03,'A',0334,'O',0317,0205,'g',0236,'M',0231,0265,0221,0363,'H',0225,'U','n',0256,0277,0134,0343,']',0373,'R','i',0305,'5',',',0301,0,031,023,'B','^',0326,'I',0304,'z','*',0320,'(',0300,04,0253,0342,0233,'0',';','V',0333,0313,'u',0345,0254,'w',0272,0253,0355,'w',0177,023,0277,0325,0347,0256,01,'v',0221,011,0221,06,0224,0207,'h','K','4','6',0372,031,'t',0234,0324,016,0330,'L',015,'b',0214,0336,06,0261,'J',0252,0267,'k',011,0255,'%',0366,'{',0271,'|','s','H','@',0243,0,'e',0242,0216,0202,0223,'9',0301,0316,0257,'6',0320,0365,0325,'8','M','a','`','w','S',0335,'z','Z',0362,'B',0303,'d',0336,'m','7',0216,0202,'r','[',0360,0203,0356,05,0362,'t',0304,0370,0134,'U',036,06,'x',0364,0241,'<',' ',03,0225,0250,0357,'Y','_','z',0277,0237,0206,0265,0236,'Z',0277,'b',0370,'8',0243,'l','i','R',0,0250,'T',037,0372,025,0276,'&',0247,'M','0',0302,036,'[','}',0253,016,';',0177,0,'P',0244,0365,0300,037,'9',0373,0324,0201,05,'*','I',0311,'k',0333,'5',0225,'Y',020,014,0215,'C','1',010,'3',0375,03,047,0217,'B',0303,'&','9','y','>',0350,0227,0200,0321,0245,0326,'C','-',0364,0207,'z',0277,0356,017,0321,0301,0212,0217,0244,01,07,037,'x',0356,0320,'R',0200,'.','Z','t',0314,015,'#','o',0250,'D',010,'6',0237,0246,'y',0331,013,'m',0366,'2',0370,'7',0372,'^','"','9',0354,'m',0373,026,'=',0200,',',0302,0315,0310,'3',0302,0241,0313,0322,'o',023,04,015,'k',0330,0240,0311,'%',0317,0251,0246,'.',0216,'j',0217,0301,'|',0364,0243,0316,'y','+','>','/',0237,'E',0354,'R',0216,'$',0340,0320,0335,'l','|',025,0236,0346,'B','s','?',0221,0361,05,0276,0223,0334,';','O',0177,0374,'X',0373,'S',0231,'.',0222,0321,0343,'^',0354,0364,0276,'r','2',0302,'U',0270,0330,0375,06,0275,0234,0325,0360,0300,017,0204,'v',023,0327,0134,'1',0305,0205,'l','<',0254,025,'5',0,0322,023,0241,0300,'@',033,05,'f',0253,'*','6',0326,0375,017,0373,'I','b',0351,0322,0324,'h','e',0302,03,0363,'Y',0202,022,0254,0305,017,0232,'k',0266,';','Q',0362,'[','s','%','6','#','Y',022,0215,0217,0225,'0',0366,0245,0310,020,0203,0351,'k','s',0201,'m','w',0375,0255,'Y',0216,0307,0355,0345,0253,'o',01,'M','l',037,01,0345,0321,0241,'D',0261,0340,02,0,0366,027,0313,'!',0206,06,0277,017,0216,0241,026,016,']',0375,0207,0324,0313,'g',0244,'t',014,0223,05,0304,0372,06,'~',014,0207,07,'@',0340,'2',0272,036,')',0350,0267,0266,0210,'4',015,0277,'t','Y',0332,'W',01,'N','#',011,'6',036,']',016,'>','v',0364,036,06,0204,'4','5','~','m',0346,0274,'-',0373,'d',027,0202,'O',035,'w',023,'9','+','a','~',023,0334,0323,014,0321,'!',0276,05,0356,0340,0363,'F',012,0250,03,'Z','3',031,016,07,024,011,'a',0305,0274,0215,010,021,0247,'j',0256,0275,033,013,'=',0366,0254,0,021,'T','l',0134,'%',03,010,'%',0304,0247,04,0304,0345,'v',0244,0204,0360,011,'U',0301,'E',0310,0302,'}',035,07,07,0346,'h',0327,033,' ',0257,0366,'k',013,0204,013,0261,0177,06,03,'c','u',0366,' ',021,'$',0331,'o','|','/',0236,0244,0320,0215,0262,' ',0236,0350,0375,'n','l',0307,0373,0266,0335,'7','m',0210,0236,'W','?','w',0317,0240,0273,022,0310,0264,033,0367,0253,0366,0203,'J','(',0252,'a',0200,0313,'I',0321,'k',0237,0366,'~','=',025,'m','P',0211,0221,0242,'_',011,'(',0323,01,0341,032,047,0240,'_',0356,'r','/','d',0351,'5','$',0332,0301,027,0355,027,0357,06,0264,0276,'P','Y','e','Z','w','_',0315,'5','s',':','4',032,07,01,'j',0324,0303,0,'e',0336,0223,0253,'R',033,0272,024,0362,'h','p',0300,'h','U',0376,'^',0346,0223,0264,0270,'{','6',0244,0,'%','l',05,'M','"',0222,'"',0245,0233,0211,'z',0367,')',0333,'Q','*',0345,'j','"',0374,'C','e',0303,0372,0236,'x',0372,'X','Z',031,'n',0237,0227,0341,0335,0366,'B',0261,'1',0237,07,0357,0253,0214,0276,'0','?','_','U',0322,',','n','s',0310,037,'=','.','v',')',0331,'s',0370,':',0346,'j','}',0321,03,0362,0237,'H',0321,'@','C','R',0177,' ',0276,017,'O','A','!','=',0204,0360,0224,0305,0273,012,0350,0203,0310,'K',0313,0240,01,031,'B',0,'2',0264,0322,0356,0267,'k','x',0356,0257,0332,015,'+','8','o','#','m','o',0214,'|',0321,'S',04,'S',0312,')','@',0260,032,'8','h',013,0202,020,0221,0245,'=',04,'.','7',0305,'-','d',0271,'4','4',0206,022,0321,'_',')','k',0217,0370,'R','O','2',0311,0177,024,0326,0314,0244,0320,0247,'T',0300,'6',0233,016,0134,'|',0355,'F',0214,'@',0254,06,012,'{',0204,0302,'-',0233,0261,0253,0305,0265,0240,0,0,05,0200,0366,'D',0234,0231,'j',010,0362,0201,0347,0251,0206,0304,037,02,017,0307,0324,0204,'"','~',0311,0373,'t',0245,0200,'R','W','C',0257,0331,0363,0326,0203,022,'#',0367,'?','O',0244,0313,'0',0214,'t',017,'N',0361,'0',0206,017,0263,017,0212,0235,025,'@',0354,'y',022,'y',0242,0306,'B',0340,022,'?',017,0326,0310,'s',0232,0276,024,0362,0267,'b',0222,0261,'E',0217,047,'_',035,'9','i','e',0226,0357,0320,'K','o',0376,0320,0244,'H',0207,'5',0273,037,0240,027,0227,0215,0307,0212,022,0345,0346,'>','J',023,0221,04,'V','u','%',0370,0177,0302,0236,'X','G',0312,0265,014,')','i',0376,0340,0301,'V','w',0242,0217,0320,'A','z',0267,0235,025,0375,0204,0267,0366,'p','O',0375,0343,0365,0325,0315,0237,':','_',0277,0253,0263,0322,'z',026,030,0200,0346,':',0363,0354,'y',0320,'G',0363,0134,'E','$',0203,011,0362,'S',0350,0205,'|',017,0310,0372,'x',0243,'e',0237,0213,0331,0371,0317,0232,011,0253,'(',0335,0326,0371,'1',0331,0372,'4','Z','i',0205,0341,0345,'~','.',0351,'G','.','E','x',',',016,0,0,0340,0251,':','V','V',0236,017,0337,'u',0350,'0',0210,0134,'J',':','v',03,0363,'7',0241,0242,0222,047,0320,'V',0303,'B','4','j',0322,0251,'[',0255,'F','c',0300,'g',0374,0237,0307,'z',05,0,'*',0330,012,'8',010,'i','K',0344,0356,'j',0363,'m',017,'h','L',0260,0215,0314,'u','[',')',0227,0374,0213,0177,0251,'x','B',0242,' ',0237,0336,0353,0317,'K',0376,03,014,'(',013,0306,'=',0323,0320,0260,0252,0362,0200,'_','p',0361,'P','Q','d',035,0322,'~','_',036,0246,'<','(',035,0253,0236,'J','*','3','u','0','>','^',023,0342,0316,0224,030,032,'h',047,'Q',0233,'?',0235,'&',0203,0242,01,0254,0254,'!',0273,0241,0241,0312,0324,'-',0336,031,0316,'G',0206,'^','c','n',0262,0310,'^','U',027,025,0343,0221,'x',0336,0232,0322,0273,'h',032,024,0202,0251,0205,0337,0247,0236,0274,'P',0,0,020,06,0225,'q','H',0345,0261,'~','?',0342,0317,0265,01,'D','E',0313,'d',0370,'u',017,0260,0374,0200,030,016,03,0353,'h','m',0224,025,0361,0362,':','I',025,0265,01,'I',0354,'^',0360,'z',030,047,'(',0304,0277,0271,0366,0252,015,'$','O','i',0227,0355,0343,0324,0134,' ',0374,0320,0342,0230,'9',')',0343,'q',0344,'m',0343,0351,'4',06,0377,0,0327,'w','c','?',0373,'I','q',0244,'%','W','/',0243,'m',0134,015,015,0327,0200,0275,021,022,'3',015,0333,'*',0261,010,'@',0304,0335,0356,0340,'7','v',0232,'%',0316,0300,07,0373,'>',0325,027,0204,0232,0374,')',035,')',0233,'J','I',02,'X',0326,0364,017,0240,'e',0260,020,'}','f',0242,0373,0353,033,0311,0360,0364,0360,' ',0205,06,'o','"',0226,'A','|','3',' ',037,'g',0257,0340,0211,'M',0237,'x',0361,'X',0304,0234,0332,'H',032,0,'U',' ',0350,0236,0245,0326,'t',0226,0325,0235,0207,0354,0367,'i',0314,'%','#','v',0341,0371,'m','V',0271,0310,'L',0233,035,0367,'}',',',037,0260,'%',0362,07,'w','?',024,'i','B',014,0241,0200,'<',0321,021,015,'x',0263,'`',0370,017,'.',0276,0332,'o','f',030,0204,0276,0362,0277,0,0351,'F',0214,0226,'R',03,0362,'/','=',06,'a','l',021,0252,0327,0226,0360,0352,'h',0331,0372,0271,0235,'[',0252,0266,'u',0231,0353,0237,0326,'&',0240,0211,0360,0326,0335,'o',0304,0250,'/',0332,0240,'b',024,0373,0347,0333,0231,06,0302,022,0332,'=',0232,0277,0367,0351,021,'d',' ',0340,0307,0345,017,'.',0336,0334,'F','I','B',0314,022,'p',0201,'8','z','T',0344,0354,'L',010,0327,0306,'o',0327,'A',0253,'I',02,'b',02,'m','6','.',0361,0324,'0',0364,' ',0204,'d',033,0223,0377,0,0361,0350,'Z','h',023,0244,'m','}',0215,'"',025,0331,0370,'o',0370,'|',0275,0265,0235,0314,'l','5','^',02,0364,':',0300,0335,'g','Q','r',0265,04,0302,'-',0262,0261,'w',0204,'v',0227,'J',015,0312,'6',0,'@',06,0321,0355,0254,'h',030,'J',0302,01,0252,0240,035,0351,0363,0324,0304,0231,'R',0345,'V','g',0247,0205,0374,0230,'7',04,0177,0263,0240,'&','4',0214,'#','d',0246,'l',0317,'Y',035,'s','2','P',0352,'#',0322,0326,0252,'~',0360,0235,0262,02,0364,027,'%',0216,0373,'K',0354,0373,0352,07,'y',06,'@',0363,021,0347,0333,'`',0271,020,'K',0344,016,0356,'_',024,'&',0235,0250,'/',0353,0232,0321,'D',0262,0356,']',0355,0241,0300,'{','t',047,010,0316,025,'V',0362,0251,'&',0266,'6','z',0255,0356,0373,0223,'&',0356,0276,0224,0230,0377,0,022,'a',033,0220,'W','J','l',0316,'R',0320,0332,'h',05,'p',0271,0246,0333,'}',010,'S','&','D',017,']',0254,0271,020,0220,'>',030,'|','S','G','D',0362,014,047,0311,'Q','t',04,'^','c',0354,0307,0217,'i',0221,0340,'a','-',0224,0354,'2',0370,0337,0351,03,02,030,0356,0337,0237,0370,0273,0356,'$',014,'2',0233,'F',']','-',0363,036,0222,0360,0277,'1',012,'s',0310,'U',0363,'&',0313,'l',0335,0273,'l',0236,0234,0315,'(',0302,'C',0275,'e',0345,0352,'&','R',0233,0221,'Y',06,0206,023,0273,0277,0241,0211,0322,'%',0260,'y',0301,'x','V','!',0202,0234,0347,0374,'m',0354,0345,0375,032,'t',032,0257,01,'P',0276,0215,'.','V',0253,0312,0323,022,021,'2','[','0',0367,0313,0307,'r',0200,0200,02,0,',',036,0335,0363,0327,0200,0225,0313,0260,'4',0344,0337,0246,'&',0315,0264,'G',03,0246,'*',0377,0,0341,010,020,0322,'B',':',0221,0276,0215,03,')',04,0352,'!',0315,012,'<','%',010,0221,0310,0211,0343,0244,'d',014,'P',020,0315,'[',0315,0220,'k',0257,0320,0275,',',0373,0264,'~',037,'6',0274,0302,'-',0222,0335,0341,'<',0373,'<',017,02,0211,'|',0247,'s',0227,0306,0325,016,'C','-',06,0253,'`','%','{','V',']',0201,0210,'V','^','W',0340,0203,'O','q',034,0363,'h','q','Q','5',026,'l','Y',0355,0324,0311,'F',0240,'#','(',0354,'K',';','z',0343,'0',0357,022,0211,'>',031,0134,'`',0351,0227,07,'#',06,0200,0350,0210,'>','*',030,0347,'#',012,'o',0302,0304,015,0304,'u',0353,0207,02,'j',0324,0237,'a',0207,0305,'/',0225,'W',' ',0302,'|',0225,037,0301,0373,0350,0370,0230,0361,0354,'s','T','J','%',0262,0235,0206,'_',033,0375,'0',0260,0322,0335,0134,0340,0330,0276,015,037,'r',0251,0256,0215,'&',0321,0223,027,0330,'2','6',0364,0340,0311,0322,'8',0134,0252,036,'j',030,0257,0320,0212,0300,0325,0272,0342,0213,0342,0200,0262,'3','`','f','o','n',0367,'V','`','t',0333,'X','_','+',0270,'3',0350,'-','b','(',026,0320,';',0311,'N','V',0224,0306,0315,0377,0,0306,0347,0260,0261,0370,033,033,0257,01,'z',035,'5',0332,0265,027,'v',0260,015,0300,0266,'~','P',0262,0370,'5',0367,'9',0331,0262,'/',010,',',0350,013,'k',':',0365,'^',')',024,032,'f',0316,0266,011,0257,0241,01,0211,031,'q','C',0221,024,0247,0247,'9',034,'L','p',0270,0261,0205,'M',':','r',0242,'G','D',0360,0220,0265,'O',0331,035,'U',0271,'3',015,0203,016,0251,'a',0353,0301,0367,0220,'K','h','h',034,'X',0242,0375,015,0376,0340,0244,'`','D','a',035,'=','|','G',0264,0245,0364,0274,0271,0355,025,0227,'8',0205,0265,0216,02,'Z',0313,034,'C','t',0234,0254,0276,0341,'@',0253,01,0225,0250,0350,0311,0310,0266,026,0323,01,0224,'S',0257,'R','.',0250,'6',015,'K',' ',0227,'J',0307,0242,0341,020,'a',0365,'+','_','P','Y',']',0276,0244,031,0316,02,'<',0265,'l',010,0134,0351,07,0256,'J','f',032,0202,047,0303,'C','*','(','D','X',0300,0234,'$','>','j',0333,']',0256,'V',0317,0231,0371,'=','h',0231,0356,'M',0207,0247,0367,0343,0275,04,020,'b',0260,0231,0320,'7','|','+','e',0360,'i',0356,'P','K',0301,0210,021,' ',0212,0224,0331,0272,'L',0272,0232,0331,')','$',011,'^',0347,0315,0322,0212,'A','@',' ',03,0,'z','0',0311,033,'a',0234,'J',0320,'Y',035,020,'j',034,0201,0262,014,0242,0226,026,'w',0300,0351,'r',0310,0220,'0',0216,0364,'Y','D','e','k',06,032,021,',','4',0220,0223,0325,'d','i',0300,'i',0134,0367,0262,0253,' ',024,0306,']','?',0210,'}','T','-','S',0231,'P',030,0302,'c',0273,0345,0377,0,'i',025,0207,0246,0222,0305,'s',0221,'b',0370,'5','}',0316,'>',0361,0371,0245,0203,'U',0300,027,'T',014,0325,0312,0325,0260,0226,013,0267,05,'Q','e',026,0230,0352,'k','x',0364,05,036,0324,0210,0354,037,'L',0351,0355,0254,0256,0340,'5',0214,0274,0253,035,'T',0317,';',0260,0271,'7','p',021,0321,027,0210,0242,':',0365,0262,016,'K','P','(',0270,0211,0247,'T','k',022,0377,0,')',0366,0233,'<','-','$',06,0201,0270,0226,'D',0242,'"',032,'G','W',0217,0213,0236,'=','L','[',0214,0307,0376,0247,0361,0336,0265,0272,'`',0221,0345,0340,'>','l','k','P','P','=',0345,0252,0345,'e','{',0373,0230,'~',012,'@',0252,'a','e',0263,0231,0225,0255,'^',0225,0352,'K',033,0203,0204,0223,'!','l',0205,0,'y',07,0200,026,0,0320,0364,0302,0245,0236,'F',031,0310,0212,'T','y','q',0326,'K','9',0356,'b',0272,0304,'$',0364,0220,'y',0361,0205,'A','>',021,0244,0265,0221,' ','L','a',011,023,'D','z',0242,'D',0330,',','g',0340,0371,'Q','Z',0374,031,0221,0373,'?','!','H',0214,'6','}','&',0246,034,0373,01,0345,0374,'Q',0223,0,0200,030,0342,0261,'$',014,'_',047,03,0253,0315,0264,0367,'.',015,'X',0331,0222,'A',0244,010,':',0316,0302,0220,025,'B','U','r',0257,'K',0340,'i','*',0260,01,'u','T',0,0250,'j',0200,027,025,0266,'[','E','e',0230,'^',0251,',',0230,06,'9',0231,0213,01,027,0201,0255,0246,0223,0264,0234,04,0302,'#',0204,'t',0352,'K',015,0360,0320,0263,0272,'N',0340,'J',0347,'Q',0,030,'6','P',0270,'v','~','I','5',0247,'2',0256,0213,0204,0334,'H','G','f',0220,'Z',0340,0345,'Z',0223,'m',0376,'{','u',0230,05,030,0,0225,0254,0337,0215,0266,'8',0321,0335,0370,'h','Z',0216,0301,0225,0335,'u','i',0220,'h','h','1',0334,'|',0275,0237,'r',0302,012,'t',014,'_','R','X',0362,01,'`','T',0325,0254,'3',0,01,0240,01,0240,015,':',0226,'y',0247,'P',0341,0204,0331,06,0326,'o','!',026,'z',0344,0255,0260,0224,0355,02,0302,'1',0344,0273,'g','I',0271,0332,'`',0231,02,0134,'F',0362,'T',0264,'P','%',0316,'M',0,047,'@','8',07,'P',0344,0,0206,0301,0336,'n',0216,'a',0360,0356,'I',0355,0302,'F',0310,0342,0205,01,0245,'U',0256,0355,0223,0346,0223,0360,0307,0373,'T',0274,'>',0353,'E','a','w',027,0352,0231,0354,'=',0352,032,'F','p',037,0246,0217,'1',032,'G',0372,'Q',0320,0346,0316,']',0334,0321,'A',0303,015,0247,0274,'_','u',':','>',06,'K',0233,'~',0333,035,0312,010,06,0,0200,014,01,0356,'"',0331,'1','k',')',013,0256,0253,0201,'+',0212,'6','9','5',021,'b',':',023,'+',0224,0253,0236,0253,'}',0204,0256,0204,0274,0302,06,0240,0261,'(',0266,0307,')','@',0312,'n',0214,0252,0272,0252,0347,0327,017,0325,0364,0211,011,0377,0,'r','7','*',0331,'F',0252,0345,0364,0256,020,'o',0,03,0251,0317,017,06,0,'K',0201,04,'L','E','M','~',0312,013,0134,'p',' ',0270,':',0200,0205,'F','@',0204,0215,0206,030,0363,'R',012,0232,04,'}',0312,'o',0336,0207,0352,0235,0367,0345,0373,0244,'}',0260,0177,'Z','2',027,014,0252,'C',0213,'+',0367,'T','O',0374,'N',01,0373,0320,0247,0334,024,016,0342,0324,0361,'@','@',01,0,020,036,0346,034,0364,0254,'1',0344,'v',']',0325,0205,0326,0202,0374,0343,0231,'r',013,0225,'e','n',0266,0,0351,0234,013,'t',030,06,0352,0224,'(','a','Y','"',':',0205,0300,'n','`','&',017,'`',')','0','l',016,'!',0352,0335,022,022,'%',0254,0216,0301,0271,'>',' ','(','M','C',0243,047,'R','p',0340,'m',0244,013,0210,0202,'%',0304,0245,'e','e','&',')','X','L',015,0227,'d',017,0360,0267,0224,'@','S',012,'[','.','^',0301,0,0316,';',0224,0222,'d',0216,'l','n',0267,'W','^',0271,0270,'k',0215,0362,0314,0242,06,'V',0360,0240,0366,'@','H',03,0214,0222,0233,0327,0344,0260,0206,'B',0370,014,020,016,0375,'d',0303,'I',0306,',',05,0321,'#',0205,0242,0324,0,0361,'U',011,',',010,0377,0,06,0330,'N',0201,0230,0302,015,0234,0315,';',0202,'M',0363,'~','"',0354,04,01,0200,0,0320,0353,0217,0201,'3','Y','e','j',0226,';',0324,02,017,'i',0212,0220,0260,'j',0313,0200,0231,0373,0221,015,036,'2','V','P',0246,0204,021,021,0270,0235,'w',0232,'Z','/','2',0255,0334,0226,'!',0330,024,0202,'<','1',0222,0231,'~',034,0353,022,'"',036,0376,012,0210,0321,0373,0272,0270,02,0353,'b',0216,'$',06,0231,0263,034,0271,0334,0235,0267,'D',014,'u','Q','e','U',0313,0327,'2',0201,031,'M','q',0254,0204,'j',010,'j',014,'x',0235,025,0,026,0,' ',017,'m','$',0215,0330,035,02,0340,'@','0','$','X',0242,0376,0256,0342,0210,'B',0342,'=','z','!',0331,0265,'H',0134,0262,0216,0342,0215,0232,'i',032,'*',0266,0310,0254,0333,036,0267,'$',0265,013,0271,0354,0270,'D',0367,0213,05,'H',0303,0342,'[',0334,'3',02,'_','I',0222,'S','F','!','Y',037,'3','o','v',0342,'j',0275,0,0257,0326,'H','N',026,'d',0311,0276,032,0201,0300,0203,0304,' ','K',0,0,07,0270,'r',0341,0220,014,0301,'&','t',01,'u','I','b',0314,07,0231,'4','D',0262,'d','D','K',0212,'z',04,0206,0345,'#',0332,'F',0271,0200,'!',0,0300,0254,'0',0371,0226,01,'.',0251,0233,024,031,0251,0252,0372,0327,'a',04,'N','O','r','F',014,0217,'f','Z','b',0320,'`',0221,0201,0242,0264,'v','@','Q','k','x','[',014,'0',0254,0372,' ',0202,0301,035,'p',0363,0261,'D',03,0223,0272,'i',0,',',0,'@',036,0352,036,0227,0207,'s',0243,0264,0256,'Z','n','*',0364,0364,'I',01,013,'e',0223,'W',022,022,'B','/',0240,0331,0264,0376,'|',0233,0366,0260,',',0201,'0',0224,0361,0204,034,0255,0256,0244,'x',0346,'`',0243,'p',020,'m',0342,'B',03,'p',017,0264,0134,0274,'.','L',0252,0,0356,0321,0257,'P',021,0306,'H','p',0246,015,0303,'j','~','o',0241,'9','v','&',0341,'A','O','D','@','`',0205,0270,01,'W',0265,'M',0215,01,0313,'V','I',0246,022,0327,0270,020,' ',0202,0307,0274,0210,022,0201,032,0,0331,0350,0202,'P',0301,')',0272,'J',05,0223,'N','3',010,'_',0321,0261,030,'Z',024,'J',0205,'B',0334,'j',0346,021,'F',016,'d',0242,'5','w',0306,'d',024,'S',',',0210,0331,0221,'t',0320,'Q',0211,'s','G',0257,0340,0260,0177,0324,05,010,0222,0134,0365,'C',0273,0310,0357,'k',0225,'M','#',0325,'3',0211,0231,'y',0307,'B',0222,'n',0341,0233,'B','.','/',011,0316,0266,0273,0313,0221,'p',0304,'Y',0213,'Z',026,0273,0372,'H',0317,0206,'G',014,0320,'v',022,0257,03,014,0,020,'A',03,'T',0255,0374,0306,0204,0230,03,0337,03,0,0204,'"','H',0224,0254,0320,'A',017,0310,0261,'e','W',0231,'-','.',0242,023,0263,0336,'y',02,'i',0237,'Q',0335,0202,'/',0201,'=',0210,0266,0212,0234,0221,0271,0311,'8',0220,0361,'1',0336,'i','-',0353,' ',0213,'e','i',0276,0211,0357,'_',0266,0262,017,0370,024,'8','g',0264,'|','T',0236,0225,',',0237,0205,0312,0210,0301,0313,'|','2',0241,'H',0211,'D',0274,016,0264,':',0360,'c',0232,02,0325,'L','A',0216,'V',0317,0264,0267,0305,032,037,'7',0210,0267,0211,'}',0244,0242,'5',0220,010,'W',0274,0321,0245,0252,0263,0377,0,'(',0304,0352,'H',0341,'^','f',0245,0224,'&',0206,0350,'U',0357,0351,0233,0237,0246,'I',0200,05,0325,'m',024,')',0272,'V','Z',0360,022,0341,031,0233,0322,'H','j',047,'8',0217,'.',0251,0226,0312,0212,0271,0177,0202,'v','6','V',04,0211,02,' ','-',0321,0266,'*',0362,022,0214,0200,',',010,014,0366,0,0363,'N',0236,010,0266,0204,'.','"','"','8',0376,06,'#',02,'^',0220,'!',0213,011,0261,0211,'!',0241,'f',0200,0222,'D',0276,'@',0273,'r','`',0302,0277,0206,0301,06,':',020,0222,'$',02,'X',01,0305,'@',0316,0341,'m',0314,0330,01,'-','-',010,0345,'n',0272,0204,'.','"','"','8',0367,0252,'*','Y',0341,0275,0306,'-',0320,'B',0311,'$',013,0323,0270,0224,0313,'M','G',04,025,0205,010,0224,'h','|','X',',',0,'X','8',0376,'&',0333,0204,'.',014,'B',0203,0223,0205,04,'v',0134,010,034,0231,'f',0354,'n','w',0244,0222,02,'F',0214,'K',0204,0271,'t',0227,0317,0270,013,'U','L',0206,0,'*',0360,'S',0247,0372,0272,0211,0234,0301,'k','j','f',0226,0211,0354,'9','p','Z','I','%',0264,0320,0344,'@','@',014,0,'`',0376,'5',022,'0','~',0272,'&',0215,'2',0316,'o',022,'5',0234,'5','P',0307,0252,' ',020,0325,'X',0263,0221,0305,'3',0223,014,014,0314,'h','m',0224,0217,0262,0236,'d',010,0321,'0','%','X',034,024,0324,'}',03,0330,'K',033,0250,'2',0350,01,0355,'x',03,':',0311,0212,'<',0351,022,'+',027,0371,0134,0231,0177,0223,012,011,06,013,0224,'C','N',0231,0325,031,0313,0225,0362,021,'A','&',0236,0257,026,'I',0205,0256,0340,'y',0253,0207,034,013,'F',023,'4',0363,'9',0253,0215,0370,'X','^',0366,0207,'8',0243,0210,'P',' ',0256,0326,0257,0350,'^',0233,'=',0211,01,'Z',02,'+',047,0231,0210,0371,'i',0334,0347,012,'p',0336,0354,0362,015,'^',0224,0315,013,030,0206,'_','V',0355,0212,0276,02,031,'M',0231,0203,0204,0346,'k','8','E','L','-','V','$',0274,0277,0315,0247,'s',0310,'H',0321,0226,04,'2',034,0213,'4','Z','L',0177,0224,0252,'v','7',0371,'l','(',0330,0343,'@','~',02,'Q',0241,035,0376,0205,0245,0247,0374,0313,'c','W',0361,0322,0365,0335,025,0255,012,0364,'w',0340,'?',0202,0377,0331,}; diff --git a/src/embedded_images/tick_erased.jpg.h b/src/embedded_images/tick_erased.jpg.h new file mode 100644 index 0000000..d1ef2cb --- /dev/null +++ b/src/embedded_images/tick_erased.jpg.h @@ -0,0 +1,16 @@ +/* Autogenerated by hxtools bin2c */ +#ifndef TICK_ERASED_JPG_H +#define TICK_ERASED_JPG_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern const unsigned char bin2c_te_jpg[54896]; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* TICK_ERASED_JPG_H */ diff --git a/src/embedded_images/tick_erased.xcf b/src/embedded_images/tick_erased.xcf Binary files differnew file mode 100644 index 0000000..61d0b59 --- /dev/null +++ b/src/embedded_images/tick_erased.xcf diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..9c34910 --- /dev/null +++ b/src/gui.c @@ -0,0 +1,7133 @@ +/* + * gui.c: An ncurses GUI for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* RATIONALE: + * + * This entire GUI is a non-portable task-specific thunk. + * + * The alternatives are, however, no better. The CDK is large and clumsy, + * and things like ncurses libmenu are not worth the storage overhead. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <time.h> + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ncurses.h> +#include <panel.h> +#include <stdint.h> +#include <libconfig.h> +#include <string.h> +#include <strings.h> +#include <sys/stat.h> + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "gui.h" +#include "pass.h" +#include "logging.h" +#include "version.h" +#include "temperature.h" +#include "miscellaneous.h" +#include "hpa_dco.h" +#include "customers.h" +#include "conf.h" + +#define NWIPE_GUI_PANE 8 + +/* Header window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_HEADER_W COLS +#define NWIPE_GUI_HEADER_H 1 +#define NWIPE_GUI_HEADER_X 0 +#define NWIPE_GUI_HEADER_Y 0 + +/* Footer window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_FOOTER_W COLS +#define NWIPE_GUI_FOOTER_H 1 +#define NWIPE_GUI_FOOTER_X 0 +#define NWIPE_GUI_FOOTER_Y ( LINES - 1 ) + +/* Options window: width, height, x coorindate, y coordinate. */ +#define NWIPE_GUI_OPTIONS_W 44 +#define NWIPE_GUI_OPTIONS_H 7 +#define NWIPE_GUI_OPTIONS_Y 1 +#define NWIPE_GUI_OPTIONS_X 0 + +/* Options fields, relative to their window. */ +#define NWIPE_GUI_OPTIONS_TAB 10 +#define NWIPE_GUI_OPTIONS_ENTROPY_Y 1 +#define NWIPE_GUI_OPTIONS_ENTROPY_X 1 +#define NWIPE_GUI_OPTIONS_PRNG_Y 2 +#define NWIPE_GUI_OPTIONS_PRNG_X 1 +#define NWIPE_GUI_OPTIONS_METHOD_Y 3 +#define NWIPE_GUI_OPTIONS_METHOD_X 1 +#define NWIPE_GUI_OPTIONS_VERIFY_Y 4 +#define NWIPE_GUI_OPTIONS_VERIFY_X 1 +#define NWIPE_GUI_OPTIONS_ROUNDS_Y 5 +#define NWIPE_GUI_OPTIONS_ROUNDS_X 1 + +/* Stats window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_STATS_W ( COLS - 44 ) +#define NWIPE_GUI_STATS_H 7 +#define NWIPE_GUI_STATS_Y 1 +#define NWIPE_GUI_STATS_X 44 + +/* Stats fields, relative to their window. */ +#define NWIPE_GUI_STATS_RUNTIME_Y 1 +#define NWIPE_GUI_STATS_RUNTIME_X 1 +#define NWIPE_GUI_STATS_ETA_Y 2 +#define NWIPE_GUI_STATS_ETA_X 1 +#define NWIPE_GUI_STATS_LOAD_Y 3 +#define NWIPE_GUI_STATS_LOAD_X 1 +#define NWIPE_GUI_STATS_THROUGHPUT_Y 4 +#define NWIPE_GUI_STATS_THROUGHPUT_X 1 +#define NWIPE_GUI_STATS_ERRORS_Y 5 +#define NWIPE_GUI_STATS_ERRORS_X 1 +#define NWIPE_GUI_STATS_TAB 16 + +/* Select window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_MAIN_W COLS +#define NWIPE_GUI_MAIN_H ( LINES - NWIPE_GUI_MAIN_Y - 1 ) +#define NWIPE_GUI_MAIN_Y 8 +#define NWIPE_GUI_MAIN_X 0 + +#define SKIP_DEV_PREFIX 5 + +/* Window pointers. */ +WINDOW* footer_window; +WINDOW* header_window; +WINDOW* main_window; +WINDOW* options_window; +WINDOW* stats_window; + +PANEL* footer_panel; +PANEL* header_panel; +PANEL* main_panel; +PANEL* options_panel; +PANEL* stats_panel; + +/* Options window title. */ +const char* options_title = " Options "; + +/* Statistics window title. */ +const char* stats_title = " Statistics "; + +/* Footer labels. */ +const char* main_window_footer = + "S=Start m=Method p=PRNG v=Verify r=Rounds b=Blanking Space=Select c=Config CTRL+C=Quit"; +const char* main_window_footer_warning_lower_case_s = " WARNING: To start the wipe press SHIFT+S (uppercase S) "; + +const char* main_window_footer_warning_no_blanking_with_ops2 = + " WARNING: Zero blanking is not allowed with ops2 method "; + +const char* main_window_footer_warning_no_blanking_with_verify_only = + " WARNING: Zero blanking is not allowed with verify method "; + +const char* main_window_footer_warning_no_drive_selected = + " No drives selected, use spacebar to select a drive, then press S to start "; + +/* Oddly enough, placing extra quotes around the footer strings fixes corruption to the right + * of the footer message when the terminal is resized, a quirk in ncurses? - DO NOT REMOVE THE \" */ +const char* selection_footer = "J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit"; +const char* selection_footer_config = "J=Down K=Up Return=Select ESC|Backspace=back Ctrl+C=Quit"; +const char* selection_footer_preview_prior_to_drive_selection = + "A=Accept & display drives J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit"; +const char* selection_footer_add_customer = "S=Save J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit"; +const char* selection_footer_add_customer_yes_no = "Save Customer Details Y/N"; +const char* end_wipe_footer = "B=[Toggle between dark\\blank\\blue screen] Ctrl+C=Quit"; +const char* rounds_footer = "Left=Erase Esc=Cancel Ctrl+C=Quit"; +const char* selection_footer_text_entry = "Esc=Cancel Return=Submit Ctrl+C=Quit"; + +/* The number of lines available in the terminal */ +int stdscr_lines; + +/* The number of columns available in the terminal */ +int stdscr_cols; + +/* The size of the terminal lines when previously checked */ +int stdscr_lines_previous; + +/* The size of the terminal columns when previously checked */ +int stdscr_cols_previous; + +int tft_saver = 0; + +void nwipe_gui_title( WINDOW* w, const char* s ) +{ + /** + * Prints the string 's' centered on the first line of the window 'w'. + */ + + /* The number of lines in the window. (Not used.) */ + int wy; + (void) wy; /* flag wy not used to the compiler, to silence warning */ + + /* The number of columns in the window. */ + int wx; + + /* Get the window dimensions. */ + getmaxyx( w, wy, wx ); + + /*Calculate available total margin */ + int margin = ( wx - strlen( s ) ); + if( margin < 0 ) + { + margin = 0; + } + + /* tft_saver = grey text on black mode */ + if( tft_saver ) + { + wattron( w, A_BOLD ); + } + + /* Print the title. */ + mvwprintw( w, 0, margin / 2, "%s", s ); + +} /* nwipe_gui_title */ + +void nwipe_init_pairs( void ) +{ + if( has_colors() ) + { + /* Initialize color capabilities. */ + start_color(); + + if( can_change_color() ) + { + /* Redefine cyan to gray. */ + init_color( COLOR_CYAN, 128, 128, 128 ); + } + + /* If we are in tft saver mode set grey text on black background else + * Set white on blue as the emphasis color */ + if( tft_saver ) + { + init_pair( 1, COLOR_BLACK, COLOR_BLACK ); + } + else + { + init_pair( 1, COLOR_WHITE, COLOR_BLUE ); + } + + /* Set gray (or cyan) on blue as the normal color. */ + init_pair( 2, COLOR_CYAN, COLOR_BLUE ); + + /* Set red on blue as the hilite color. */ + init_pair( 3, COLOR_RED, COLOR_BLUE ); + + /* If we are in tft saver mode set grey text on black background else + * Set white on blue as the emphasis color */ + if( tft_saver ) + { + init_pair( 4, COLOR_BLACK, COLOR_BLACK ); + } + else + { + init_pair( 4, COLOR_BLUE, COLOR_WHITE ); + } + + /* Set white on green for success messages. */ + init_pair( 5, COLOR_WHITE, COLOR_GREEN ); + + /* Set white on red for failure messages. */ + init_pair( 6, COLOR_WHITE, COLOR_RED ); + + /* Set black on black for when hiding the display. */ + init_pair( 7, COLOR_BLACK, COLOR_BLACK ); + + /* Set green on blue for reverse bold messages */ + init_pair( 8, COLOR_GREEN, COLOR_WHITE ); + + /* Set green on blue for reverse bold error messages */ + init_pair( 9, COLOR_RED, COLOR_WHITE ); + + /* Set black on yellow for warning messages */ + init_pair( 10, COLOR_BLACK, COLOR_YELLOW ); + + /* Set black on blue for minimum temperature reached */ + init_pair( 11, COLOR_BLACK, COLOR_BLUE ); + + /* Set blue on blue to make temperature invisible */ + init_pair( 12, COLOR_BLUE, COLOR_BLUE ); + + /* Set magenta on blue */ + init_pair( 13, COLOR_MAGENTA, COLOR_BLUE ); + + /* Set white on black for low critical temperature */ + init_pair( 14, COLOR_WHITE, COLOR_BLACK ); + + /* Set the background style. */ + wbkgdset( stdscr, COLOR_PAIR( 1 ) | ' ' ); + } +} + +void nwipe_gui_init( void ) +{ + /** + * Initializes the ncurses gui. + */ + + /* Initialize the screen. */ + initscr(); + + /* Disable TTY line buffering. */ + cbreak(); + + /* Disable TTY echo. */ + noecho(); + + /* Enable most special keys. */ + keypad( stdscr, TRUE ); + + /* Create the text/background color pairs */ + nwipe_init_pairs(); + + /* Clear the screen. */ + wclear( stdscr ); + + /* Create the header window. */ + nwipe_gui_create_header_window(); + + /* Create the footer window and panel */ + nwipe_gui_create_footer_window( main_window_footer ); + + /* Create the options window and panel */ + nwipe_gui_create_options_window(); + + /* Create the stats window. */ + nwipe_gui_create_stats_window(); + + /* Create a new main window and panel */ + nwipe_gui_create_main_window(); + + update_panels(); + doupdate(); + + /* Hide the cursor. */ + curs_set( 0 ); + +} /* nwipe_gui_init */ + +void nwipe_gui_free( void ) +{ + /** + * Releases the ncurses gui. + * + */ + /* Free ncurses resources. */ + if( del_panel( footer_panel ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting footer panel failed!." ); + } + if( del_panel( header_panel ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting header panel failed!." ); + } + if( del_panel( main_panel ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting main panel failed!." ); + } + if( del_panel( options_panel ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting options panel failed!." ); + } + if( del_panel( stats_panel ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting stats panel failed!." ); + } + if( delwin( footer_window ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting footer window failed!." ); + } + if( delwin( header_window ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting header window failed!." ); + } + if( delwin( main_window ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting main window failed!." ); + } + if( delwin( options_window ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting options window failed!." ); + } + if( delwin( stats_window ) != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Deleting stats window failed!." ); + } + if( endwin() != OK ) + { + nwipe_log( NWIPE_LOG_ERROR, "Curses endwin() failed !" ); + } + +} /* nwipe_gui_free */ + +void nwipe_gui_create_main_window() +{ + /* Create the main window. */ + main_window = newwin( NWIPE_GUI_MAIN_H, NWIPE_GUI_MAIN_W, NWIPE_GUI_MAIN_Y, NWIPE_GUI_MAIN_X ); + main_panel = new_panel( main_window ); + + if( has_colors() ) + { + /* Set the background style. */ + wbkgdset( main_window, COLOR_PAIR( 1 ) | ' ' ); + + /* Apply the color change. */ + wattron( main_window, COLOR_PAIR( 1 ) ); + + /* In tft saver mode we toggle the intensity bit which gives us grey text */ + if( tft_saver ) + { + wattron( main_window, A_BOLD ); + } + else + { + wattroff( main_window, A_BOLD ); + } + } + + /* Clear the main window. */ + werase( main_window ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* refresh main window */ + wnoutrefresh( main_window ); + +} /* nwipe_gui_create_main_window */ + +void nwipe_gui_create_header_window() +{ + char anon_label[] = " (ANONYMIZED)"; + char bannerplus[80]; + + /* Create the header window. */ + header_window = newwin( NWIPE_GUI_HEADER_H, NWIPE_GUI_HEADER_W, NWIPE_GUI_HEADER_Y, NWIPE_GUI_HEADER_X ); + header_panel = new_panel( header_window ); + + if( has_colors() ) + { + /* Set the background style of the header window. */ + wbkgdset( header_window, COLOR_PAIR( 4 ) | ' ' ); + + if( tft_saver ) + { + wattron( main_window, A_BOLD ); + } + } + + /* Clear the header window. */ + werase( header_window ); + + /* If in anonymized mode modify the title banner to reflect this */ + strcpy( bannerplus, banner ); + + if( nwipe_options.quiet ) + { + strcat( bannerplus, anon_label ); + } + + /* Print the product banner. */ + nwipe_gui_title( header_window, bannerplus ); + + /* Refresh the header window */ + wnoutrefresh( header_window ); + +} /* nwipe_gui_create_header_window */ + +void nwipe_gui_create_footer_window( const char* footer_text ) +{ + /* Create the footer window. */ + footer_window = newwin( NWIPE_GUI_FOOTER_H, NWIPE_GUI_FOOTER_W, NWIPE_GUI_FOOTER_Y, NWIPE_GUI_FOOTER_X ); + footer_panel = new_panel( footer_window ); + + if( has_colors() ) + { + /* Set the background style of the footer window. */ + wbkgdset( footer_window, COLOR_PAIR( 4 ) | ' ' ); + } + + /* Erase the footer window. */ + werase( footer_window ); + + /* Add help text to the footer */ + nwipe_gui_title( footer_window, footer_text ); + + /* Refresh the footer window */ + wnoutrefresh( footer_window ); + +} /* nwipe_gui_create_footer_window */ + +void nwipe_gui_amend_footer_window( const char* footer_text ) +{ + /* Clear the footer window. */ + werase( footer_window ); + + /* Add help text to the footer */ + nwipe_gui_title( footer_window, footer_text ); + + /* Refresh the footer window */ + wnoutrefresh( footer_window ); + +} /* nwipe_gui_amend_footer_window */ + +void nwipe_gui_create_options_window() +{ + /* Create the options window. */ + options_window = newwin( NWIPE_GUI_OPTIONS_H, NWIPE_GUI_OPTIONS_W, NWIPE_GUI_OPTIONS_Y, NWIPE_GUI_OPTIONS_X ); + options_panel = new_panel( options_window ); + + if( has_colors() ) + { + /* Set the background style of the options window. */ + wbkgdset( options_window, COLOR_PAIR( 1 ) | ' ' ); + + /* Apply the color change to the options window. */ + wattron( options_window, COLOR_PAIR( 1 ) ); + + if( tft_saver ) + { + wattron( options_window, A_BOLD ); + } + } + + /* Clear the options window. */ + werase( options_window ); + + /* Add a border. */ + box( options_window, 0, 0 ); + +} /* nwipe_gui_create_options_window */ + +void nwipe_gui_create_stats_window() +{ + /* Create the stats window. */ + stats_window = newwin( NWIPE_GUI_STATS_H, NWIPE_GUI_STATS_W, NWIPE_GUI_STATS_Y, NWIPE_GUI_STATS_X ); + stats_panel = new_panel( stats_window ); + + if( has_colors() ) + { + /* Set the background style of the stats window. */ + wbkgdset( stats_window, COLOR_PAIR( 1 ) | ' ' ); + + /* Apply the color change to the stats window. */ + wattron( stats_window, COLOR_PAIR( 1 ) ); + + if( tft_saver ) + { + wattron( stats_window, A_BOLD ); + } + } + + /* Clear the new window. */ + werase( stats_window ); + + /* Add a border. */ + box( stats_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( stats_window, stats_title ); + + /* Print field labels. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_RUNTIME_Y, NWIPE_GUI_STATS_RUNTIME_X, "Runtime: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, NWIPE_GUI_STATS_ETA_X, "Remaining: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_LOAD_X, "Load Averages: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_THROUGHPUT_X, "Throughput: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_ERRORS_X, "Errors: " ); + +} /* nwipe_gui_create_stats_window */ + +void nwipe_gui_create_all_windows_on_terminal_resize( int force_creation, const char* footer_text ) +{ + /* Get the terminal size */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* If the user has resized the terminal then recreate the windows and panels */ + if( stdscr_cols_previous != stdscr_cols || stdscr_lines_previous != stdscr_lines || force_creation == 1 ) + { + /* Save the revised terminal size so we check whether the user has resized next time */ + stdscr_lines_previous = stdscr_lines; + stdscr_cols_previous = stdscr_cols; + + /* Clear the screen. */ + wclear( stdscr ); + + /* Create a new header window and panel due to terminal size having changed */ + nwipe_gui_create_header_window(); + + /* Create a new main window and panel due to terminal size having changed */ + nwipe_gui_create_main_window(); + + /* Create a new footer window and panel due to terminal size having changed */ + nwipe_gui_create_footer_window( footer_text ); + + /* Create a new options window and panel due to terminal size having changed */ + nwipe_gui_create_options_window(); + + /* Create a new stats window and panel due to terminal size having changed */ + nwipe_gui_create_stats_window(); + + /* Update the options window. */ + nwipe_gui_options(); + + update_panels(); + doupdate(); + } +} + +void nwipe_gui_select( int count, nwipe_context_t** c ) +{ + extern int terminate_signal; + + /* Widget labels. */ + const char* select_title = " Disks and Partitions "; + + /* The number of lines available in the window. */ + int wlines; + + /* The number of columns available in the window. */ + int wcols; + + /* The number of selection elements that we can show in the window. */ + int slots; + + /* The index of the element that is visible in the first slot. */ + int offset = 0; + + /* The selection focus. */ + int focus = 0; + + /* A generic loop variable. */ + int i = 0; + + /* User input buffer. */ + int keystroke; + + /* The current working line. */ + int yy; + + /* Flag, Valid key hit = 1, anything else = 0 */ + int validkeyhit; + + /* Counts number of drives and partitions that have been selected */ + int number_of_selected_contexts = 0; + + /* Control A toggle status -1=indefined, 0=all drives delected, 1=all drives selected */ + int select_all_toggle_status = -1; + + /* Get the terminal size */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Save the terminal size so we check whether the user has resized */ + stdscr_lines_previous = stdscr_lines; + stdscr_cols_previous = stdscr_cols; + + time_t temperature_check_time = time( NULL ); + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int iteration_counter; + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int expected_iterations; + + time_t previous_iteration_timestamp; + + do + { + + nwipe_gui_create_all_windows_on_terminal_resize( 0, main_window_footer ); + + /* There is one slot per line. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less two lines for the box and two lines for padding. */ + slots = wlines - 4; + if( slots < 0 ) + { + slots = 0; + } + + /* The code here adjusts the offset value, required when the terminal is resized vertically */ + if( slots > count ) + { + offset = 0; + } + else + { + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + } + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + } + } + + if( count >= slots && slots > 0 ) + { + offset = focus + 1 - slots; + if( offset < 0 ) + { + offset = 0; + } + } + + /* Clear the main window, necessary when switching selections such as method etc */ + werase( main_window ); + + /* Refresh main window */ + wnoutrefresh( main_window ); + + /* If the user selected an option the footer text would have changed. + * Here we set it back to the main key help text */ + nwipe_gui_create_footer_window( main_window_footer ); + + /* Refresh the stats window */ + wnoutrefresh( stats_window ); + + /* Refresh the options window */ + wnoutrefresh( options_window ); + + /* Update the options window. */ + nwipe_gui_options(); + + /* Initialize the line offset. */ + yy = 2; + + for( i = 0; i < slots && i < count; i++ ) + { + + /* Move to the next line. */ + mvwprintw( main_window, yy++, 1, " " ); + + if( i + offset == focus ) + { + if( c[focus]->select == NWIPE_SELECT_TRUE || c[focus]->select == NWIPE_SELECT_FALSE ) + { + /* Print the 'enabled' cursor. */ + waddch( main_window, ACS_RARROW ); + } + + else + { + /* Print the 'disabled' cursor. */ + waddch( main_window, ACS_DIAMOND ); + } + } + + else + { + /* Print whitespace. */ + waddch( main_window, ' ' ); + } + + /* In the event for the offset value somehow becoming invalid, this if statement will prevent a segfault + * and the else part will log the out of bounds values for debugging */ + if( i + offset >= 0 && i + offset < count ) + { + + switch( c[i + offset]->select ) + { + case NWIPE_SELECT_TRUE: + + if( nwipe_options.method == &nwipe_verify_zero || nwipe_options.method == &nwipe_verify_one ) + { + wprintw( main_window, + "[vrfy] %s %s ", + c[i + offset]->gui_device_name, + c[i + offset]->device_type_str ); + } + else + { + wprintw( main_window, + "[wipe] %s %s ", + c[i + offset]->gui_device_name, + c[i + offset]->device_type_str ); + } + break; + + case NWIPE_SELECT_FALSE: + /* Print an element that is not selected. */ + wprintw( main_window, + "[ ] %s %s ", + c[i + offset]->gui_device_name, + c[i + offset]->device_type_str ); + break; + + case NWIPE_SELECT_TRUE_PARENT: + + /* This element will be wiped when its parent is wiped. */ + wprintw( main_window, + "[****] %s %s ", + c[i + offset]->gui_device_name, + c[i + offset]->device_type_str ); + break; + + case NWIPE_SELECT_FALSE_CHILD: + + /* We can't wipe this element because it has a child that is being wiped. */ + wprintw( main_window, + "[----] %s %s ", + c[i + offset]->gui_device_name, + c[i + offset]->device_type_str ); + break; + + case NWIPE_SELECT_DISABLED: + + /* We don't know how to wipe this device. (Iomega Zip drives.) */ + wprintw( main_window, "[????] %s ", "Unrecognized Device" ); + break; + + default: + + /* TODO: Handle the sanity error. */ + break; + + } /* switch select */ + + wprintw( main_window, "[%s] ", c[i + offset]->device_size_text ); + + /* Read the drive temperature values */ + // nwipe_update_temperature( c[i + offset] ); + + /* print the temperature */ + wprintw_temperature( c[i + offset] ); + + switch( c[i + offset]->HPA_status ) + { + case HPA_ENABLED: + wprintw( main_window, " " ); + wattron( main_window, COLOR_PAIR( 9 ) ); + wprintw( main_window, "[HS? YES]" ); + wattroff( main_window, COLOR_PAIR( 9 ) ); + break; + + case HPA_DISABLED: + wprintw( main_window, " " ); + wprintw( main_window, "[HS? NO ]" ); + break; + + case HPA_UNKNOWN: + wprintw( main_window, " " ); + wprintw( main_window, "[HS? ???]" ); + break; + + default: + + wprintw( main_window, " " ); + wprintw( main_window, "[HS? N/A]" ); + break; + } + + /* print the drive model and serial number */ + wprintw( main_window, " %s/%s", c[i + offset]->device_model, c[i + offset]->device_serial_no ); + + if( c[i + offset]->HPA_toggle_time + 1 < time( NULL ) ) + { + switch( c[i + offset]->HPA_display_toggle_state ) + { + case 0: + c[i + offset]->HPA_display_toggle_state = 1; + break; + + case 1: + c[i + offset]->HPA_display_toggle_state = 0; + break; + } + c[i + offset]->HPA_toggle_time = time( NULL ); + } + } + else + { + nwipe_log( NWIPE_LOG_DEBUG, + "GUI.c,nwipe_gui_select(), scroll, array index out of bounds, i=%u, count=%u, slots=%u, " + "focus=%u, offset=%u", + i, + count, + slots, + focus, + offset ); + } + + } /* for */ + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols - 8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines - 2, wcols - 8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + /* Draw a border around the menu window. */ + box( main_window, 0, 0 ); + + /* Print a title. */ + nwipe_gui_title( main_window, select_title ); + + /* Refresh the window. */ + wnoutrefresh( main_window ); + + /* Output to physical screen */ + doupdate(); + + /* Initialise the iteration counter */ + iteration_counter = 0; + + previous_iteration_timestamp = time( NULL ); + + /* Calculate Maximum allowed iterations per second */ + expected_iterations = ( 1000 / GETCH_BLOCK_MS ) * 8; + + do + { + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + + validkeyhit = 0; + timeout( GETCH_BLOCK_MS ); // block getch() for ideally about 250ms. + keystroke = getch(); // Get user input. + timeout( -1 ); // Switch back to blocking mode. + + /* To avoid 100% CPU usage, check for a runaway condition caused by the "keystroke = getch(); (above), from + * immediately returning an error condition. We check for an error condition because getch() returns a ERR + * value when the timeout value "timeout( 250 );" expires as well as when a real error occurs. We can't + * differentiate from normal operation and a failure of the getch function to block for the specified period + * of timeout. So here we check the while loop hasn't exceeded the number of expected iterations per second + * ie. a timeout(250) block value of 250ms means we should not see any more than (1000/250) = 4 iterations. + * We increase this to 32 iterations to allow a little tolerance. Why is this necessary? It's been found + * that in KDE konsole and other terminals based on the QT terminal engine exiting the terminal without + * first exiting nwipe results in nwipe remaining running but detached from any interface which causes + * getch to fail and its associated timeout. So the CPU or CPU core rises to 100%. Here we detect that + * failure and exit nwipe gracefully with the appropriate error. This does not affect use of tmux for + * attaching or detaching from a running nwipe session when sitting at the selection screen. All other + * terminals correctly terminate nwipe when the terminal itself is exited. + */ + + iteration_counter++; + + if( previous_iteration_timestamp == time( NULL ) ) + { + if( iteration_counter > expected_iterations ) + { + nwipe_log( NWIPE_LOG_ERROR, + "GUI.c,nwipe_gui_select(), loop runaway, did you close the terminal without exiting " + "nwipe? Exiting nwipe now." ); + /* Issue signal to nwipe to exit immediately but gracefully */ + terminate_signal = 1; + } + } + else + { + /* new second, so reset counter */ + iteration_counter = 0; + previous_iteration_timestamp = time( NULL ); + } + + /* We don't necessarily use all of these. For future reference these are some CTRL+key values + * ^A - 1, ^B - 2, ^D - 4, ^E - 5, ^F - 6, ^G - 7, ^H - 8, ^I - 9, ^K - 11, ^L - 12, ^N - 14, + * ^O - 15, ^P - 16, ^R - 18, ^T - 20, ^U - 21, ^V - 22, ^W - 23, ^X - 24, ^Y - 25 + * Use nwipe_log( NWIPE_LOG_DEBUG, "Key Name: %s - %u", keyname(keystroke),keystroke) to + * figure out what code is returned by what ever key combination */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + validkeyhit = 1; + + /* Increment the focus. */ + focus += 1; + + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + break; + } + + if( focus - offset >= slots ) + { + /* The next element is offscreen. Scroll down. */ + offset += 1; + break; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + validkeyhit = 1; + + /* Decrement the focus. */ + focus -= 1; + + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + break; + } + + if( focus < offset ) + { + /* The next element is offscreen. Scroll up. */ + offset -= 1; + break; + } + + break; + + case KEY_ENTER: + case 10: + case ' ': + + validkeyhit = 1; + + /* TODO: This block should be made into a function. */ + + if( c[focus]->select == NWIPE_SELECT_TRUE ) + { + /* Reverse the selection of this element. */ + c[focus]->select = NWIPE_SELECT_FALSE; + + if( c[focus]->device_part == 0 ) + { + /* Sub-deselect all partitions and slices within this disk. */ + for( i = 0; i < count; i++ ) + { + if( c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun && c[i]->device_part > 0 ) + { + c[i]->select = NWIPE_SELECT_FALSE; + } + + } /* for all contexts */ + + } /* if sub-deselect */ + + else + { + /* The number of selected partitions or slices within this disk. */ + int j = 0; + + for( i = 0; i < count; i++ ) + { + if( c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun && c[i]->device_part > 0 + && c[i]->select == NWIPE_SELECT_TRUE ) + { + /* Increment the counter. */ + j += 1; + } + + } /* for all contexts */ + + if( j == 0 ) + { + /* Find the parent disk of this partition or slice. */ + for( i = 0; i < count; i++ ) + { + if( c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun && c[i]->device_part == 0 ) + { + /* Enable the disk element. */ + c[i]->select = NWIPE_SELECT_FALSE; + } + + } /* for all contexts */ + + } /* if */ + + } /* else super-enable */ + + break; + + } /* if NWIPE_SELECT_TRUE */ + + if( c[focus]->select == NWIPE_SELECT_FALSE ) + { + /* Reverse the selection. */ + c[focus]->select = NWIPE_SELECT_TRUE; + + if( c[focus]->device_part == 0 ) + { + /* Sub-select all partitions and slices within this disk. */ + for( i = 0; i < count; i++ ) + { + if( c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun && c[i]->device_part > 0 ) + { + c[i]->select = NWIPE_SELECT_TRUE_PARENT; + } + + } /* for */ + + } /* if sub-select */ + + else + { + /* ASSERT: ( c[focus]->device_part > 0 ) */ + + /* Super-deselect the disk that contains this device. */ + for( i = 0; i < count; i++ ) + { + if( c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun && c[i]->device_part == 0 ) + { + c[i]->select = NWIPE_SELECT_FALSE_CHILD; + } + } + + } /* else super-deselect */ + + break; + + } /* if NWIPE_SELECT_FALSE */ + + /* TODO: Explain to the user why they can't change this. */ + break; + + case 'm': + case 'M': + + validkeyhit = 1; + + /* Run the method dialog. */ + nwipe_gui_method(); + break; + + case 'p': + case 'P': + + validkeyhit = 1; + + /* Run the PRNG dialog. */ + nwipe_gui_prng(); + + break; + + case 'r': + case 'R': + + validkeyhit = 1; + + /* Run the rounds dialog. */ + nwipe_gui_rounds(); + + break; + + case 'v': + case 'V': + + validkeyhit = 1; + + /* Run the option dialog. */ + nwipe_gui_verify(); + break; + + case 'b': + case 'B': + + validkeyhit = 1; + + if( nwipe_options.method == &nwipe_ops2 ) + { + /* Warn the user about that zero blanking with the ops2 method is not allowed */ + wattron( footer_window, COLOR_PAIR( 10 ) ); + nwipe_gui_amend_footer_window( main_window_footer_warning_no_blanking_with_ops2 ); + doupdate(); + sleep( 3 ); + wattroff( footer_window, COLOR_PAIR( 10 ) ); + + /* After the delay return footer text back to key help */ + nwipe_gui_amend_footer_window( main_window_footer ); + doupdate(); + + break; + } + + if( nwipe_options.method == &nwipe_verify_zero || nwipe_options.method == &nwipe_verify_one ) + { + /* Warn the user about that zero blanking with the ops2 method is not allowed */ + wattron( footer_window, COLOR_PAIR( 10 ) ); + nwipe_gui_amend_footer_window( main_window_footer_warning_no_blanking_with_verify_only ); + doupdate(); + sleep( 3 ); + wattroff( footer_window, COLOR_PAIR( 10 ) ); + + /* After the delay return footer text back to key help */ + nwipe_gui_amend_footer_window( main_window_footer ); + doupdate(); + + break; + } + + /* Run the noblank dialog. */ + nwipe_gui_noblank(); + break; + + case 'c': + case 'C': + /* main configuration menu */ + validkeyhit = 1; + + /* Run the configuration dialog */ + nwipe_gui_config(); + break; + + case 'S': + + /* User wants to start the wipe */ + validkeyhit = 1; + + /* Have any drives have been selected ? */ + number_of_selected_contexts = 0; + for( i = 0; i < count; i++ ) + { + if( c[i]->select == NWIPE_SELECT_TRUE ) + { + number_of_selected_contexts += 1; + } + } + + /* if no drives have been selected, print a warning on the footer */ + if( number_of_selected_contexts == 0 ) + { + wattron( footer_window, COLOR_PAIR( 10 ) ); + nwipe_gui_amend_footer_window( main_window_footer_warning_no_drive_selected ); + doupdate(); + sleep( 3 ); + wattroff( footer_window, COLOR_PAIR( 10 ) ); + + /* After the delay return footer text back to key help */ + nwipe_gui_amend_footer_window( main_window_footer ); + doupdate(); + + /* Remove any repeated S key strokes, without this the gui would hang + * for a period of time, i.e sleep above x number of repeated 's' keystrokes + * which could run into minutes */ + do + { + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get user input. + timeout( -1 ); // Switch back to blocking mode. + } while( keystroke == 'S' ); + + /* Remove the S from keystroke, which allows us to stay within the selection menu loop */ + keystroke = 0; + } + + break; + + case 's': + + /* user has mistakenly hit the lower case 's' instead of capital 'S' */ + validkeyhit = 1; + + /* Warn the user about their mistake */ + wattron( footer_window, COLOR_PAIR( 10 ) ); + nwipe_gui_amend_footer_window( main_window_footer_warning_lower_case_s ); + doupdate(); + sleep( 3 ); + wattroff( footer_window, COLOR_PAIR( 10 ) ); + + /* After the delay return footer text back to key help */ + nwipe_gui_amend_footer_window( main_window_footer ); + doupdate(); + + /* Remove any repeated s key strokes, without this the gui would hang + * for a period of time, i.e sleep above x number of repeated 's' keystrokes + * which could run into minutes */ + do + { + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get user input. + timeout( -1 ); // Switch back to blocking mode. + } while( keystroke == 's' ); + + break; + + case 1: + + /* Ctrl A - Toggle select/deselect all drives */ + validkeyhit = 1; + + if( select_all_toggle_status == -1 || select_all_toggle_status == 0 ) + { + for( i = 0; i < count; i++ ) + { + c[i]->select = NWIPE_SELECT_TRUE; + } + select_all_toggle_status = 1; + } + else + { + if( select_all_toggle_status == 1 ) + { + for( i = 0; i < count; i++ ) + { + c[i]->select = NWIPE_SELECT_FALSE; + } + select_all_toggle_status = 0; + } + else + { + nwipe_log( + NWIPE_LOG_ERROR, + "gui.c:nwipe_gui_select(), Invalid value in variable select_all_toggle_status = %d", + select_all_toggle_status ); + } + } + + break; + + } /* keystroke switch */ + + /* Check the terminal size, if the user has changed it the while loop checks for + * this change and exits the valid key hit loop so the windows can be updated */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Update the selection window every 1 second specifically + * so that the drive temperatures are updated and also the line toggle that + * occurs with the HPA status and the drive size & temperature. + */ + if( time( NULL ) > ( temperature_check_time + 1 ) ) + { + temperature_check_time = time( NULL ); + validkeyhit = 1; + } + + } /* key hit loop */ + while( validkeyhit == 0 && terminate_signal != 1 && stdscr_cols_previous == stdscr_cols + && stdscr_lines_previous == stdscr_lines ); + + } while( keystroke != 'S' && terminate_signal != 1 ); + + if( keystroke == 'S' ) + { + /* If user has pressed S to start wipe change status line */ + werase( footer_window ); + nwipe_gui_title( footer_window, end_wipe_footer ); + wnoutrefresh( footer_window ); + } + +} /* nwipe_gui_select */ + +void nwipe_gui_options( void ) +{ + /** + * Updates the options window. + * + * @modifies options_window + * + */ + + /* Erase the window. */ + werase( options_window ); + + mvwprintw( + options_window, NWIPE_GUI_OPTIONS_ENTROPY_Y, NWIPE_GUI_OPTIONS_ENTROPY_X, "Entropy: Linux Kernel (urandom)" ); + + mvwprintw( + options_window, NWIPE_GUI_OPTIONS_PRNG_Y, NWIPE_GUI_OPTIONS_PRNG_X, "PRNG: %s", nwipe_options.prng->label ); + + mvwprintw( options_window, + NWIPE_GUI_OPTIONS_METHOD_Y, + NWIPE_GUI_OPTIONS_METHOD_X, + "Method: %s", + nwipe_method_label( nwipe_options.method ) ); + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_VERIFY_Y, NWIPE_GUI_OPTIONS_VERIFY_X, "Verify: " ); + + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + wprintw( options_window, "Off" ); + break; + + case NWIPE_VERIFY_LAST: + wprintw( options_window, "Last Pass" ); + break; + + case NWIPE_VERIFY_ALL: + wprintw( options_window, "All Passes" ); + break; + + default: + wprintw( options_window, "Unknown %i", nwipe_options.verify ); + + } /* switch verify */ + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_ROUNDS_Y, NWIPE_GUI_OPTIONS_ROUNDS_X, "Rounds: " ); + + /* Disable blanking for ops2 and verify methods */ + if( nwipe_options.method == &nwipe_ops2 || nwipe_options.method == &nwipe_verify_zero + || nwipe_options.method == &nwipe_verify_one ) + { + nwipe_options.noblank = 1; + } + + if( nwipe_options.noblank ) + { + wprintw( options_window, "%i (no final blanking pass)", nwipe_options.rounds ); + } + else + { + wprintw( options_window, "%i (plus blanking pass)", nwipe_options.rounds ); + } + + /* Add a border. */ + box( options_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( options_window, options_title ); + + /* Refresh the window. */ + // wrefresh( options_window ); + wnoutrefresh( options_window ); + +} /* nwipe_gui_options */ + +void nwipe_gui_rounds( void ) +{ + /** + * Allows the user to change the rounds option. + * + * @modifies nwipe_options.rounds + * @modifies main_window + * + */ + + /* Set the initial focus. */ + int focus = nwipe_options.rounds; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, rounds_footer ); + wrefresh( footer_window ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Rounds " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "This is the number of times to run the wipe method on each device." ); + yy++; + + if( focus > 0 ) + { + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, "> %i", focus ); + } + else + { + mvwprintw( main_window, yy++, tab1, "The number of rounds must be a non-negative integer." ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, "> " ); + } + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + if( focus < 100000000 ) + { + /* Left shift, base ten. */ + focus *= 10; + + /* This assumes ASCII input, where the zero character is 0x30. */ + focus += keystroke - 48; + } + + break; + + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + /* Right shift, base ten. */ + focus /= 10; + + break; + + } /* switch keystroke */ + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + if( focus > 0 ) + { + /* Set the number of rounds. */ + nwipe_options.rounds = focus; + } + +} /* nwipe_guid_rounds */ + +void nwipe_gui_prng( void ) +{ + /** + * Allows the user to change the PRNG. + * + * @modifies nwipe_options.prng + * @modifies main_window + * + */ + + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + extern int terminate_signal; + + /* The number of implemented PRNGs. */ + const int count = 3; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* Set the initial focus. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + if( nwipe_options.prng == &nwipe_twister ) + { + focus = 0; + } + if( nwipe_options.prng == &nwipe_isaac ) + { + focus = 1; + } + if( nwipe_options.prng == &nwipe_isaac64 ) + { + focus = 2; + } + + do + { + /* Clear the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + + /* Initialize the working row. */ + yy = 3; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", nwipe_twister.label ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac.label ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac64.label ); + yy++; + + /* Print the cursor. */ + mvwaddch( main_window, 3 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + mvwprintw( main_window, + yy++, + tab1, + "The Mersenne Twister, by Makoto Matsumoto and Takuji Nishimura, is a " ); + mvwprintw( main_window, + yy++, + tab1, + "generalized feedback shift register PRNG that is uniform and " ); + mvwprintw( main_window, + yy++, + tab1, + "equidistributed in 623-dimensions with a proven period of 2^19937-1. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "This implementation passes the Marsaglia Diehard test suite. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + break; + + case 1: + + mvwprintw( main_window, + yy++, + tab1, + "ISAAC, by Bob Jenkins, is a PRNG derived from RC4 with a minimum period of " ); + mvwprintw( main_window, + yy++, + tab1, + "2^40 and an expected period of 2^8295. It is difficult to recover the " ); + mvwprintw( main_window, + yy++, + tab1, + "initial PRNG state by cryptanalysis of the ISAAC stream. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "Performs best on a 32-bit CPU. Use ISAAC-64 if this system has a 64-bit CPU." ); + break; + + case 2: + + mvwprintw( main_window, + yy++, + tab1, + "ISAAC-64, by Bob Jenkins, is like 32-bit ISAAC, but with a minimum period of" ); + mvwprintw( main_window, + yy++, + tab1, + "2^77 and an expected period of 2^16583. It is difficult to recover the " ); + mvwprintw( main_window, + yy++, + tab1, + "initial PRNG state by cryptanalysis of the ISAAC-64 stream. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "Performs best on a 64-bit CPU. Use ISAAC if this system has a 32-bit CPU. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Pseudo Random Number Generator " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus == 0 ) + { + nwipe_options.prng = &nwipe_twister; + } + if( focus == 1 ) + { + nwipe_options.prng = &nwipe_isaac; + } + if( focus == 2 ) + { + nwipe_options.prng = &nwipe_isaac64; + } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } while( terminate_signal != 1 ); + +} /* nwipe_gui_prng */ + +void nwipe_gui_verify( void ) +{ + /** + * Allows the user to change the verification option. + * + * @modifies nwipe_options.verify + * @modifies main_window + * + */ + + extern int terminate_signal; + + /* The number of definitions in the nwipe_verify_t enumeration. */ + const int count = 3; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* Set the initial focus. */ + int focus = nwipe_options.verify; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + do + { + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " Verification Off " ); + mvwprintw( main_window, yy++, tab1, " Verify Last Pass " ); + mvwprintw( main_window, yy++, tab1, " Verify All Passes " ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + mvwprintw( main_window, + yy++, + tab1, + "Do not verify passes. The wipe will be a write-only operation. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + break; + + case 1: + + mvwprintw( main_window, + yy++, + tab1, + "Check whether the device is actually empty after the last pass fills the " ); + mvwprintw( main_window, + yy++, + tab1, + "device with zeros. " ); + break; + + case 2: + + mvwprintw( main_window, + yy++, + tab1, + "After every pass, read back the pattern and check whether it is correct. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "This program writes the entire length of the device before it reads back " ); + mvwprintw( main_window, + yy++, + tab1, + "for verification, even for random pattern passes, to better ensure that " ); + mvwprintw( main_window, + yy++, + tab1, + "hardware caches are actually flushed. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Verification Mode " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus >= 0 && focus < count ) + { + nwipe_options.verify = focus; + } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } while( terminate_signal != 1 ); + +} /* nwipe_gui_verify */ + +void nwipe_gui_noblank( void ) +{ + /** + * Allows the user to change the verification option. + * + * @modifies nwipe_options.noblank + * @modifies main_window + * + */ + + extern int terminate_signal; + + /* The number of options available. */ + const int count = 2; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 40; + + /* Set the initial focus. */ + int focus = nwipe_options.noblank; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + do + { + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " Perform a final blanking pass " ); + mvwprintw( main_window, yy++, tab1, " Do not perform final blanking pass " ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + mvwprintw( main_window, + yy++, + tab1, + "Perform a final blanking pass after the wipe, leaving disk with only zeros. " ); + mvwprintw( main_window, + yy++, + tab1, + "Note that the RCMP TSSIT OPS-II method never blanks the device regardless " ); + mvwprintw( main_window, + yy++, + tab1, + "of this setting. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + break; + + case 1: + + mvwprintw( main_window, + yy++, + tab1, + "Do not perform a final blanking pass. Leave data as per final wiping pass. " ); + mvwprintw( main_window, + yy++, + tab1, + "Note that the RCMP TSSIT OPS-II method never blanks the device regardless " ); + mvwprintw( main_window, + yy++, + tab1, + "of this setting. " ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Final Blanking Pass " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus >= 0 && focus < count ) + { + nwipe_options.noblank = focus; + } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } + + while( terminate_signal != 1 ); +} /* nwipe_gui_noblank */ + +void nwipe_gui_method( void ) +{ + /** + * Allows the user to change the wipe method. + * + * @modifies nwipe_options.method + * @modifies main_window + * + */ + + extern int terminate_signal; + + /* The number of implemented methods. */ + const int count = 10; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + if( nwipe_options.method == &nwipe_zero ) + { + focus = 0; + } + if( nwipe_options.method == &nwipe_one ) + { + focus = 1; + } + if( nwipe_options.method == &nwipe_ops2 ) + { + focus = 2; + } + if( nwipe_options.method == &nwipe_dodshort ) + { + focus = 3; + } + if( nwipe_options.method == &nwipe_dod522022m ) + { + focus = 4; + } + if( nwipe_options.method == &nwipe_gutmann ) + { + focus = 5; + } + if( nwipe_options.method == &nwipe_random ) + { + focus = 6; + } + if( nwipe_options.method == &nwipe_verify_zero ) + { + focus = 7; + } + if( nwipe_options.method == &nwipe_verify_one ) + { + focus = 8; + } + if( nwipe_options.method == &nwipe_is5enh ) + { + focus = 9; + } + + do + { + /* Clear the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_zero ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_one ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_ops2 ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_dodshort ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_dod522022m ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_gutmann ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_random ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_verify_zero ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_verify_one ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_is5enh ) ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + mvwprintw( main_window, 2, tab2, "Security Level: high (1 pass)" ); + + mvwprintw( main_window, 4, tab2, "This method fills the device with zeros. Note " ); + mvwprintw( main_window, 5, tab2, "that the rounds option does not apply to this " ); + mvwprintw( main_window, 6, tab2, "method. This method always runs one round. " ); + mvwprintw( main_window, 7, tab2, " " ); + mvwprintw( main_window, 8, tab2, "There is no publicly available evidence that " ); + mvwprintw( main_window, 9, tab2, "data can be recovered from a modern traditional " ); + mvwprintw( main_window, 10, tab2, "hard drive (HDD) that has been zero wiped, " ); + mvwprintw( main_window, 11, tab2, "however a wipe that includes a prng may be " ); + mvwprintw( main_window, 12, tab2, "preferable. " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "Security Level: high (1 pass)" ); + + mvwprintw( main_window, 4, tab2, "This method fills the device with ones. Note that" ); + mvwprintw( main_window, 5, tab2, "the rounds option does not apply to this method. " ); + mvwprintw( main_window, 6, tab2, "This method always runs one round. " ); + mvwprintw( main_window, 7, tab2, " " ); + mvwprintw( main_window, 8, tab2, "This method might be used when wiping a solid " ); + mvwprintw( main_window, 9, tab2, "state drive if an additional level of security is" ); + mvwprintw( main_window, 10, tab2, "required beyond using the drives internal secure " ); + mvwprintw( main_window, 11, tab2, "erase features. Alternatively PRNG may be " ); + mvwprintw( main_window, 12, tab2, "preferable. " ); + break; + + case 2: + + mvwprintw( main_window, 2, tab2, "Security Level: higher (8 passes)" ); + + mvwprintw( main_window, 4, tab2, "The Royal Canadian Mounted Police Technical " ); + mvwprintw( main_window, 5, tab2, "Security Standard for Information Technology. " ); + mvwprintw( main_window, 6, tab2, "Appendix OPS-II: Media Sanitization. " ); + mvwprintw( main_window, 7, tab2, " " ); + mvwprintw( main_window, 8, tab2, "This implementation, with regards to paragraph 2 " ); + mvwprintw( main_window, 9, tab2, "section A of the standard, uses a pattern that is" ); + mvwprintw( main_window, 10, tab2, "one random byte and that is changed each round. " ); + break; + + case 3: + + mvwprintw( main_window, 2, tab2, "Security Level: higher (3 passes)" ); + + mvwprintw( main_window, 4, tab2, "The US Department of Defense 5220.22-M short wipe" ); + mvwprintw( main_window, 5, tab2, "This method is composed of passes 1, 2 & 7 from " ); + mvwprintw( main_window, 6, tab2, "the standard DoD 5220.22-M wipe. " ); + mvwprintw( main_window, 7, tab2, " " ); + mvwprintw( main_window, 8, tab2, "Pass 1: A random character " ); + mvwprintw( main_window, 9, tab2, "Pass 2: The bitwise complement of pass 1. " ); + mvwprintw( main_window, 10, tab2, "Pass 3: A random number generated data stream " ); + break; + + case 4: + + mvwprintw( main_window, 2, tab2, "Security Level: higher (7 passes)" ); + + mvwprintw( main_window, 3, tab2, "The American Department of Defense 5220.22-M " ); + mvwprintw( main_window, 4, tab2, "standard wipe. " ); + mvwprintw( main_window, 5, tab2, " " ); + mvwprintw( main_window, 6, tab2, "Pass 1: A Random character " ); + mvwprintw( main_window, 7, tab2, "Pass 2: The bitwise complement of pass 1 " ); + mvwprintw( main_window, 8, tab2, "Pass 3: A random number generated data stream " ); + mvwprintw( main_window, 9, tab2, "Pass 4: A Random character " ); + mvwprintw( main_window, 10, tab2, "Pass 5: A Random character " ); + mvwprintw( main_window, 11, tab2, "Pass 6: The bitwise complement of pass 5 " ); + mvwprintw( main_window, 12, tab2, "Pass 7: A random number generated data stream " ); + break; + + case 5: + + mvwprintw( main_window, 2, tab2, "Security Level: Paranoid ! (35 passes) " ); + mvwprintw( main_window, 3, tab2, "Don't waste your time with this on a modern drive" ); + + mvwprintw( main_window, 5, tab2, "This is the method described by Peter Gutmann in " ); + mvwprintw( main_window, 6, tab2, "the paper entitled \"Secure Deletion of Data from" ); + mvwprintw( main_window, 7, tab2, "Magnetic and Solid-State Memory\", however not " ); + mvwprintw( main_window, 8, tab2, "relevant in regards to modern hard disk drives. " ); + break; + + case 6: + + mvwprintw( main_window, 2, tab2, "Security Level: Depends on Rounds" ); + + mvwprintw( main_window, 4, tab2, "This method fills the device with a stream from " ); + mvwprintw( main_window, 5, tab2, "the PRNG. It is probably the best method to use " ); + mvwprintw( main_window, 6, tab2, "on modern hard disk drives due to variation in " ); + mvwprintw( main_window, 7, tab2, "encoding methods. " ); + mvwprintw( main_window, 8, tab2, " " ); + mvwprintw( main_window, 9, tab2, "This method has a high security level with 1 " ); + mvwprintw( main_window, 10, tab2, "round and an increasingly higher security level " ); + mvwprintw( main_window, 11, tab2, "as rounds are increased." ); + break; + + case 7: + + mvwprintw( main_window, 2, tab2, "Security Level: Not applicable" ); + + mvwprintw( main_window, 4, tab2, "This method only reads the device and checks " ); + mvwprintw( main_window, 5, tab2, "that it is all zero. " ); + + break; + + case 8: + + mvwprintw( main_window, 2, tab2, "Security Level: Not applicable" ); + + mvwprintw( main_window, 4, tab2, "This method only reads the device and checks " ); + mvwprintw( main_window, 5, tab2, "that it is all ones (0xFF)." ); + + break; + + case 9: + + mvwprintw( main_window, 2, tab2, "Security Level: higher (3 passes)" ); + + mvwprintw( main_window, 4, tab2, "HMG IA/IS 5 (Infosec Standard 5): Secure " ); + mvwprintw( main_window, 5, tab2, "Sanitisation of Protectively Marked Information " ); + mvwprintw( main_window, 6, tab2, "or Sensitive Information " ); + mvwprintw( main_window, 7, tab2, " " ); + mvwprintw( main_window, 8, tab2, "This method fills the device with 0s, then with " ); + mvwprintw( main_window, 9, tab2, "1s, then with a PRNG stream, then reads the " ); + mvwprintw( main_window, 10, tab2, "device to verify the PRNG stream was " ); + mvwprintw( main_window, 11, tab2, "successfully written. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Wipe Method " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && terminate_signal != 1 ); + + switch( focus ) + { + case 0: + nwipe_options.method = &nwipe_zero; + break; + + case 1: + nwipe_options.method = &nwipe_one; + break; + + case 2: + nwipe_options.method = &nwipe_ops2; + break; + + case 3: + nwipe_options.method = &nwipe_dodshort; + break; + + case 4: + nwipe_options.method = &nwipe_dod522022m; + break; + + case 5: + nwipe_options.method = &nwipe_gutmann; + break; + + case 6: + nwipe_options.method = &nwipe_random; + break; + + case 7: + nwipe_options.method = &nwipe_verify_zero; + break; + + case 8: + nwipe_options.method = &nwipe_verify_one; + break; + + case 9: + nwipe_options.method = &nwipe_is5enh; + break; + } + +} /* nwipe_gui_method */ + +void nwipe_gui_config( void ) +{ + /** + * Display the configuration Main Menu selection window + * + */ + + extern int terminate_signal; + + /* Number of entries in the configuration menu. */ + const int count = 8; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 40; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_config ); + wrefresh( footer_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_config ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Enable/Disable " ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Edit Organisation" ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Select Customer " ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Add Customer " ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Delete Customer " ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Preview Details " ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Preview at Start " ); + yy++; + mvwprintw( main_window, yy++, tab1, " %s", "Set System Date & Time " ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + if( nwipe_options.PDF_enable ) + { + mvwprintw( main_window, 2, tab2, "PDF Report = ENABLED" ); + } + else + { + mvwprintw( main_window, 2, tab2, "PDF Report = DISABLED" ); + } + + mvwprintw( main_window, 4, tab2, "Enable or Disable creation of the PDF " ); + mvwprintw( main_window, 5, tab2, "report/certificate " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "PDF Report - Edit Organisation" ); + + mvwprintw( main_window, 4, tab2, "This option allows you to edit details" ); + mvwprintw( main_window, 5, tab2, "of the organisation that is performing" ); + mvwprintw( main_window, 6, tab2, "the erasure. This includes: business " ); + mvwprintw( main_window, 7, tab2, "name, business address, contact name " ); + mvwprintw( main_window, 8, tab2, "and contact phone. " ); + break; + + case 2: + mvwprintw( main_window, 2, tab2, "PDF Report - Select Customer" ); + + mvwprintw( main_window, 4, tab2, "Allows selection of a customer as " ); + mvwprintw( main_window, 5, tab2, "displayed on the PDF report. Customer " ); + mvwprintw( main_window, 6, tab2, "information includes Name (This can be" ); + mvwprintw( main_window, 7, tab2, "a personal or business name), address " ); + mvwprintw( main_window, 8, tab2, "contact name and contact phone. " ); + mvwprintw( main_window, 9, tab2, " " ); + mvwprintw( main_window, 10, tab2, "Customer data is located in: " ); + mvwprintw( main_window, 11, tab2, "/etc/nwipe/nwipe_customers.csv " ); + break; + + case 3: + + mvwprintw( main_window, 2, tab2, "PDF Report - Add Customer " ); + + mvwprintw( main_window, 4, tab2, "This option allows you to add a new " ); + mvwprintw( main_window, 5, tab2, "customer. A customer can be optionally" ); + mvwprintw( main_window, 6, tab2, "displayed on the PDF report. Customer " ); + mvwprintw( main_window, 7, tab2, "information includes Name (This can be" ); + mvwprintw( main_window, 8, tab2, "a personal or business name), address " ); + mvwprintw( main_window, 9, tab2, "contact name and contact phone. " ); + mvwprintw( main_window, 10, tab2, " " ); + mvwprintw( main_window, 11, tab2, "Customer data is saved in: " ); + mvwprintw( main_window, 12, tab2, "/etc/nwipe/nwipe_customers.csv " ); + break; + + case 4: + + mvwprintw( main_window, 2, tab2, "PDF Report - Delete Customer " ); + + mvwprintw( main_window, 4, tab2, "This option allows you to delete a " ); + mvwprintw( main_window, 5, tab2, "customer. A customer can be optionally" ); + mvwprintw( main_window, 6, tab2, "displayed on the PDF report. Customer " ); + mvwprintw( main_window, 7, tab2, "information includes Name (This can be" ); + mvwprintw( main_window, 8, tab2, "a personal or business name), address " ); + mvwprintw( main_window, 9, tab2, "contact name and contact phone. " ); + mvwprintw( main_window, 10, tab2, " " ); + mvwprintw( main_window, 11, tab2, "Customer data is saved in: " ); + mvwprintw( main_window, 12, tab2, "/etc/nwipe/nwipe_customers.csv " ); + break; + + case 5: + + mvwprintw( main_window, 2, tab2, "PDF Report - Preview Organisation, " ); + mvwprintw( main_window, 3, tab2, "Customer and Date/Time details " ); + + mvwprintw( main_window, 5, tab2, "This allows the above information to " ); + mvwprintw( main_window, 6, tab2, "be checked prior to starting the wipe " ); + mvwprintw( main_window, 7, tab2, "so that the information is correct on " ); + mvwprintw( main_window, 8, tab2, "the pdf report. " ); + break; + + case 6: + + if( nwipe_options.PDF_preview_details ) + { + mvwprintw( main_window, 2, tab2, "Preview Org. & Customer at start = ENABLED" ); + } + else + { + mvwprintw( main_window, 2, tab2, "Preview Org. & Customer at start = DISABLED" ); + } + mvwprintw( main_window, 4, tab2, "A preview prior to the drive selection" ); + mvwprintw( main_window, 5, tab2, "of the organisation that is performing" ); + mvwprintw( main_window, 6, tab2, "the wipe, the customer details and the" ); + mvwprintw( main_window, 7, tab2, "current date and time in order to " ); + mvwprintw( main_window, 8, tab2, "confirm that the information is " ); + mvwprintw( main_window, 9, tab2, "correct on the pdf report prior to " ); + mvwprintw( main_window, 10, tab2, "drive selection and starting the erase" ); + break; + + case 8: + + mvwprintw( main_window, 2, tab2, "Set System Date & Time " ); + + mvwprintw( main_window, 4, tab2, "Useful when host is not connected to " ); + mvwprintw( main_window, 5, tab2, "the internet and not running the 'ntp'" ); + mvwprintw( main_window, 6, tab2, "(network time protocol). " ); + break; + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Configuration " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + if( focus == 6 ) + { + focus += 2; /* mind the gaps */ + } + else + { + focus += 1; + } + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + if( focus == 8 ) + { + focus -= 2; /* mind the gaps */ + } + else + { + focus -= 1; + } + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + case 27: /* ESC */ + + return; + + } /* switch */ + + if( keystroke == 0x0A ) + { + switch( focus ) + { + case 0: + /* Toggle on pressing ENTER key */ + if( nwipe_options.PDF_enable == 0 ) + { + nwipe_options.PDF_enable = 1; + + /* write the setting to nwipe.conf */ + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "ENABLED" ); + } + else + { + nwipe_options.PDF_enable = 0; + + /* write the setting to nwipe.conf */ + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "DISABLED" ); + } + break; + + case 1: + nwipe_gui_edit_organisation(); + break; + + case 2: + customer_processes( SELECT_CUSTOMER ); + + break; + + case 3: + nwipe_gui_add_customer(); + break; + + case 4: + customer_processes( DELETE_CUSTOMER ); + break; + + case 5: + nwipe_gui_preview_org_customer( SHOWING_IN_CONFIG_MENUS ); + break; + + case 6: + /* Toggle on pressing ENTER key */ + if( nwipe_options.PDF_preview_details == 0 ) + { + nwipe_options.PDF_preview_details = 1; + + /* write the setting to nwipe.conf */ + nwipe_conf_update_setting( "PDF_Certificate.PDF_Preview", "ENABLED" ); + } + else + { + nwipe_options.PDF_preview_details = 0; + + /* write the setting to nwipe.conf */ + nwipe_conf_update_setting( "PDF_Certificate.PDF_Preview", "DISABLED" ); + } + break; + + case 8: + nwipe_gui_set_date_time(); + break; + } + keystroke = -1; + } + + } while( keystroke != KEY_ENTER && /* keystroke != ' ' && */ keystroke != 10 && terminate_signal != 1 ); + +} /* end of nwipe_config() */ + +void nwipe_gui_edit_organisation( void ) +{ + /** + * Display the list of organisation details available for editing + * + */ + + extern int terminate_signal; + + /* Number of entries in the configuration menu. */ + const int count = 5; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 27; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* variables used by libconfig for extracting data from nwipe.conf */ + config_setting_t* setting; + const char *business_name, *business_address, *contact_name, *contact_phone, *op_tech_name; + extern config_t nwipe_cfg; + + do + { + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_config ); + wrefresh( footer_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_config ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", "Edit Business Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Edit Business Address" ); + mvwprintw( main_window, yy++, tab1, " %s", "Edit Contact Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Edit Contact Phone" ); + mvwprintw( main_window, yy++, tab1, " %s", "Edit Tech/Operator" ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + setting = config_lookup( &nwipe_cfg, "Organisation_Details" ); + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Business_Name", &business_name ) ) + { + mvwprintw( main_window, 2, tab2, ": %s", business_name ); + } + else + { + mvwprintw( main_window, 2, tab2, ": Cannot retrieve business_name, nwipe.conf" ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Business_Address", &business_address ) ) + { + mvwprintw( main_window, 3, tab2, ": %s", business_address ); + } + else + { + mvwprintw( main_window, 3, tab2, ": Cannot retrieve business address, nwipe.conf" ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Name", &contact_name ) ) + { + mvwprintw( main_window, 4, tab2, ": %s", contact_name ); + } + else + { + mvwprintw( main_window, 4, tab2, ": Cannot retrieve contact name, nwipe.conf" ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Phone", &contact_phone ) ) + { + mvwprintw( main_window, 5, tab2, ": %s", contact_phone ); + } + else + { + mvwprintw( main_window, 5, tab2, ": Cannot retrieve contact phone, nwipe.conf" ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Op_Tech_Name", &op_tech_name ) ) + { + mvwprintw( main_window, 6, tab2, ": %s", op_tech_name ); + } + else + { + mvwprintw( main_window, 6, tab2, ": Cannot retrieve op_tech_name, nwipe.conf" ); + } + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " PDF Report - Edit Organisation " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + case 27: /* ESC */ + + return; + + } /* switch */ + + } while( keystroke != KEY_ENTER && keystroke != 10 && terminate_signal != 1 ); + + if( keystroke == KEY_ENTER || keystroke == 10 || keystroke == ' ' ) + { + switch( focus ) + { + case 0: + nwipe_gui_organisation_business_name( business_name ); + keystroke = 0; + break; + + case 1: + nwipe_gui_organisation_business_address( business_address ); + keystroke = 0; + break; + + case 2: + nwipe_gui_organisation_contact_name( contact_name ); + keystroke = 0; + break; + + case 3: + nwipe_gui_organisation_contact_phone( contact_phone ); + keystroke = 0; + break; + + case 4: + nwipe_gui_organisation_op_tech_name( op_tech_name ); + keystroke = 0; + break; + } + } + + } while( keystroke != KEY_ENTER && keystroke != 10 && terminate_signal != 1 ); + +} /* end of nwipe_gui_edit_organisation( void ) */ + +void nwipe_gui_organisation_business_name( const char* business_name ) +{ + /** + * Allows the user to change the organisation business name as displayed on the PDF report. + * + * @modifies business_name in nwipe.conf + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer */ + char buffer[256] = ""; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + /* variables used by libconfig for inserting data into nwipe.conf */ + config_setting_t* setting; + // const char* business_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Copy the current business name to the buffer */ + strcpy( buffer, business_name ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Edit Organisation Business Name " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the business name of the organisation performing the erasure" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < 255 ) + { + buffer[idx++] = keystroke; + buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + if( !( setting = config_lookup( &nwipe_cfg, "Organisation_Details.Business_Name" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to locate [Organisation_Details.Business_Name] in %s", nwipe_config_file ); + } + + /* libconfig: Write the new business name */ + if( config_setting_set_string( setting, buffer ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Failed to write [%s] to [Organisation_Details.Business_Name] in %s", + buffer, + nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( config_write_file( &nwipe_cfg, nwipe_config_file ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write organisation business name to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "[Success] Business name written to %s", nwipe_config_file ); + } + +} /* End of nwipe_gui_organisation_business_name() */ + +void nwipe_gui_organisation_business_address( const char* business_address ) +{ + /** + * Allows the user to change the organisation business address as displayed on the PDF report. + * + * @modifies business_address in nwipe.conf + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer */ + char buffer[256] = ""; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + /* variables used by libconfig for inserting data into nwipe.conf */ + config_setting_t* setting; + // const char* business_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Copy the current business address to the buffer */ + strcpy( buffer, business_address ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Edit Organisation Business Address " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the business address of the organisation performing the erasure" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < 255 ) + { + buffer[idx++] = keystroke; + buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + if( !( setting = config_lookup( &nwipe_cfg, "Organisation_Details.Business_Address" ) ) ) + { + nwipe_log( + NWIPE_LOG_ERROR, "Failed to locate [Organisation_Details.Business_Address] in %s", nwipe_config_file ); + } + + /* libconfig: Write the new business name */ + if( config_setting_set_string( setting, buffer ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Failed to write [%s] to [Organisation_Details.Business_Address] in %s", + buffer, + nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( config_write_file( &nwipe_cfg, nwipe_config_file ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write organisation business address to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "[Success] Business address written to %s", nwipe_config_file ); + } + +} /* End of nwipe_gui_organisation_business_address() */ + +void nwipe_gui_organisation_contact_name( const char* contact_name ) +{ + /** + * Allows the user to change the organisation business address as displayed on the PDF report. + * + * @modifies business_address in nwipe.conf + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer */ + char buffer[256] = ""; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + /* variables used by libconfig for inserting data into nwipe.conf */ + config_setting_t* setting; + // const char* business_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Copy the current business address to the buffer */ + strcpy( buffer, contact_name ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Edit Organisation Contact Name " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the contact name for the organisation performing the erasure" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < 255 ) + { + buffer[idx++] = keystroke; + buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + if( !( setting = config_lookup( &nwipe_cfg, "Organisation_Details.Contact_Name" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to locate [Organisation_Details.Contact_Name] in %s", nwipe_config_file ); + } + + /* libconfig: Write the new organisation contact name */ + if( config_setting_set_string( setting, buffer ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Failed to write [%s] to [Organisation_Details.Contact_Name] in %s", + buffer, + nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( config_write_file( &nwipe_cfg, nwipe_config_file ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write organisation contact name to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "[Success] Business contact name written to %s", nwipe_config_file ); + } + +} /* End of nwipe_gui_organisation_contact_name() */ + +void nwipe_gui_organisation_contact_phone( const char* contact_phone ) +{ + /** + * Allows the user to change the organisation contact name as displayed on the PDF report. + * + * @modifies organisation contact name in nwipe.conf + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer */ + char buffer[256] = ""; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + /* variables used by libconfig for inserting data into nwipe.conf */ + config_setting_t* setting; + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Copy the current business address to the buffer */ + strcpy( buffer, contact_phone ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Edit Organisation Contact Phone " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the contact phone for the organisation performing the erasure" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < 255 ) + { + buffer[idx++] = keystroke; + buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + if( !( setting = config_lookup( &nwipe_cfg, "Organisation_Details.Contact_Phone" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to locate [Organisation_Details.Contact_Phone] in %s", nwipe_config_file ); + } + + /* libconfig: Write the organistion contact phone */ + if( config_setting_set_string( setting, buffer ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Failed to write [%s] to [Organisation_Details.Contact_Phone] in %s", + buffer, + nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( config_write_file( &nwipe_cfg, nwipe_config_file ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write organisation contact phone to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "[Success] Business contact phone written to %s", nwipe_config_file ); + } + +} /* End of nwipe_gui_organisation_contact_phone() */ + +void nwipe_gui_organisation_op_tech_name( const char* op_tech_name ) +{ + /** + * Allows the user to change the organisation contact name as displayed on the PDF report. + * + * @modifies organisation contact name in nwipe.conf + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer */ + char buffer[256] = ""; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + /* variables used by libconfig for inserting data into nwipe.conf */ + config_setting_t* setting; + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Copy the current op_tech_name to the buffer */ + strcpy( buffer, op_tech_name ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Edit Operator/Technician Name " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the operator/technician's name that is performing the erasure" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < 255 ) + { + buffer[idx++] = keystroke; + buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* libconfig: Locate the Organisation Details section in nwipe.conf */ + if( !( setting = config_lookup( &nwipe_cfg, "Organisation_Details.Op_Tech_Name" ) ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to locate [Organisation_Details.Op_Tech_Name] in %s", nwipe_config_file ); + } + + /* libconfig: Write the organistion operator/technician name */ + if( config_setting_set_string( setting, buffer ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Failed to write [%s] to [Organisation_Details.Op_Tech_Name] in %s", + buffer, + nwipe_config_file ); + } + + /* Write out the new configuration. */ + if( config_write_file( &nwipe_cfg, nwipe_config_file ) == CONFIG_FALSE ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write organisation operator/technician to %s", nwipe_config_file ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "[Success] operator/technician name written to %s", nwipe_config_file ); + } + +} /* End of nwipe_gui_organisation_op_tech_name() */ + +void nwipe_gui_list( int count, char* window_title, char** list, int* selected_entry ) +{ + /** + * Displays a selectable list in a window, return 1 -n in selected entry. + * If selected entry = 0, then user cancelled selection. + */ + + extern int terminate_signal; + + /* The number of lines available in the window. */ + int wlines; + + /* The number of columns available in the window. */ + int wcols; + + /* The number of selection elements that we can show in the window. */ + int slots; + + /* The index of the element that is visible in the first slot. */ + int offset = 0; + + /* The selection focus. */ + int focus = 0; + + /* A generic loop variable. */ + int i = 0; + + /* User input buffer. */ + int keystroke; + + /* The current working line. */ + int yy; + + /* Flag, Valid key hit = 1, anything else = 0 */ + int validkeyhit; + + /* Processed customer entry as displayed in selection dialog */ + char* display_line; + + /* Get the terminal size */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Save the terminal size so we check whether the user has resized */ + stdscr_lines_previous = stdscr_lines; + stdscr_cols_previous = stdscr_cols; + + /* Used to refresh the window every second */ + time_t check_time = time( NULL ); + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int iteration_counter; + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int expected_iterations; + + /* General Indexes */ + int idx, idx2; + + time_t previous_iteration_timestamp; + + do + { + + nwipe_gui_create_all_windows_on_terminal_resize( 0, main_window_footer ); + + /* There is one slot per line. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less two lines for the box and two lines for padding. */ + slots = wlines - 4; + if( slots < 0 ) + { + slots = 0; + } + + /* The code here adjusts the offset value, required when the terminal is resized vertically */ + if( slots > count ) + { + offset = 0; + } + else + { + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + } + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + } + } + + if( count >= slots && slots > 0 ) + { + offset = focus + 1 - slots; + if( offset < 0 ) + { + offset = 0; + } + } + + /* Clear the main window, necessary when switching selections such as method etc */ + werase( main_window ); + + /* Refresh main window */ + wnoutrefresh( main_window ); + + /* Set footer help text */ + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + /* Refresh the stats window */ + wnoutrefresh( stats_window ); + + /* Refresh the options window */ + wnoutrefresh( options_window ); + + /* Update the options window. */ + nwipe_gui_options(); + + /* Initialize the line offset. */ + yy = 2; + + for( i = 0; i < slots && i < count; i++ ) + { + /* Move to the next line. */ + mvwprintw( main_window, yy++, 1, " " ); + + if( i + offset == focus ) + { + /* Print the 'enabled' cursor. */ + waddch( main_window, ACS_RARROW ); + } + + else + { + /* Print whitespace. */ + waddch( main_window, ' ' ); + } + + /* In the event for the offset value somehow becoming invalid, this if statement will prevent a segfault + * and the else part will log the out of bounds values for debugging */ + if( i + offset >= 0 && i + offset < count ) + { + /* print a entry from the list, we need to process the string before display, + * removing the double quotes that are used in csv for identifying the start & end of a field. + */ + if( ( display_line = calloc( sizeof( char ), strlen( list[i + offset] ) ) ) ) + { + idx = 0; + idx2 = 0; + while( list[i + offset][idx] != 0 ) + { + if( list[i + offset][idx] == '"' ) + { + idx++; + } + else + { + display_line[idx2++] = list[i + offset][idx++]; + } + } + display_line[idx2] = 0; + wprintw( main_window, "%s ", display_line ); + free( display_line ); + } + } + else + { + nwipe_log( NWIPE_LOG_DEBUG, + "GUI.c,nwipe_gui_select(), scroll, array index out of bounds, i=%u, count=%u, slots=%u, " + "focus=%u, offset=%u", + i, + count, + slots, + focus, + offset ); + } + + } /* for */ + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols - 8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines - 2, wcols - 8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + /* Draw a border around the menu window. */ + box( main_window, 0, 0 ); + + /* Print a title. */ + nwipe_gui_title( main_window, window_title ); + + /* Refresh the window. */ + wnoutrefresh( main_window ); + + /* Output to physical screen */ + doupdate(); + + /* Initialise the iteration counter */ + iteration_counter = 0; + + previous_iteration_timestamp = time( NULL ); + + /* Calculate Maximum allowed iterations per second */ + expected_iterations = ( 1000 / GETCH_BLOCK_MS ) * 8; + + do + { + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + + validkeyhit = 0; + timeout( GETCH_BLOCK_MS ); // block getch() for ideally about 250ms. + keystroke = getch(); // Get user input. + timeout( -1 ); // Switch back to blocking mode. + + /* To avoid 100% CPU usage, check for a runaway condition caused by the "keystroke = getch(); (above), from + * immediately returning an error condition. We check for an error condition because getch() returns a ERR + * value when the timeout value "timeout( 250 );" expires as well as when a real error occurs. We can't + * differentiate from normal operation and a failure of the getch function to block for the specified period + * of timeout. So here we check the while loop hasn't exceeded the number of expected iterations per second + * ie. a timeout(250) block value of 250ms means we should not see any more than (1000/250) = 4 iterations. + * We increase this to 32 iterations to allow a little tolerance. Why is this necessary? It's been found + * that in KDE konsole and other terminals based on the QT terminal engine exiting the terminal without + * first exiting nwipe results in nwipe remaining running but detached from any interface which causes + * getch to fail and its associated timeout. So the CPU or CPU core rises to 100%. Here we detect that + * failure and exit nwipe gracefully with the appropriate error. This does not affect use of tmux for + * attaching or detaching from a running nwipe session when sitting at the selection screen. All other + * terminals correctly terminate nwipe when the terminal itself is exited. + */ + + iteration_counter++; + + if( previous_iteration_timestamp == time( NULL ) ) + { + if( iteration_counter > expected_iterations ) + { + nwipe_log( NWIPE_LOG_ERROR, + "GUI.c,nwipe_gui_select(), loop runaway, did you close the terminal without exiting " + "nwipe? Exiting nwipe now." ); + /* Issue signal to nwipe to exit immediately but gracefully */ + terminate_signal = 1; + } + } + else + { + /* new second, so reset counter */ + iteration_counter = 0; + previous_iteration_timestamp = time( NULL ); + } + + /* We don't necessarily use all of these. For future reference these are some CTRL+key values + * ^A - 1, ^B - 2, ^D - 4, ^E - 5, ^F - 6, ^G - 7, ^H - 8, ^I - 9, ^K - 11, ^L - 12, ^N - 14, + * ^O - 15, ^P - 16, ^R - 18, ^T - 20, ^U - 21, ^V - 22, ^W - 23, ^X - 24, ^Y - 25 + * Use nwipe_log( NWIPE_LOG_DEBUG, "Key Name: %s - %u", keyname(keystroke),keystroke) to + * figure out what code is returned by what ever key combination */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + validkeyhit = 1; + + /* Increment the focus. */ + focus += 1; + + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + break; + } + + if( focus - offset >= slots ) + { + /* The next element is offscreen. Scroll down. */ + offset += 1; + break; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + validkeyhit = 1; + + /* Decrement the focus. */ + focus -= 1; + + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + break; + } + + if( focus < offset ) + { + /* The next element is offscreen. Scroll up. */ + offset -= 1; + break; + } + + break; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + *selected_entry = 0; + return; + break; + + case KEY_ENTER: + case 10: + case ' ': + + validkeyhit = 1; + + /* Return the index of the selected item in the list. Values start at 1 not zero */ + *selected_entry = focus + 1; + return; + + break; + + } /* keystroke switch */ + + /* Check the terminal size, if the user has changed it the while loop checks for + * this change and exits the valid key hit loop so the windows can be updated */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Update the selection window every 1 second specifically + * so that the drive temperatures are updated and also the line toggle that + * occurs with the HPA status and the drive size & temperature. + */ + if( time( NULL ) > ( check_time + 1 ) ) + { + check_time = time( NULL ); + validkeyhit = 1; + } + + } /* key hit loop */ + while( validkeyhit == 0 && terminate_signal != 1 && stdscr_cols_previous == stdscr_cols + && stdscr_lines_previous == stdscr_lines ); + + } while( terminate_signal != 1 ); + +} /* nwipe_gui_list */ + +void nwipe_gui_add_customer( void ) +{ + /** + * Add new customer top level menu + * + */ + + extern int terminate_signal; + + /* Number of entries in the configuration menu. */ + const int count = 4; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 27; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + char customer_name[FIELD_LENGTH] = ""; + char customer_address[FIELD_LENGTH] = ""; + char customer_contact_name[FIELD_LENGTH] = ""; + char customer_contact_phone[FIELD_LENGTH] = ""; + + /* 0 = NO = don't save, 1 = YES = save customer */ + int save = NO; + + /* 0 = Display standard dialog footer, 1 = YES = display "Save Y/N" footer */ + int yes_no = NO; + + /* variables used by libconfig for extracting data from nwipe.conf */ + config_setting_t* setting; + // const char *business_name, *business_address, *contact_name, *contact_phone, *op_tech_name; + extern config_t nwipe_cfg; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_config ); + wrefresh( footer_window ); + + do + { + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Change footer based on whether we are waiting for a Y/N response */ + if( yes_no == YES ) + { + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_add_customer_yes_no ); + wrefresh( footer_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_add_customer_yes_no ); + } + else + { + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_config ); + wrefresh( footer_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_config ); + } + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s : %s", "Add Customer Name ", customer_name ); + mvwprintw( main_window, yy++, tab1, " %s : %s", "Add Customer Address ", customer_address ); + mvwprintw( main_window, yy++, tab1, " %s : %s", "Add Customer Contact Name ", customer_contact_name ); + mvwprintw( main_window, yy++, tab1, " %s : %s", "Add Customer Contact Phone", customer_contact_phone ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " PDF Report - Add New Customer " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + if( yes_no == NO ) + { + switch( keystroke ) + { + // Save customer + case 's': + case 'S': + break; + + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + focus += 1; + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + focus -= 1; + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + case 27: /* ESC */ + + /* If the user has entered any text then ask if the customer entries should be saved */ + if( customer_name[0] != 0 || customer_address[0] != 0 || customer_contact_name[0] != 0 + || customer_contact_phone[0] != 0 ) + { + /* Set the footer yes/no flag */ + yes_no = YES; + } + else + { + return; + } + break; + + } /* switch */ + } + else + { + /* Waiting for a Y/N response */ + switch( keystroke ) + { + case 'y': + case 'Y': + save = 1; + break; + + case 'n': + case 'N': + return; + break; + } + } + + } while( save != YES && keystroke != 's' && keystroke != KEY_ENTER && keystroke != 10 + && terminate_signal != 1 ); + + if( keystroke == KEY_ENTER || keystroke == 10 ) + { + switch( focus ) + { + case 0: + nwipe_gui_add_customer_name( customer_name ); + keystroke = 0; + break; + + case 1: + nwipe_gui_add_customer_address( customer_address ); + keystroke = 0; + break; + + case 2: + nwipe_gui_add_customer_contact_name( customer_contact_name ); + keystroke = 0; + break; + + case 3: + nwipe_gui_add_customer_contact_phone( customer_contact_phone ); + keystroke = 0; + break; + } + } + + } while( save != YES && keystroke != 's' && keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 + && terminate_signal != 1 ); + + /* If save set, or user pressed s or S then save the customer details */ + if( keystroke == 's' || keystroke == 'S' || save == 1 ) + { + write_customer_csv_entry( customer_name, customer_address, customer_contact_name, customer_contact_phone ); + } + +} /* end of nwipe_gui_add_customer( void ) */ + +void nwipe_gui_add_customer_name( char* customer_name ) +{ + /** + * Allows the user to change the customer's contact name as displayed on the PDF report. + * + * @modifies customer's contact name + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( customer_name ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Add New Customer Name " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the customer's name (business or personal name)" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", customer_name ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + customer_name[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH ) + { + customer_name[idx++] = keystroke; + customer_name[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", customer_name ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + +} /* End of nwipe_gui_add_customer_name() */ + +void nwipe_gui_add_customer_address( char* customer_address ) +{ + /** + * Allows the user to change the customer's address as displayed on the PDF report. + * + * @modifies customer's address + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( customer_address ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Add New Customer Address " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the customer's address" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", customer_address ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + customer_address[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH ) + { + customer_address[idx++] = keystroke; + customer_address[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", customer_address ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + +} /* End of nwipe_gui_add_customer_address() */ + +void nwipe_gui_add_customer_contact_name( char* customer_contact_name ) +{ + /** + * Allows the user to change the customer contact name as displayed on the PDF report. + * + * @modifies customer's contact name + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( customer_contact_name ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Add New Customer Contact Name " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the customer's contact name" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", customer_contact_name ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + customer_contact_name[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH ) + { + customer_contact_name[idx++] = keystroke; + customer_contact_name[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", customer_contact_name ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + +} /* End of nwipe_gui_add_customer_contact_name() */ + +void nwipe_gui_add_customer_contact_phone( char* customer_contact_phone ) +{ + /** + * Allows the user to change the customer contact phone as displayed on the PDF report. + * + * @modifies customer's contact phone + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* buffer index */ + int idx = 0; + + extern int terminate_signal; + + // const char* contact_name; + extern config_t nwipe_cfg; + extern char nwipe_config_file[]; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( customer_contact_phone ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Add New Customer Contact Phone " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the customer's contact phone" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", customer_contact_phone ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + customer_contact_phone[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH ) + { + customer_contact_phone[idx++] = keystroke; + customer_contact_phone[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", customer_contact_phone ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + +} /* End of nwipe_gui_add_customer_contact_phone() */ + +void nwipe_gui_preview_org_customer( int mode ) +{ + /** + * Display the organisation and customers details and the current system date and time + * + */ + + extern int terminate_signal; + + /* Number of entries in the configuration menu. */ + const int count = 12; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 27; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + time_t t; + + char output_str[FIELD_LENGTH]; + + /* Window dimensions */ + int wlines; + int wcols; + + /* variables used by libconfig for extracting data from nwipe.conf */ + config_setting_t* setting; + const char *business_name, *business_address, *contact_name, *contact_phone, *op_tech_name; + const char *customer_name, *customer_address, *customer_contact_name, *customer_contact_phone; + extern config_t nwipe_cfg; + + do + { + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Update the footer window. */ + werase( footer_window ); + if( mode == SHOWING_IN_CONFIG_MENUS ) + { + nwipe_gui_title( footer_window, selection_footer ); + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer ); + } + else + { + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_preview_prior_to_drive_selection ); + nwipe_gui_title( footer_window, selection_footer_preview_prior_to_drive_selection ); + } + wrefresh( footer_window ); + + /* Determine size of window */ + getmaxyx( main_window, wlines, wcols ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", "Business Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Business Address" ); + mvwprintw( main_window, yy++, tab1, " %s", "Contact Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Contact Phone" ); + mvwprintw( main_window, yy++, tab1, " %s", "Tech/Operator" ); + yy++; + mvwprintw( main_window, yy++, tab1, " %s", "Customer Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Customer Address" ); + mvwprintw( main_window, yy++, tab1, " %s", "Customer Contact Name" ); + mvwprintw( main_window, yy++, tab1, " %s", "Customer Contact Phone" ); + yy++; + mvwprintw( main_window, yy++, tab1, " %s", "System Date/Time" ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + /****************************************************************** + * libconfig: Locate the Organisation Details section in nwipe.conf + */ + + setting = config_lookup( &nwipe_cfg, "Organisation_Details" ); + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Business_Name", &business_name ) ) + { + str_truncate( wcols, tab2, business_name, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 2, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve business_name, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 2, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Business_Address", &business_address ) ) + { + str_truncate( wcols, tab2, business_address, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 3, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve business address, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 3, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Name", &contact_name ) ) + { + str_truncate( wcols, tab2, contact_name, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 4, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve contact name, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 4, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Phone", &contact_phone ) ) + { + str_truncate( wcols, tab2, contact_phone, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 5, tab2, ": %s", output_str ); + } + else + { + str_truncate( + wcols, tab2, "Cannot retrieve customer contact phone, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 5, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Op_Tech_Name", &op_tech_name ) ) + { + str_truncate( wcols, tab2, op_tech_name, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 6, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve op_tech_name, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 6, tab2, ": %s", output_str ); + } + + /********************************************************************** + * libconfig: Locate the current customer details section in nwipe.conf + */ + setting = config_lookup( &nwipe_cfg, "Selected_Customer" ); + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Customer_Name", &customer_name ) ) + { + str_truncate( wcols, tab2, customer_name, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 8, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve Customer_Name, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 8, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Customer_Address", &customer_address ) ) + { + str_truncate( wcols, tab2, customer_address, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 9, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve customer address, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 9, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Name", &contact_name ) ) + { + str_truncate( wcols, tab2, contact_name, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 10, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve contact name, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 10, tab2, ": %s", output_str ); + } + + /* Retrieve data from nwipe.conf */ + if( config_setting_lookup_string( setting, "Contact_Phone", &contact_phone ) ) + { + str_truncate( wcols, tab2, contact_phone, output_str, FIELD_LENGTH ); + mvwprintw( main_window, 11, tab2, ": %s", output_str ); + } + else + { + str_truncate( wcols, tab2, "Cannot retrieve contact phone, nwipe.conf", output_str, FIELD_LENGTH ); + mvwprintw( main_window, 11, tab2, ": %s", output_str ); + } + + /******************************* + * Retrieve system date and time + */ + time( &t ); + mvwprintw( main_window, 13, tab2, ": %s", ctime( &t ) ); + + /* ************ + * Add a border + */ + box( main_window, 0, 0 ); + + /************* + * Add a title + */ + nwipe_gui_title( main_window, " PDF Report - Preview Organisation, customer and date/time " ); + + /******************** + * Refresh the window + */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + if( focus == 4 || focus == 9 ) + { + focus += 2; /* mind the gaps */ + } + else + { + focus += 1; + } + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + if( focus == 6 || focus == 11 ) + { + focus -= 2; /* mind the gaps */ + } + else + { + focus -= 1; + } + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + case 27: /* ESC */ + + return; + break; + + case 'A': + case 'a': + if( mode == SHOWING_PRIOR_TO_DRIVE_SELECTION ) + { + return; + } + + } /* switch */ + + } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && terminate_signal != 1 ); + + if( keystroke == KEY_ENTER || keystroke == 10 || keystroke == ' ' ) + { + switch( focus ) + { + case 0: + nwipe_gui_organisation_business_name( business_name ); + keystroke = 0; + break; + + case 1: + nwipe_gui_organisation_business_address( business_address ); + keystroke = 0; + break; + + case 2: + nwipe_gui_organisation_contact_name( contact_name ); + keystroke = 0; + break; + + case 3: + nwipe_gui_organisation_contact_phone( contact_phone ); + keystroke = 0; + break; + + case 4: + nwipe_gui_organisation_op_tech_name( op_tech_name ); + keystroke = 0; + break; + + case 6: + case 7: + case 8: + case 9: + nwipe_gui_config(); + break; + + case 11: + nwipe_gui_set_date_time(); + } + } + + } while( keystroke != 'A' && keystroke != 'a' && keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 + && terminate_signal != 1 ); + +} /* end of nwipe_gui_preview_org_customer( void ) */ + +void nwipe_gui_set_date_time( void ) +{ + /** + * Set system date and time + * + */ + + extern int terminate_signal; + + /* Number of entries in the configuration menu. */ + const int count = 6; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 27; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + time_t t; + + /* Window dimensions */ + int wlines; + int wcols; + + extern config_t nwipe_cfg; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_config ); + wrefresh( footer_window ); + + do + { + do + { + /* Clear the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_config ); + + /* Determine size of window */ + getmaxyx( main_window, wlines, wcols ); + + /* Initialize the working row. */ + yy = 4; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", "Year" ); + mvwprintw( main_window, yy++, tab1, " %s", "Month" ); + mvwprintw( main_window, yy++, tab1, " %s", "Day" ); + yy++; + mvwprintw( main_window, yy++, tab1, " %s", "Hours" ); + mvwprintw( main_window, yy++, tab1, " %s", "Minutes" ); + yy++; + mvwprintw( main_window, + yy++, + tab1, + " %s", + "If a Network Time Protocol (NTP) daemon is running date/time may not change" ); + mvwprintw( main_window, + yy++, + tab1, + " %s", + "or may revert back to NTP provided time. Setting time here is for use when" ); + mvwprintw( main_window, + yy++, + tab1, + " %s", + "the host system is not running NTP or not connected to the internet." ); + + /* Print the cursor. */ + mvwaddch( main_window, 4 + focus, tab1, ACS_RARROW ); + + /******************************* + * Retrieve system date and time + */ + time( &t ); + mvwprintw( main_window, 2, tab1, "%s", ctime( &t ) ); + + /* ************ + * Add a border + */ + box( main_window, 0, 0 ); + + /************* + * Add a title + */ + nwipe_gui_title( main_window, " Set date/time " ); + + /******************** + * Refresh the window + */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count - 1 ) + { + if( focus == 2 ) + { + focus += 2; /* mind the gaps */ + } + else + { + focus += 1; + } + } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) + { + if( focus == 4 ) + { + focus -= 2; /* mind the gaps */ + } + else + { + focus -= 1; + } + } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + case 27: /* ESC */ + + return; + + } /* switch */ + + } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && terminate_signal != 1 ); + + if( keystroke == KEY_ENTER || keystroke == 10 || keystroke == ' ' ) + { + switch( focus ) + { + case 0: + /* Set year */ + nwipe_gui_set_system_year(); + keystroke = 0; + break; + + case 1: + /* Set month */ + nwipe_gui_set_system_month(); + keystroke = 0; + break; + + case 2: + /* Set day */ + nwipe_gui_set_system_day(); + keystroke = 0; + break; + + case 4: + /* Set hours */ + nwipe_gui_set_system_hour(); + keystroke = 0; + break; + + case 5: + /* Set minutes */ + nwipe_gui_set_system_minute(); + keystroke = 0; + break; + } + } + + } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && terminate_signal != 1 ); + +} /* end of nwipe_gui_set_date_time( void ) */ + +void nwipe_gui_set_system_year( void ) +{ + /** + * Allows the user to edit the host systems year + * + * @modifies system year + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy = 2; + + /* Input buffer. */ + int keystroke; + + /* Various output from the date command is processed in this buffer */ + char date_buffer[256]; + date_buffer[0] = 0; + + char year[5] = ""; + char month[3] = ""; + char day[3] = ""; + char hours[3] = ""; + char minutes[3] = ""; + char seconds[3] = ""; + + /* buffer index */ + int idx = 0; + + int status = 0; + + FILE* fp; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + fp = popen( "date +%Y", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "popen:Failed to retrieve date +%Y %s", date_buffer ); + mvwprintw( main_window, yy + 4, tab1, "popen:date command failed retrieving year" ); + } + + if( fgets( date_buffer, sizeof( date_buffer ), fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "fgets:failed to retrieve year %s", date_buffer ); + mvwprintw( main_window, yy + 5, tab1, "fgets:failed retrieving year" ); + } + + /* terminate string after fourth character removing any lf */ + date_buffer[4] = 0; + + pclose( fp ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( date_buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Set System Year " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, yy++, tab1, "Enter the current year, four numeric digits, return key to submit" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + date_buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH && idx < 4 ) + { + date_buffer[idx++] = keystroke; + date_buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* Write year back to system */ + status = read_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:read_system_datetime failed, see previous messages for detail" ); + } + + strncpy( year, date_buffer, 4 ); + + status = write_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:write_system_datetime failed, see previous messages for detail" ); + } + +} /* End of nwipe_gui_set_system_year() */ + +void nwipe_gui_set_system_month( void ) +{ + /** + * Allows the user to edit the host systems year + * + * @modifies system month + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy = 2; + + /* Input buffer. */ + int keystroke; + + /* Various output from the date command is processed in this buffer */ + char date_buffer[256]; + date_buffer[0] = 0; + + char year[5] = ""; + char month[3] = ""; + char day[3] = ""; + char hours[3] = ""; + char minutes[3] = ""; + char seconds[3] = ""; + + /* buffer index */ + int idx = 0; + + int status = 0; + + FILE* fp; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + fp = popen( "date +%m", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "popen:Failed to retrieve date +%m %s", date_buffer ); + mvwprintw( main_window, yy + 4, tab1, "popen:date command failed retrieving month" ); + } + + if( fgets( date_buffer, sizeof( date_buffer ), fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "fgets:failed to retrieve month %s", date_buffer ); + mvwprintw( main_window, yy + 5, tab1, "fgets:failed retrieving month" ); + } + + /* terminate string after fourth character removing any lf */ + date_buffer[2] = 0; + + pclose( fp ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( date_buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Set System Month " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( + main_window, yy++, tab1, "Enter the current month, two numeric digits, i.e 01, return key to submit" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + date_buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH && idx < 4 ) + { + date_buffer[idx++] = keystroke; + date_buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* Write year back to system */ + status = read_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:read_system_datetime failed, see previous messages for detail" ); + } + + strncpy( month, date_buffer, 2 ); + + status = write_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:write_system_datetime failed, see previous messages for detail" ); + } + +} /* End of nwipe_gui_set_system_month() */ + +void nwipe_gui_set_system_day( void ) +{ + /** + * Allows the user to edit the host systems year + * + * @modifies system day of the month + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy = 2; + + /* Input buffer. */ + int keystroke; + + /* Various output from the date command is processed in this buffer */ + char date_buffer[256]; + date_buffer[0] = 0; + + char year[5] = ""; + char month[3] = ""; + char day[3] = ""; + char hours[3] = ""; + char minutes[3] = ""; + char seconds[3] = ""; + + /* buffer index */ + int idx = 0; + + int status = 0; + + FILE* fp; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + fp = popen( "date +%d", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "popen:Failed to retrieve date +%d %s", date_buffer ); + mvwprintw( main_window, yy + 4, tab1, "popen:date command failed retrieving day of month" ); + } + + if( fgets( date_buffer, sizeof( date_buffer ), fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "fgets:failed to retrieve day of month %s", date_buffer ); + mvwprintw( main_window, yy + 5, tab1, "fgets:failed retrieving day of month" ); + } + + /* terminate string after fourth character removing any lf */ + date_buffer[2] = 0; + + pclose( fp ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( date_buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Set System Day of Month " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( main_window, + yy++, + tab1, + "Enter the current day of month, two numeric digits, i.e 01, return key to submit" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + date_buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH && idx < 4 ) + { + date_buffer[idx++] = keystroke; + date_buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* Write year back to system */ + status = read_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:read_system_datetime failed, see previous messages for detail" ); + } + + strncpy( day, date_buffer, 2 ); + + status = write_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:write_system_datetime failed, see previous messages for detail" ); + } + +} /* End of nwipe_gui_set_system_day() */ + +void nwipe_gui_set_system_hour( void ) +{ + /** + * Allows the user to edit the host systems year + * + * @modifies system hour + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy = 2; + + /* Input buffer. */ + int keystroke; + + /* Various output from the date command is processed in this buffer */ + char date_buffer[256]; + date_buffer[0] = 0; + + char year[5] = ""; + char month[3] = ""; + char day[3] = ""; + char hours[3] = ""; + char minutes[3] = ""; + char seconds[3] = ""; + + /* buffer index */ + int idx = 0; + + int status = 0; + + FILE* fp; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + fp = popen( "date +%H", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "popen:Failed to retrieve date +%H %s", date_buffer ); + mvwprintw( main_window, yy + 4, tab1, "popen:date command failed retrieving hour" ); + } + + if( fgets( date_buffer, sizeof( date_buffer ), fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "fgets:failed to retrieve the hour %s", date_buffer ); + mvwprintw( main_window, yy + 5, tab1, "fgets:failed retrieving the hour" ); + } + + /* terminate string after fourth character removing any lf */ + date_buffer[2] = 0; + + pclose( fp ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( date_buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Set System Hour " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( + main_window, yy++, tab1, "Enter the current hour, two numeric digits, i.e 01, return key to submit" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + date_buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH && idx < 4 ) + { + date_buffer[idx++] = keystroke; + date_buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* Write year back to system */ + status = read_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:read_system_datetime failed, see previous messages for detail" ); + } + + strncpy( hours, date_buffer, 2 ); + + status = write_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:write_system_datetime failed, see previous messages for detail" ); + } + +} /* End of nwipe_gui_set_system_hour() */ + +void nwipe_gui_set_system_minute( void ) +{ + /** + * Allows the user to edit the host systems year + * + * @modifies system minute + * @modifies main_window + * + */ + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy = 2; + + /* Input buffer. */ + int keystroke; + + /* Various output from the date command is processed in this buffer */ + char date_buffer[256]; + date_buffer[0] = 0; + + char year[5] = ""; + char month[3] = ""; + char day[3] = ""; + char hours[3] = ""; + char minutes[3] = ""; + char seconds[3] = ""; + + /* buffer index */ + int idx = 0; + + int status = 0; + + FILE* fp; + + extern int terminate_signal; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer_text_entry ); + wrefresh( footer_window ); + + fp = popen( "date +%M", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "popen:Failed to retrieve date +%M %s", date_buffer ); + mvwprintw( main_window, yy + 4, tab1, "popen:date command failed retrieving minute" ); + } + + if( fgets( date_buffer, sizeof( date_buffer ), fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "fgets:failed to retrieve the minute %s", date_buffer ); + mvwprintw( main_window, yy + 5, tab1, "fgets:failed retrieving the minute" ); + } + + /* terminate string after fourth character removing any lf */ + date_buffer[2] = 0; + + pclose( fp ); + + /* Set the buffer index to point to the end of the string, i.e the NULL */ + idx = strlen( date_buffer ); + + do + { + /* Erase the main window. */ + werase( main_window ); + + nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_text_entry ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Set System Minute " ); + + /* Initialize the working row. */ + yy = 4; + + mvwprintw( + main_window, yy++, tab1, "Enter the current minute, two numeric digits, i.e 01, return key to submit" ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + timeout( 250 ); // block getch() for 250ms. + keystroke = getch(); // Get a keystroke. + timeout( -1 ); // Switch back to blocking mode. + + switch( keystroke ) + { + /* Escape key. */ + case 27: + return; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + if( idx > 0 ) + { + date_buffer[--idx] = 0; + } + + break; + + } /* switch keystroke */ + + if( ( keystroke >= ' ' && keystroke <= '~' ) && keystroke != '\"' && idx < FIELD_LENGTH && idx < 4 ) + { + date_buffer[idx++] = keystroke; + date_buffer[idx] = 0; + mvwprintw( main_window, 2, tab1, ">%s", date_buffer ); + } + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && terminate_signal != 1 ); + + /* Write year back to system */ + status = read_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:read_system_datetime failed, see previous messages for detail" ); + } + + strncpy( minutes, date_buffer, 2 ); + + status = write_system_datetime( year, month, day, hours, minutes, seconds ); + if( status != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "func:write_system_datetime failed, see previous messages for detail" ); + } + +} /* End of nwipe_gui_set_system_minute() */ + +void nwipe_gui_load( void ) +{ + /** + * Prints the system load average to the statistics window. + * + * @modifies stat_window Prints the system load average to the statistics window. + * + */ + + /* A file handle for the stat file. */ + FILE* nwipe_fp; + + /* The one, five, and fifteen minute load averages. */ + float load_01; + float load_05; + float load_15; + + /* Open the loadavg file. */ + nwipe_fp = fopen( NWIPE_KNOB_LOADAVG, "r" ); + + /* Print the label. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_LOAD_X, "Load Averages:" ); + + if( nwipe_fp ) + { + /* The load averages are the first three numbers in the file. */ + if( 3 == fscanf( nwipe_fp, "%f %f %f", &load_01, &load_05, &load_15 ) ) + { + /* Print the load average. */ + mvwprintw( stats_window, + NWIPE_GUI_STATS_LOAD_Y, + NWIPE_GUI_STATS_TAB, + "%04.2f %04.2f %04.2f", + load_01, + load_05, + load_15 ); + } + else + { + /* Print an error. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_TAB, "(fscanf error %i)", errno ); + } + + /* Close the loadavg file. */ + fclose( nwipe_fp ); + } + else + { + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_TAB, "(fopen error %i)", errno ); + } + +} /* nwipe_gui_load */ + +void* nwipe_gui_status( void* ptr ) +{ + /** + * Shows runtime statistics and overall progress. + * + * @parameter count The number of contexts in the array. + * @parameter c An array of device contexts. + * + * @modifies main_window Prints information into the main window. + * @modifies c[].throughput Updates the i/o throughput value. + * + */ + + extern int terminate_signal; + + nwipe_thread_data_ptr_t* nwipe_thread_data_ptr; + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t*) ptr; + + nwipe_context_t** c; + nwipe_misc_thread_data_t* nwipe_misc_thread_data; + int count; + + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + count = nwipe_misc_thread_data->nwipe_selected; + + char nomenclature_result_str[NOMENCLATURE_RESULT_STR_SIZE]; /* temporary usage */ + + /* Spinner character */ + char spinner_string[2]; + + /* Create the finish message, this changes based on whether PDF creation is enabled + * and whether a logfile has been specified + */ + char finish_message[NWIPE_GUI_FOOTER_W + 132]; + if( nwipe_options.logfile[0] == 0 && nwipe_options.PDF_enable != 0 ) + { + snprintf( finish_message, + sizeof( finish_message ), + "Wipe finished - press enter to create pdfs & exit. Logged to STDOUT" ); + } + else + { + if( nwipe_options.logfile[0] != 0 && nwipe_options.PDF_enable != 0 ) + { + snprintf( finish_message, + sizeof( finish_message ), + "Wipe finished - press enter to create pdfs & exit. Logged to %s", + nwipe_options.logfile ); + } + else + { + if( nwipe_options.logfile[0] != 0 && nwipe_options.PDF_enable == 0 ) + { + snprintf( finish_message, + sizeof( finish_message ), + "Wipe finished - press enter to exit (pdfs disabled in config). Logged to %s", + nwipe_options.logfile ); + } + else + { + if( nwipe_options.logfile[0] == 0 && nwipe_options.PDF_enable == 0 ) + { + snprintf( finish_message, + sizeof( finish_message ), + "Wipe finished - press enter to exit (pdfs disabled in config). Logged to STDOUT" ); + } + else + { + /* This is a catch all something unexpected happens with the above logic */ + snprintf( finish_message, + sizeof( finish_message ), + "Wipe finished - press enter to exit. Logged to STDOUT" ); + } + } + } + } + + /* We count time from when this function is first called. */ + static time_t nwipe_time_start = 0; + + /* Whether the screen has been blanked by the user. */ + static int nwipe_gui_blank = 0; + + /* The current time. */ + time_t nwipe_time_now; + + /* The time when all wipes ended */ + time_t nwipe_time_stopped; + + /* The index of the element that is visible in the first slot. */ + static int offset; + + /* The number of elements that we can show in the window. */ + int slots; + + /* Window dimensions. */ + int wlines; + int wcols; + + /* Generic loop variable. */ + int i; + + /* The current working line in the main window. */ + int yy; + + /* User input buffer. */ + int keystroke; + + /* controls main while loop */ + int loop_control; + + /* The combined througput of all processes. */ + nwipe_misc_thread_data->throughput = 0; + + /* The estimated runtime of the slowest device. */ + nwipe_misc_thread_data->maxeta = 0; + + /* The combined number of errors of all processes. */ + nwipe_misc_thread_data->errors = 0; + + /* Time values. */ + int nwipe_hh; + int nwipe_mm; + int nwipe_ss; + + struct timespec tim, tim2; + tim.tv_sec = 0; + tim.tv_nsec = 100000000L; /* sleep for 0.1 seconds */ + + /* Throughput variables */ + u64 nwipe_throughput; + + /* The number of active wipe processes. */ + /* Set to 1 initially to start loop. */ + int nwipe_active = 1; + + /* Used in the gui status loop to trap a failure of the halfdelay(), getch() mechanism to block for the designated + * period */ + int expected_iterations; + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period, initialise the counter */ + int iteration_counter = 0; + + time_t previous_iteration_timestamp = time( NULL ); + + /* Calculate Maximum allowed iterations per second (typically 20), which is double the expected iterations + * (typically 10) */ + expected_iterations = ( 1000 / GETCH_GUI_STATS_UPDATE_MS ) * 2; + + if( nwipe_time_start == 0 ) + { + /* This is the first time that we have been called. */ + nwipe_time_start = time( NULL ) - 1; + } + + nwipe_gui_title( footer_window, end_wipe_footer ); + + loop_control = 1; + + while( loop_control ) + { + /* IMPORTANT ! Halfdelay(1) causes getch() to pause for 0.1 secs. This is important for two reasons. + * 1. Pauses the getch for 0.1 secs so that the screen is only updated max 10 times/sec. Without + * this delay the loop would run hundreds of times per sec maxing out the core. + * 2. By keeping the delay below 0.2 seconds, i.e 0.1, it makes the keypress and resizing + * nice and responsive. + */ + halfdelay( GETCH_GUI_STATS_UPDATE_MS ); // Important, don't change this unless you know what you are doing ! + // Related to getch(). + + keystroke = getch(); // Get user input. + + iteration_counter++; + + /* Much like the same check we perform in the nwipe_gui_select() function, here we check that we are not looping + * any faster than as defined by the halfdelay() function above, typically this loop runs at 10 times a second. + * This check makes sure that if the loop runs faster than double this value i.e 20 times a second then the + * program exits. This check is therefore determining whether the getch() function is returning immediately + * rather than blocking for the defined period of 100ms. Why is this necessary? Some terminals (konsole & + * deriviatives) that are exited while nwipe is still running fail to terminate nwipe this causes the + * halfdelay()/getch() functions to immediately fail causing the loop frequency to drastically increase. We + * detect that speed increase here and therefore close down nwipe. This doesn't affect the use of the tmux + * terminal by which you can detach and reattach to running nwipe processes. tmux still works correctly. + */ + if( previous_iteration_timestamp == time( NULL ) ) + { + if( iteration_counter > expected_iterations ) + { + nwipe_log( NWIPE_LOG_ERROR, + "GUI.c,nwipe_gui_status(), loop runaway, did you close the terminal without exiting " + "nwipe? Initiating shutdown now." ); + /* Issue signal to nwipe to shutdown immediately but gracefully */ + terminate_signal = 1; + } + } + else + { + /* new second, so reset counter */ + iteration_counter = 0; + previous_iteration_timestamp = time( NULL ); + } + + /* Get the current time. */ + if( nwipe_active && terminate_signal != 1 ) + { + nwipe_time_now = time( NULL ); + nwipe_time_stopped = nwipe_time_now; + } + else + { + nwipe_time_now = nwipe_time_stopped; + } + + /* Erase the main window. */ + werase( main_window ); + + /* Erase the stats window. */ + werase( stats_window ); + + /* Erase the footer window */ + werase( footer_window ); + + /* Only repaint the windows on terminal resize if the user hasn't blanked the screen */ + if( nwipe_gui_blank == 0 ) + { + if( nwipe_active != 0 ) + { + /* if resizing the terminal during a wipe a specific footer is required */ + nwipe_gui_create_all_windows_on_terminal_resize( 0, end_wipe_footer ); + } + else + { + /* and if the wipes have finished a different footer is required */ + nwipe_gui_create_all_windows_on_terminal_resize( 0, finish_message ); + } + } + + /* Initialize our working offset to the third line. */ + yy = 2; + + /* Get the window dimensions. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less four lines for the box and padding. */ + slots = wlines - 4; + + /* Each element prints three lines. */ + slots /= 3; + + if( nwipe_active == 0 || terminate_signal == 1 ) + { + nwipe_gui_title( footer_window, finish_message ); + + // Refresh the footer_window ; + wnoutrefresh( footer_window ); + } + + if( terminate_signal == 1 ) + { + loop_control = 0; + } + + if( keystroke > 0x0a && keystroke < 0x7e && nwipe_gui_blank == 1 ) + { + tft_saver = 0; + nwipe_init_pairs(); + nwipe_gui_create_all_windows_on_terminal_resize( 1, end_wipe_footer ); + + /* Show screen */ + nwipe_gui_blank = 0; + + /* Set background */ + wbkgdset( stdscr, COLOR_PAIR( 1 ) ); + wclear( stdscr ); + + /* Unhide panels */ + show_panel( header_panel ); + show_panel( footer_panel ); + show_panel( stats_panel ); + show_panel( options_panel ); + show_panel( main_panel ); + + /* Reprint the footer */ + nwipe_gui_title( footer_window, end_wipe_footer ); + + // Refresh the footer_window ; + wnoutrefresh( footer_window ); + + /* Update panels */ + update_panels(); + doupdate(); + } + else if( keystroke > 0 ) + { + + switch( keystroke ) + { + + case 'b': + case 'B': + + if( nwipe_gui_blank == 0 && tft_saver != 1 ) + { + /* grey text on black background */ + tft_saver = 1; + nwipe_init_pairs(); + nwipe_gui_create_all_windows_on_terminal_resize( 1, end_wipe_footer ); + } + else + { + if( nwipe_gui_blank == 0 && tft_saver == 1 ) + { + /* Blank screen. */ + tft_saver = 0; + nwipe_gui_blank = 1; + hide_panel( header_panel ); + hide_panel( footer_panel ); + hide_panel( stats_panel ); + hide_panel( options_panel ); + hide_panel( main_panel ); + } + + /* Set the background style. */ + wbkgdset( stdscr, COLOR_PAIR( 7 ) ); + wclear( stdscr ); + } + + break; + + case KEY_DOWN: + case 'j': + case 'J': + + /* Scroll down. */ + offset += 1; + + if( count < slots ) + { + offset = 0; + } + + else if( offset + slots > count ) + { + offset = count - slots; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + /* Scroll up. */ + offset -= 1; + + if( offset < 0 ) + { + offset = 0; + } + + break; + + case ' ': + case 0x0a: + + /* Check whether we have finished all wipes, if yes exit while loop if user pressed spacebar or + * return. */ + if( !nwipe_active || terminate_signal == 1 ) + { + loop_control = 0; + } + + break; + + default: + + /* Do nothing. */ + break; + } + + } /* keystroke */ + + /* If wipe has completed and user has specified auto poweroff or nowait then we can skip waiting for the user to + * press return */ + if( !nwipe_active ) + { + if( nwipe_options.autopoweroff || nwipe_options.nowait ) + { + loop_control = 0; + } + } + + /* Update data in statistics & main windows only if we're in 'gui' mode and only if a wipe has started */ + if( global_wipe_status == 1 ) + { + /* Always run compute_stats() as we need to whether any threads are still active */ + if( terminate_signal != 1 ) + { + nwipe_active = compute_stats( ptr ); // Returns number of active wipe threads + } + + /* Only print the stats if the user hasn't blanked the screen */ + if( nwipe_gui_blank == 0 ) + { + + /* Print information for the user. */ + for( i = offset; i < offset + slots && i < count; i++ ) + { + /* Print the device details. */ + mvwprintw( main_window, + yy++, + 2, + "%s %s [%s] ", + c[i]->device_name, + c[i]->device_type_str, + c[i]->device_size_text ); + wprintw_temperature( c[i] ); + wprintw( main_window, " %s/%s", c[i]->device_model, c[i]->device_serial_no ); + + /* Check whether the child process is still running the wipe. */ + if( c[i]->wipe_status == 1 ) + { + /* Print percentage and pass information. */ + mvwprintw( main_window, + yy++, + 4, + "[%5.2f%%, round %i of %i, pass %i of %i] ", + c[i]->round_percent, + c[i]->round_working, + c[i]->round_count, + c[i]->pass_working, + c[i]->pass_count ); + + } /* child running */ + else + { + if( c[i]->result == 0 ) + { + mvwprintw( main_window, yy++, 4, "[%05.2f%% complete, SUCCESS! ", c[i]->round_percent ); + } + else if( c[i]->signal ) + { + wattron( main_window, COLOR_PAIR( 9 ) ); + mvwprintw( main_window, yy++, 4, "(>>> FAILURE! <<<, signal %i) ", c[i]->signal ); + wattroff( main_window, COLOR_PAIR( 9 ) ); + } + else + { + wattron( main_window, COLOR_PAIR( 9 ) ); + mvwprintw( main_window, yy++, 4, "(>>> IOERROR! <<<, code %i) ", c[i]->result ); + wattroff( main_window, COLOR_PAIR( 9 ) ); + } + + } /* child returned */ + + if( c[i]->verify_errors ) + { + wprintw( main_window, "[verr:%llu] ", c[i]->verify_errors ); + } + if( c[i]->pass_errors ) + { + wprintw( main_window, "[perr:%llu] ", c[i]->pass_errors ); + } + if( c[i]->wipe_status == 1 ) + { + switch( c[i]->pass_type ) + { + /* Each text field in square brackets should be the same number of characters + * to retain output in columns */ + case NWIPE_PASS_FINAL_BLANK: + if( !c[i]->sync_status ) + { + wprintw( main_window, "[ blanking] " ); + } + break; + + case NWIPE_PASS_FINAL_OPS2: + if( !c[i]->sync_status ) + { + wprintw( main_window, "[OPS2final] " ); + } + break; + + case NWIPE_PASS_WRITE: + if( !c[i]->sync_status ) + { + wprintw( main_window, "[ writing ] " ); + } + break; + + case NWIPE_PASS_VERIFY: + if( !c[i]->sync_status ) + { + wprintw( main_window, "[verifying] " ); + } + break; + + case NWIPE_PASS_NONE: + break; + } + + if( c[i]->sync_status ) + { + wprintw( main_window, "[ syncing ] " ); + } + } + + /* Determine throughput nomenclature for this drive and output drives throughput to GUI */ + Determine_C_B_nomenclature( + c[i]->throughput, nomenclature_result_str, NOMENCLATURE_RESULT_STR_SIZE ); + + wprintw( main_window, "[%s/s] ", nomenclature_result_str ); + + /* Insert whitespace. */ + yy += 1; + + /* Increment the next spinner character for this context if the thread is active */ + if( c[i]->wipe_status == 1 ) + { + spinner( c, i ); + spinner_string[0] = c[i]->spinner_character[0]; + } + else + { + /* If the wipe thread is no longer active, replace the spinner with a space */ + spinner_string[0] = ' '; + } + spinner_string[1] = 0; + wprintw( main_window, " %s ", spinner_string ); + } + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols - 8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines - 2, wcols - 8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + /* Box the main window. */ + box( main_window, 0, 0 ); + + /* Refresh the main window. */ + wnoutrefresh( main_window ); + + /* Update the load average field, but only if we are still wiping */ + if( nwipe_active && terminate_signal != 1 ) + { + nwipe_gui_load(); + } + + nwipe_throughput = nwipe_misc_thread_data->throughput; + + /* Determine the nomenclature for the combined throughput */ + Determine_C_B_nomenclature( nwipe_throughput, nomenclature_result_str, NOMENCLATURE_RESULT_STR_SIZE ); + + /* Print the combined throughput. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_THROUGHPUT_X, "Throughput:" ); + + mvwprintw( + stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_TAB, "%s/s", nomenclature_result_str ); + + /* Change the current time into a delta. */ + nwipe_time_now -= nwipe_time_start; + + /* Put the delta into HH:mm:ss form. */ + nwipe_hh = nwipe_time_now / 3600; + nwipe_time_now %= 3600; + nwipe_mm = nwipe_time_now / 60; + nwipe_time_now %= 60; + nwipe_ss = nwipe_time_now; + + /* Print the runtime. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_RUNTIME_Y, 1, "Runtime:" ); + mvwprintw( stats_window, + NWIPE_GUI_STATS_RUNTIME_Y, + NWIPE_GUI_STATS_TAB, + "%02i:%02i:%02i", + nwipe_hh, + nwipe_mm, + nwipe_ss ); + + mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, 1, "Remaining:" ); + + time_t nwipe_maxeta = nwipe_misc_thread_data->maxeta; + if( nwipe_maxeta > 0 ) + { + /* Do it again for the estimated runtime remaining. */ + nwipe_hh = nwipe_maxeta / 3600; + nwipe_maxeta %= 3600; + nwipe_mm = nwipe_maxeta / 60; + nwipe_maxeta %= 60; + nwipe_ss = nwipe_maxeta; + + /* Print the estimated runtime remaining. */ + mvwprintw( stats_window, + NWIPE_GUI_STATS_ETA_Y, + NWIPE_GUI_STATS_TAB, + "%02i:%02i:%02i", + nwipe_hh, + nwipe_mm, + nwipe_ss ); + } + + /* Print the error count. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_ERRORS_X, "Errors:" ); + mvwprintw( stats_window, + NWIPE_GUI_STATS_ERRORS_Y, + NWIPE_GUI_STATS_TAB, + " %llu", + nwipe_misc_thread_data->errors ); + + /* Add a border. */ + box( stats_window, 0, 0 ); + + /* Add a title. */ + mvwprintw( stats_window, 0, ( NWIPE_GUI_STATS_W - strlen( stats_title ) ) / 2, "%s", stats_title ); + + /* Refresh internal representation of stats window */ + wnoutrefresh( stats_window ); + + /* Output all windows to screen */ + doupdate(); + + } // end blank screen if + + } // end wipes have started if + + } /* End of while loop */ + + nwipe_gui_title( footer_window, finish_message ); + terminate_signal = 1; + + return NULL; +} /* nwipe_gui_status */ + +int compute_stats( void* ptr ) +{ + nwipe_thread_data_ptr_t* nwipe_thread_data_ptr; + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t*) ptr; + + nwipe_context_t** c; + nwipe_misc_thread_data_t* nwipe_misc_thread_data; + + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + int count = nwipe_misc_thread_data->nwipe_selected; + + int nwipe_active = 0; + int i; + + time_t nwipe_time_now = time( NULL ); + + nwipe_misc_thread_data->throughput = 0; + nwipe_misc_thread_data->maxeta = 0; + nwipe_misc_thread_data->errors = 0; + + /* Enumerate all contexts to compute statistics. */ + for( i = 0; i < count; i++ ) + { + /* Check whether the child process is still running the wipe. */ + if( c[i]->wipe_status == 1 ) + { + /* Increment the child counter. */ + nwipe_active += 1; + + /* Even if the wipe has finished ALWAYS run the stats one last time so the final SUCCESS percentage value is + * correct. Maintain a rolling average of throughput. */ + nwipe_update_speedring( &c[i]->speedring, c[i]->round_done, nwipe_time_now ); + + if( c[i]->speedring.timestotal > 0 && c[i]->wipe_status == 1 ) + { + /* Update the current average throughput in bytes-per-second. */ + c[i]->throughput = c[i]->speedring.bytestotal / c[i]->speedring.timestotal; + + /* Only update the estimated remaining runtime if the + * throughput for a given drive is greater than 100,000 bytes per second + * This prevents enormous ETA's being calculated on an unresponsive + * drive */ + if( c[i]->throughput > 100000 ) + { + c[i]->eta = ( c[i]->round_size - c[i]->round_done ) / c[i]->throughput; + + if( c[i]->eta > nwipe_misc_thread_data->maxeta ) + { + nwipe_misc_thread_data->maxeta = c[i]->eta; + } + } + } + + /* Calculate the average throughput */ + c[i]->throughput = (double) c[i]->round_done / (double) difftime( nwipe_time_now, c[i]->start_time ); + } + + /* Update the percentage value. */ + c[i]->round_percent = (double) c[i]->round_done / (double) c[i]->round_size * 100; + + if( c[i]->wipe_status == 1 ) + { + /* Accumulate combined throughput. */ + nwipe_misc_thread_data->throughput += c[i]->throughput; + } + + /* Accumulate the error count. */ + nwipe_misc_thread_data->errors += c[i]->pass_errors; + nwipe_misc_thread_data->errors += c[i]->verify_errors; + nwipe_misc_thread_data->errors += c[i]->fsyncdata_errors; + + /* Read the drive temperature values */ + // if( nwipe_time_now > ( c[i]->temp1_time + 60 ) ) + // { + // nwipe_update_temperature( c[i] ); + // } + + } /* for statistics */ + + return nwipe_active; +} + +void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_bytes, time_t speedring_now ) +{ + + if( speedring->timeslast == 0 ) + { + /* Ignore the first sample and initialize. */ + speedring->timeslast = speedring_now; + return; + } + + if( speedring_now - speedring->timeslast < NWIPE_KNOB_SPEEDRING_GRANULARITY ) + { + /* Avoid jitter caused by frequent updates. */ + return; + } + + /* Subtract the oldest speed sample from the accumulator. */ + speedring->bytestotal -= speedring->bytes[speedring->position]; + speedring->timestotal -= speedring->times[speedring->position]; + + /* Put the latest bytes-per-second sample into the ring buffer. */ + speedring->bytes[speedring->position] = speedring_bytes - speedring->byteslast; + speedring->times[speedring->position] = speedring_now - speedring->timeslast; + + /* Add the newest speed sample to the accumulator. */ + speedring->bytestotal += speedring->bytes[speedring->position]; + speedring->timestotal += speedring->times[speedring->position]; + + /* Remember the last sample. */ + speedring->byteslast = speedring_bytes; + speedring->timeslast = speedring_now; + + if( ++speedring->position >= NWIPE_KNOB_SPEEDRING_SIZE ) + { + speedring->position = 0; + } +} + +int spinner( nwipe_context_t** ptr, int device_idx ) +{ + nwipe_context_t** c; + + c = ptr; + + /* The spinner characters |/-\|/-\ */ + char sc[9] = "|/-\\|/-\\/"; + + /* Check sanity of index */ + if( c[device_idx]->spinner_idx < 0 || c[device_idx]->spinner_idx > 7 ) + { + return 1; + } + + c[device_idx]->spinner_character[0] = sc[c[device_idx]->spinner_idx]; + + c[device_idx]->spinner_idx++; + + if( c[device_idx]->spinner_idx > 7 ) + { + c[device_idx]->spinner_idx = 0; + } + + return 0; +} + +void temp1_flash( nwipe_context_t* c ) +{ + if( c->temp1_flash_rate_counter < c->temp1_flash_rate ) + { + c->temp1_flash_rate_counter++; + } + else + { + c->temp1_flash_rate_counter = 0; + if( c->temp1_flash_rate_status == 0 ) + { + c->temp1_flash_rate_status = 1; + } + else + { + c->temp1_flash_rate_status = 0; + } + } +} + +void wprintw_temperature( nwipe_context_t* c ) +{ + /* See header for description of function + */ + + int temp_highest_limit; + int temp_high_limit; + int temp_low_limit; + int temp_lowest_limit; + + int local_temp1_input = c->temp1_input; + int local_temp1_crit = c->temp1_crit; + int local_temp1_max = c->temp1_max; + int local_temp1_min = c->temp1_min; + int local_temp1_lcrit = c->temp1_lcrit; + + /* Initialise */ + temp_highest_limit = NO_TEMPERATURE_DATA; + temp_high_limit = NO_TEMPERATURE_DATA; + temp_low_limit = NO_TEMPERATURE_DATA; + temp_lowest_limit = NO_TEMPERATURE_DATA; + +#if 0 + /* NOTE TEST Function, TEST Function #if 0 when not testing + * Should increment temperature back and forth between +10 to -10 + * while changing the color based on the settings such as + * c->temp1_crit and others below + */ + if( c->test_use1 > 12 || c->test_use1 < -12 ) + { + c->test_use1 = 0; // the value + c->test_use2 = 0; // direction 0 = -- or 1 = ++ + } + if( c->test_use1 >= 10 ) + { + c->test_use2 = 0; + } + else + { + if( c->test_use1 <= -10 ) + { + c->test_use2 = 1; + } + } + if( c->test_use2 == 0 ) + { + c->test_use1--; + } + else + { + c->test_use1++; + } + + /* Five test cases to test temperature color logic + * test only with temperatures in the range -8 to +8 + * test with each set of five for expected result if + * changes are made. + * + * Uncomment only one group in turn to be tested. + */ + local_temp1_input = c->test_use1; + // + // Expected result - white on blue between +5 & -5, white on red above 5 + // white on black below -5 + local_temp1_crit = NO_TEMPERATURE_DATA; + local_temp1_max = 5; + local_temp1_min = -5; + local_temp1_lcrit = NO_TEMPERATURE_DATA; + // + // Expected result - white on blue between +5 & -5, white on red above 5 + // white on black below -5 + //local_temp1_crit = 5; + //local_temp1_max = NO_TEMPERATURE_DATA; + //local_temp1_min = NO_TEMPERATURE_DATA; + //local_temp1_lcrit = -5; + // + // Expected result - white on blue 5 to -5, 5-7 red on blue, + // 8+ white on red, -5 to-7 black on blue, less than -7 white on black + //local_temp1_crit = 8; + //local_temp1_max = 5; + //local_temp1_min = -5; + //local_temp1_lcrit = -8; + // + // Expected result - white on blue 5 to -5, 5-7 red on blue, + // 8+ white on red, -5 to-7 black on blue, less than -7 white on black + //local_temp1_crit = 5; + //local_temp1_max = 8; + //local_temp1_min = -8; + //local_temp1_lcrit = -5; + // + // Expected result - always white text on blue background + //local_temp1_crit = NO_TEMPERATURE_DATA; + //local_temp1_max = NO_TEMPERATURE_DATA; + //local_temp1_min = NO_TEMPERATURE_DATA; + //local_temp1_lcrit = NO_TEMPERATURE_DATA; +#endif + + /* Depending upon the drive firmware, the meaning of 'high critical' & 'max' + * and 'low critical' & 'low' can be interchanged. First validate for 'no data' + * (1000000) and also a 0 in 'high critical' and 'max', then assign the values + * to our four variables in the appropriate order. + */ + + /* Validate critical high value & max for 0, if 0 it's invalid, change to 1000000 + */ + + /* Assign temp1_crit & temp1_max to local variables as we are going to alter + * them if 0, as they may be updated elsewhere we don't want them changed back half + * way through our processing. This is only necessary for the high temperatures and + * not the low temperatures as low temperatures may well be 0. + */ + + if( local_temp1_crit == 0 ) + { + local_temp1_crit = NO_TEMPERATURE_DATA; + } + if( local_temp1_max == 0 ) + { + local_temp1_max = NO_TEMPERATURE_DATA; + } + + /* Check which way around they are */ + if( local_temp1_crit != NO_TEMPERATURE_DATA && local_temp1_max != NO_TEMPERATURE_DATA ) + { + if( local_temp1_crit > local_temp1_max ) + { + temp_highest_limit = local_temp1_crit; + temp_high_limit = local_temp1_max; + } + else + { + temp_highest_limit = local_temp1_max; + temp_high_limit = local_temp1_crit; + } + } + else + { + /* If only one or the other is present then assign that value to both high critical and max + */ + if( local_temp1_crit == NO_TEMPERATURE_DATA && local_temp1_max != NO_TEMPERATURE_DATA ) + { + temp_highest_limit = local_temp1_max; + temp_high_limit = local_temp1_max; + } + else + { + /* If high critical is present but max is not, assign high critical to both */ + if( local_temp1_crit != NO_TEMPERATURE_DATA && local_temp1_max == NO_TEMPERATURE_DATA ) + { + temp_highest_limit = local_temp1_crit; + temp_high_limit = local_temp1_crit; + } + else + { + /* neither is present so mark both locals as not present */ + temp_highest_limit = NO_TEMPERATURE_DATA; + temp_high_limit = NO_TEMPERATURE_DATA; + } + } + } + + /* Now do the same for the low critical limit and low limit. */ + + /* Check which way around they are */ + if( local_temp1_lcrit != NO_TEMPERATURE_DATA && local_temp1_min != NO_TEMPERATURE_DATA ) + { + if( local_temp1_lcrit < local_temp1_min ) + { + temp_lowest_limit = local_temp1_lcrit; + temp_low_limit = local_temp1_min; + } + else + { + temp_lowest_limit = local_temp1_min; + temp_low_limit = local_temp1_lcrit; + } + } + else + { + /* If only one or the other is present then assign that value to both high critical and max + */ + if( local_temp1_lcrit == NO_TEMPERATURE_DATA && local_temp1_min != NO_TEMPERATURE_DATA ) + { + temp_lowest_limit = local_temp1_min; + temp_low_limit = local_temp1_min; + } + else + { + /* If high critical is present but max is not, assign high critical to both */ + if( local_temp1_lcrit != NO_TEMPERATURE_DATA && local_temp1_min == NO_TEMPERATURE_DATA ) + { + temp_lowest_limit = local_temp1_lcrit; + temp_low_limit = local_temp1_lcrit; + } + else + { + /* neither is present so mark both locals as not present */ + temp_lowest_limit = NO_TEMPERATURE_DATA; + temp_low_limit = NO_TEMPERATURE_DATA; + } + } + } + + /* if drive temperature has exceeded the critical temperature if available + */ + if( ( local_temp1_input >= temp_highest_limit ) && ( local_temp1_input != NO_TEMPERATURE_DATA ) + && ( temp_highest_limit != NO_TEMPERATURE_DATA ) ) + { + /* white on red */ + wattron( main_window, COLOR_PAIR( 6 ) ); + wprintw( main_window, "[%dC]", local_temp1_input ); + wattroff( main_window, COLOR_PAIR( 6 ) ); + } + else + { + /* if drive temperature has exceeded the max temperature if available + */ + if( ( local_temp1_input >= temp_high_limit ) && ( local_temp1_input <= temp_highest_limit ) + && ( local_temp1_input != NO_TEMPERATURE_DATA ) && ( temp_high_limit != NO_TEMPERATURE_DATA ) ) + { + /* red on blue */ + wattron( main_window, COLOR_PAIR( 3 ) ); + wprintw( main_window, "[%dC]", local_temp1_input ); + wattroff( main_window, COLOR_PAIR( 3 ) ); + } + else + { + /* if drive temperature is below the lowest critical temperature and the critical value is present + */ + if( ( local_temp1_input <= temp_lowest_limit ) && ( temp_lowest_limit != NO_TEMPERATURE_DATA ) + && ( local_temp1_input != NO_TEMPERATURE_DATA ) ) + { + /* white on black */ + wattron( main_window, COLOR_PAIR( 14 ) ); + wprintw( main_window, "[%dC]", local_temp1_input ); + wattroff( main_window, COLOR_PAIR( 14 ) ); + } + else + { + /* if drive temperature is below the minimum but above the lowest temperature and the value is present + */ + if( ( ( local_temp1_input <= temp_low_limit ) && ( local_temp1_input >= temp_lowest_limit ) + && ( local_temp1_input != NO_TEMPERATURE_DATA ) && ( temp_low_limit != NO_TEMPERATURE_DATA ) ) ) + { + /* black on blue */ + wattron( main_window, COLOR_PAIR( 11 ) ); + wprintw( main_window, "[%dC]", local_temp1_input ); + wattroff( main_window, COLOR_PAIR( 11 ) ); + } + else + { + if( local_temp1_input != NO_TEMPERATURE_DATA ) + { + /* Default white on blue */ + wprintw( main_window, "[%dC]", local_temp1_input ); + } + else + { + /* Default white on blue */ + wprintw( main_window, "[--C]" ); + } + } + } + } + } +} + +char* str_truncate( int wcols, int start_column, const char* input, char* output, int output_length ) +{ + /*** + * Truncate a string based on start position and terminal width + */ + + int length, idx = 0; + + length = wcols - start_column - 1; + idx = 0; + while( idx < output_length && idx < length ) + { + output[idx] = input[idx]; + idx++; + } + /* terminate the string */ + output[idx] = 0; + + return output; +} diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..923c85e --- /dev/null +++ b/src/gui.h @@ -0,0 +1,145 @@ +/* + * gui.h: An ncurses GUI for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef GUI_H_ +#define GUI_H_ + +void nwipe_gui_free( void ); // Stop the GUI. +void nwipe_gui_init( void ); // Start the GUI. +void nwipe_gui_create_main_window( void ); // Create the main window +void nwipe_gui_create_header_window( void ); // Create the header window +void nwipe_gui_create_footer_window( const char* ); // Create the footer window and write text +void nwipe_gui_create_options_window( void ); // Create the options window +void nwipe_gui_create_stats_window( void ); // Create the stats window +void nwipe_gui_create_all_windows_on_terminal_resize( + int force_creation, + const char* footer_text ); // If terminal is resized recreate all windows + +/** + * The primary user interface. Allows the user to + * change options and specify the devices to be wiped. + * + * @parameter count The number of contexts in the array. + * @parameter c An array of device contexts. + * + * @modifies c[].select Sets the select flag according to user input. + * @modifies options Sets program options according to to user input. + * + */ +void nwipe_gui_select( int count, nwipe_context_t** c ); // Select devices to wipe. +void* nwipe_gui_status( void* ptr ); // Update operation progress. +void nwipe_gui_method( void ); // Change the method option. +void nwipe_gui_options( void ); // Update the options window. +void nwipe_gui_prng( void ); // Change the prng option. +void nwipe_gui_rounds( void ); // Change the rounds option. +void nwipe_gui_verify( void ); // Change the verify option. +void nwipe_gui_noblank( void ); // Change the noblank option. +void nwipe_gui_config( void ); // Change the nwipe settings +void nwipe_gui_edit_organisation( void ); // Edit organisation performing the erasure +void nwipe_gui_organisation_business_name( const char* ); // Edit business name performing erase +void nwipe_gui_organisation_business_address( const char* ); // Edit business address performing erase +void nwipe_gui_organisation_contact_name( const char* ); // Edit business contact name +void nwipe_gui_organisation_contact_phone( const char* ); // Edit business contact phone +void nwipe_gui_organisation_op_tech_name( const char* ); // Edit the name of the operator/technician +void nwipe_gui_list( int, char* window_title, char**, int* ); +void nwipe_gui_add_customer( void ); // Add new customer +void nwipe_gui_add_customer_name( char* ); // Add new customer name +void nwipe_gui_add_customer_address( char* ); // Add new customer address +void nwipe_gui_add_customer_contact_name( char* ); // Add new customer contact name +void nwipe_gui_add_customer_contact_phone( char* ); // Add new customer contact phone +int nwipe_gui_yes_no_footer( void ); // Change footer to yes no + +/** nwipe_gui_preview_org_customer( int ) + * Display a editable preview of organisation, customer and date/time + * + * @param int mode 0 = use prior to drive selection + * 1 = use in config menus + * The different modes simply change the text in the footer menu and in the case + * of mode 0 enable the A key which means accept & display drive selection. + */ +void nwipe_gui_preview_org_customer( int ); // Preview window for wipe organisation and customer + +void nwipe_gui_set_system_year( void ); // Set the systems current year +void nwipe_gui_set_system_month( void ); // Set the systems month +void nwipe_gui_set_system_day( void ); // Set the system day of the month +void nwipe_gui_set_system_hour( void ); // Set the system hour +void nwipe_gui_set_system_minute( void ); // Set the system minute + +/** + * Truncate a string based on start position and terminal width + * + * @parameter wcols Width of window, obtained from getmaxyx(..) + * @parameter start_column Start column where the string starts + * @parameter input_string The string to be truncated if necessary + * @parameter ouput_string The possibly truncated string + * @parameter ouput_string_length Max length of output string + * @Return returns a pointer to the output string + */ +char* str_truncate( int, int, const char*, char*, int ); // Truncate string based on start column and terminal width + +/** + * Set system date and time + * + * @parameter void + * @Return void + */ +void nwipe_gui_set_date_time( void ); + +int spinner( nwipe_context_t** ptr, int ); // Return the next spinner character +void temp1_flash( nwipe_context_t* ); // toggles term1_flash_status, which flashes the temperature + +/** + * If the current drive temperature is available, print it to the GUI. + * This function determines if the drive temperature limits are specified & + * if so, whether the temperature should be printed as white text on blue if the + * drive is operating within it's temperature specification or red text on + * blue if the drive has exceeded the critical high temperature or black on + * blue if the drive has dropped below the drives minimum temperature specification. + * @param pointer to the drive context + */ +void wprintw_temperature( nwipe_context_t* ); + +int compute_stats( void* ptr ); +void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_done, time_t speedring_now ); + +#define NOMENCLATURE_RESULT_STR_SIZE 8 + +/* Note Do not change unless you understand how this value affects keyboard response and screen refresh when + * the drive selection screen is displayed. (prior to wipe starting). */ +#define GETCH_BLOCK_MS 250 /* millisecond block time for getch() */ + +/* Note The value of 1 (100ms) is the ideal speed for screen refresh during a wipe, a value of 2 is noticeably slower, + * don't change unless you understand how this value affects keyboard responsiveness and speed of screen stats/spinner + * updating */ +#define GETCH_GUI_STATS_UPDATE_MS 1 /* 1 * 100 = 1/10/sec = millisecond block time for gui stats screen updates */ + +#define FIELD_LENGTH 256 + +#define MAX_TITLE_LENGTH 76 + +#define YES 1 +#define NO 0 + +#define SHOWING_PRIOR_TO_DRIVE_SELECTION 0 +#define SHOWING_IN_CONFIG_MENUS 1 + +#endif /* GUI_H_ */ diff --git a/src/hddtemp_scsi/get_scsi_temp.c b/src/hddtemp_scsi/get_scsi_temp.c new file mode 100644 index 0000000..e36d357 --- /dev/null +++ b/src/hddtemp_scsi/get_scsi_temp.c @@ -0,0 +1,159 @@ +/* + * get_scsi_temp.c: functions that populate the drive temperature variables + * in SCSI/SAS drives context structure. + * Routines from hddtemp are used here. + * + * Author: Gerold Gruber <Gerold.Gruber@edv2g.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +//#define _LARGEFILE64_SOURCE +//#define _FILE_OFFSET_BITS 64 +#define _BSD_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <dirent.h> +#include <assert.h> + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "device.h" +#include "prng.h" +#include "options.h" +#include "device.h" +#include "logging.h" +#include "temperature.h" +#include "miscellaneous.h" +#include "hddtemp.h" +#include "scsi.h" + +int scsi_get_temperature( struct disk * ); + +int nwipe_init_scsi_temperature( nwipe_context_t* c ) +{ + +/* dsk anlegen, malloc */ + struct disk *dsk = (struct disk *) malloc(sizeof(struct disk)); + + /* Check the allocation. */ + if( !dsk ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to get memory for disk struct for %s", + c->device_name ); + exit( 1 ) ; + } + + assert(dsk); + + memset(dsk, 0, sizeof(*dsk)); + + /* save the dsk pointer for later use */ + c->templ_disk = dsk; + + /* initialize */ + dsk->drive = c->device_name; + dsk->type = BUS_SCSI; /* we know this as we are only called in this case */ + + errno = 0; + dsk->errormsg[0] = '\0'; + if( (dsk->fd = open(dsk->drive, O_RDONLY | O_NONBLOCK)) < 0) { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, "open: %s\n", strerror(errno)); + dsk->type = ERROR; + return 1; + } + + // sg_logs -t <device> + if( scsi_get_temperature( dsk ) == GETTEMP_SUCCESS ) + { + c->temp1_input = dsk->value; + c->temp1_crit = dsk->refvalue; + c->temp1_lcrit = -40; /* just to give it a value with some kind of sense */ + c->temp1_highest = dsk->value; + c->temp1_lowest = dsk->value; + c->temp1_max = dsk->refvalue - 5; /* seems to be kind of useful */ + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Can not read SCSI temperature for %s, %s", + dsk->drive, dsk->errormsg ); + close( dsk->fd ); + free( dsk ); + c->templ_disk = NULL; + return 1; + } + + return 0; +} + + +int nwipe_get_scsi_temperature( nwipe_context_t* c ) +{ + struct disk *dsk; + + dsk = c->templ_disk; + + if( c->templ_disk != NULL && c->templ_disk->fd != -1 ) + { + if( scsi_get_temperature( dsk ) == GETTEMP_SUCCESS ) + { + c->temp1_input = dsk->value; + +/* not at all of interest */ + if( c->temp1_input > c->temp1_highest ) + { + c->temp1_highest = c->temp1_input; + } + if( c->temp1_input < c->temp1_lowest ) + { + c->temp1_lowest = c->temp1_input; + } + +/* end not at all of interest ;-) */ + + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "Could not read SCSI temperature for %s, %s", + dsk->drive, dsk->errormsg ); + return 2; + } + } + else + { + nwipe_log( NWIPE_LOG_INFO, "no SCSI temperature reading for %s", dsk->drive ); + return 1; + } + return 0; +} + +void nwipe_shut_scsi_temperature( nwipe_context_t* c ) +{ + if( c->templ_disk->fd != -1 ) + { + close( c->templ_disk->fd ); + } + if( c->templ_disk != NULL ) + { + free( c->templ_disk ); + } + + return; +} diff --git a/src/hddtemp_scsi/hddtemp.h b/src/hddtemp_scsi/hddtemp.h new file mode 100644 index 0000000..6565991 --- /dev/null +++ b/src/hddtemp_scsi/hddtemp.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __HDDTEMP_H__ +#define __HDDTEMP_H__ + +#include <time.h> +// #include "db.h" + +//#ifdef ARCH_I386 +//typedef unsigned short u16; +//#endif +#include <linux/types.h> +typedef __u16 u16; + +#define MAX_ERRORMSG_SIZE 128 +#define DEFAULT_ATTRIBUTE_ID 194 + +#define F_to_C(val) (int)(((double)(val)-32.0)/1.8) +#define C_to_F(val) (int)(((double)(val)*(double)1.8) + (double)32.0) + +enum e_bustype { ERROR = 0, BUS_UNKNOWN, BUS_SATA, BUS_ATA, BUS_SCSI, BUS_TYPE_MAX }; + +#define GETTEMP_SUCCESS 0 +#define GETTEMP_ERROR 1 +#define GETTEMP_NOT_APPLICABLE 2 +#define GETTEMP_UNKNOWN 3 +#define GETTEMP_GUESS 4 +#define GETTEMP_KNOWN 5 +#define GETTEMP_NOSENSOR 6 +#define GETTEMP_DRIVE_SLEEP 7 + +enum e_powermode { + PWM_UNKNOWN, + PWM_ACTIVE, + PWM_SLEEPING, + PWM_STANDBY +}; + + +struct disk { + struct disk * next; + + int fd; + const char * drive; + const char * model; + enum e_bustype type; + int value; /* the drive's temperature */ + int refvalue; /* aka trip temperature */ + struct harddrive_entry * db_entry; + + char errormsg[MAX_ERRORMSG_SIZE]; +// enum e_gettemp ret; + int ret; + time_t last_time; +}; + +struct bustype { + char *name; + int (*probe)(int); + const char *(*model)(int); + enum e_gettemp (*get_temperature)(struct disk *); +}; + + +extern struct bustype * bus[BUS_TYPE_MAX]; +extern char errormsg[MAX_ERRORMSG_SIZE]; +extern int tcp_daemon, debug, quiet, wakeup, af_hint; +extern char separator; +extern long portnum, syslog_interval; +extern char * listen_addr; + +int value_to_unit(struct disk *dsk); +char get_unit(struct disk *dsk); + +#endif diff --git a/src/hddtemp_scsi/scsi.c b/src/hddtemp_scsi/scsi.c new file mode 100644 index 0000000..ab00ad6 --- /dev/null +++ b/src/hddtemp_scsi/scsi.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* + * Adapted from a patch sended by : Frederic LOCHON <lochon@roulaise.net> + */ +/* + * Adapted for use with nwipe by : Gerold Gruber <Gerold.Gruber@edv2g.de> + */ + +// Include file generated by ./configure +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// Gettext includes +#if ENABLE_NLS +#include <libintl.h> +#define _(String) gettext (String) +#else +#define _(String) (String) +#endif + +// Standard includes +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <scsi/scsi.h> + +// Application specific includes +#include "scsicmds.h" +#include "hddtemp.h" + +int scsi_get_temperature(struct disk *dsk) { + int i; + int tempPage = 0; + unsigned char buffer[1024]; + + /* + on triche un peu + we cheat a little and do not really read form drivedb as SCSI disks are not included there + original code omitted as there is no need for it in the context of nwipe + */ + + /* + Enable SMART + */ + if (scsi_smartDEXCPTdisable(dsk->fd) != 0) { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, "%s", strerror(errno)); + close(dsk->fd); + dsk->fd = -1; + return GETTEMP_ERROR; + } + + /* + Temp. capable + */ + if (scsi_logsense(dsk->fd , SUPPORT_LOG_PAGES, buffer, sizeof(buffer)) != 0) { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("log sense failed : %s"), strerror(errno)); + close(dsk->fd); + dsk->fd = -1; + return GETTEMP_ERROR; + } + + for ( i = 4; i < buffer[3] + LOGPAGEHDRSIZE ; i++) { + if (buffer[i] == TEMPERATURE_PAGE) { + tempPage = 1; + break; + } + } + + if(tempPage) { + /* + get temperature (from scsiGetTemp (scsicmd.c)) + */ + if (scsi_logsense(dsk->fd , TEMPERATURE_PAGE, buffer, sizeof(buffer)) != 0) { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("log sense failed : %s"), strerror(errno)); + close(dsk->fd); + dsk->fd = -1; + return GETTEMP_ERROR; + } + + if( (int)buffer[7] == 2 ) /* PARAMETER LENGTH */ + { + dsk->value = buffer[9]; + } + else + { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("parameter length unexpected: %d"), (int)buffer[7] ); + return GETTEMP_UNKNOWN; + } + dsk->refvalue = buffer[15]; + if( (int)buffer[13] == 2 ) /* PARAMETER LENGTH */ + { + dsk->refvalue = buffer[15]; + } + else + { + snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("parameter ref length unexpected: %d"), (int)buffer[13] ); + return GETTEMP_UNKNOWN; + } + return GETTEMP_SUCCESS; + } else { + return GETTEMP_NOSENSOR; + } +} diff --git a/src/hddtemp_scsi/scsi.h b/src/hddtemp_scsi/scsi.h new file mode 100644 index 0000000..c349e37 --- /dev/null +++ b/src/hddtemp_scsi/scsi.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SCSIC_H_ +#define SCSIC_H_ + +extern struct bustype scsi_bus; + +#endif diff --git a/src/hddtemp_scsi/scsicmds.c b/src/hddtemp_scsi/scsicmds.c new file mode 100644 index 0000000..3449203 --- /dev/null +++ b/src/hddtemp_scsi/scsicmds.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// Include file generated by ./configure +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// Gettext includes +#if ENABLE_NLS +#include <libintl.h> +#define _(String) gettext (String) +#else +#define _(String) (String) +#endif + +// Standard includes +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <scsi/scsi.h> +#include <scsi/sg.h> +#include <scsi/scsi_ioctl.h> + +// Application specific includes +#include "scsicmds.h" + +static void scsi_fixstring(unsigned char *s, int bytecount) +{ + unsigned char *p; + unsigned char *end; + + p = s; + end = s + bytecount; + + /* strip leading blanks */ + while (s != end && *s == ' ') + ++s; + /* compress internal blanks and strip trailing blanks */ + while (s != end && *s) { + if (*s++ != ' ' || (s != end && *s && *s != ' ')) + *p++ = *(s-1); + } + /* wipe out trailing garbage */ + while (p != end) + *p++ = '\0'; +} + +int scsi_SG_IO(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, unsigned char *sense, unsigned char sense_len, int dxfer_direction) { + struct sg_io_hdr io_hdr; + + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmdp = cdb; + io_hdr.cmd_len = cdb_len; + io_hdr.dxfer_len = buffer_len; + io_hdr.dxferp = buffer; + io_hdr.mx_sb_len = sense_len; + io_hdr.sbp = sense; + io_hdr.dxfer_direction = dxfer_direction; + io_hdr.timeout = 3000; /* 3 seconds should be ample */ + + return ioctl(device, SG_IO, &io_hdr); +} + +int scsi_SEND_COMMAND(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction) +{ + unsigned char buf[2048]; + unsigned int inbufsize, outbufsize, ret; + + switch(dxfer_direction) { + case SG_DXFER_FROM_DEV: + inbufsize = 0; + outbufsize = buffer_len; + break; + case SG_DXFER_TO_DEV: + inbufsize = buffer_len; + outbufsize = 0; + break; + default: + inbufsize = 0; + outbufsize = 0; + break; + } + memcpy(buf, &inbufsize , sizeof(inbufsize)); + memcpy(buf + sizeof(inbufsize), &outbufsize , sizeof(outbufsize)); + memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize), cdb, cdb_len); + memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize) + cdb_len, buffer, buffer_len); + + ret = ioctl(device, SCSI_IOCTL_SEND_COMMAND, buf); + + memcpy(buffer, buf + sizeof(inbufsize) + sizeof(outbufsize), buffer_len); + + return ret; +} + +int scsi_command(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction) +{ + static int SG_IO_supported = -1; + int ret; + + if (SG_IO_supported == 1) + return scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction); + else if (SG_IO_supported == 0) + return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction); + else { + ret = scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction); + if (ret == 0) { + SG_IO_supported = 1; + return ret; + } else { + SG_IO_supported = 0; + return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction); + } + } +} + +int scsi_inquiry(int device, unsigned char *buffer) +{ + unsigned char cdb[6]; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = INQUIRY; + cdb[4] = 36; /* should be 36 for unsafe devices (like USB mass storage stuff) + * otherwise they can lock up! SPC sections 7.4 and 8.6 */ + + if (scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_FROM_DEV) != 0) + return 1; + else { + scsi_fixstring(buffer + 8, 24); + return 0; + } +} + +int scsi_modesense(int device, unsigned char pagenum, unsigned char *buffer, int buffer_len) { + unsigned char cdb[6]; + int ret; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = MODE_SENSE; + cdb[2] = pagenum; + cdb[4] = 0xff; + + ret = scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV); + if (ret == 0) { + if ((buffer[3] + 5) > buffer[0]) /* response length too short */ + return -1; + } + return ret; +} + +int scsi_modeselect(int device, char *buffer) { + unsigned char cdb[6]; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = MODE_SELECT; + cdb[1] = 0x11; + cdb[4] = buffer[0] + 1; + + memset(buffer, 0, 12); + buffer[3] = 0x08; + buffer[10] = 0x02; + buffer[12] &= 0x3f; + + return scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_TO_DEV); +} + +int scsi_logsense(int device, int pagenum, unsigned char *buffer, int buffer_len) { + unsigned char cdb[10]; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = LOG_SENSE; + cdb[2] = 0x40 | pagenum; + cdb[7] = 0x04; + + return scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV); +} + +int scsi_smartsupport(int device) { + unsigned char buf[255]; + + if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0) + return 0; + else + return (buf[14] & 0x08) == 0; +} + +int scsi_smartDEXCPTdisable(int device) { + unsigned char buf[255]; + + if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0) + return 1; + + if (buf[14] & 0x08) { + buf[14] &= 0xf7; + buf[15] = 0x04; + return scsi_modeselect (device, buf); + } + else + return 0; +} + diff --git a/src/hddtemp_scsi/scsicmds.h b/src/hddtemp_scsi/scsicmds.h new file mode 100644 index 0000000..46cd268 --- /dev/null +++ b/src/hddtemp_scsi/scsicmds.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef SCSICMDS_H_ +#define SCSICMDS_H_ + +#define SUPPORT_LOG_PAGES 0x00 +#define TEMPERATURE_PAGE 0x0d +#define EXCEPTIONS_CONTROL_PAGE 0x1c +#define LOGPAGEHDRSIZE 4 + +int scsi_SG_IO(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, unsigned char *sense, unsigned char sense_len, int dxfer_direction); +int scsi_inquiry(int device, unsigned char *buffer); +int scsi_modesense(int device, unsigned char pagenum, unsigned char *buffer, int buffer_len); +int scsi_modeselect(int device, char *buffer); +int scsi_logsense(int device, int pagenum, unsigned char *buffer, int buffer_len); +int scsi_smartsupport(int device); +int scsi_smartDEXCPTdisable(int device); + +#endif diff --git a/src/hpa_dco.c b/src/hpa_dco.c new file mode 100644 index 0000000..160d454 --- /dev/null +++ b/src/hpa_dco.c @@ -0,0 +1,858 @@ +/* + * hpa_dco.c: functions that handle the host protected area (HPA) and + * device configuration overlay (DCO) + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <scsi/sg.h> +#include <scsi/scsi_ioctl.h> +#include "nwipe.h" +#include "context.h" +#include "version.h" +#include "method.h" +#include "logging.h" +#include "options.h" +#include "hpa_dco.h" +#include "miscellaneous.h" + +/* This function makes use of both the hdparm program to determine HPA/DCO status and we also access + * the device configuration overlay identify data structure via the sg driver with ioctl calls. + * I would prefer to write these functions without any reliance on hdparm however for the time being + * we will utilize both methods. However, I don't like doing it like this as a change in formatted + * output of hdparm could potentially break HPA/DCO detection requiring a fix. Time permitting I may + * come back to this and fully implement it without any reliance on hdparm. + */ + +int hpa_dco_status( nwipe_context_t* ptr ) +{ + nwipe_context_t* c; + c = ptr; + + int r; // A result buffer. + int set_return_value; + int exit_status; + int hpa_line_found; + int dco_line_found; + + FILE* fp; + char path_hdparm_cmd1_get_hpa[] = "hdparm --verbose -N"; + char path_hdparm_cmd2_get_hpa[] = "/sbin/hdparm --verbose -N"; + char path_hdparm_cmd3_get_hpa[] = "/usr/bin/hdparm --verbose -N"; + + char path_hdparm_cmd4_get_dco[] = "hdparm --verbose --dco-identify"; + char path_hdparm_cmd5_get_dco[] = "/sbin/hdparm --verbose --dco-identify"; + char path_hdparm_cmd6_get_dco[] = "/usr/bin/hdparm --verbose --dco-identify"; + + char pipe_std_err[] = "2>&1"; + + char result[512]; + + u64 nwipe_dco_real_max_sectors; + + char* p; + + /* Use the longest of the 'path_hdparm_cmd.....' strings above to + *determine size in the strings below + */ + char hdparm_cmd_get_hpa[sizeof( path_hdparm_cmd3_get_hpa ) + sizeof( c->device_name ) + sizeof( pipe_std_err )]; + char hdparm_cmd_get_dco[sizeof( path_hdparm_cmd6_get_dco ) + sizeof( c->device_name ) + sizeof( pipe_std_err )]; + + /* Initialise return value */ + set_return_value = 0; + + /* Construct the command including path to the binary if required, I do it like this to cope + * with distros that don't setup their paths in a standard way or maybe don't even define a + * path. By doing this we avoid the 'No such file or directory' message you would otherwise + * get on some distros. -> debian SID + */ + + if( system( "which hdparm > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/hdparm > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/hdparm > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "hdparm command not found." ); + nwipe_log( NWIPE_LOG_WARNING, + "Required by nwipe for HPA/DCO detection & correction and ATA secure erase." ); + nwipe_log( NWIPE_LOG_WARNING, "** Please install hdparm **\n" ); + cleanup(); + exit( 1 ); + } + else + { + snprintf( hdparm_cmd_get_hpa, + sizeof( hdparm_cmd_get_hpa ), + "%s %s %s\n", + path_hdparm_cmd3_get_hpa, + c->device_name, + pipe_std_err ); + snprintf( hdparm_cmd_get_dco, + sizeof( hdparm_cmd_get_dco ), + "%s %s %s\n", + path_hdparm_cmd6_get_dco, + c->device_name, + pipe_std_err ); + } + } + else + { + snprintf( hdparm_cmd_get_hpa, + sizeof( hdparm_cmd_get_hpa ), + "%s %s %s\n", + path_hdparm_cmd2_get_hpa, + c->device_name, + pipe_std_err ); + snprintf( hdparm_cmd_get_dco, + sizeof( hdparm_cmd_get_dco ), + "%s %s %s\n", + path_hdparm_cmd5_get_dco, + c->device_name, + pipe_std_err ); + } + } + else + { + snprintf( hdparm_cmd_get_hpa, + sizeof( hdparm_cmd_get_hpa ), + "%s %s %s\n", + path_hdparm_cmd1_get_hpa, + c->device_name, + pipe_std_err ); + snprintf( hdparm_cmd_get_dco, + sizeof( hdparm_cmd_get_dco ), + "%s %s %s\n", + path_hdparm_cmd4_get_dco, + c->device_name, + pipe_std_err ); + } + + /* Initialise the results buffer, so we don't some how inadvertently process a past result */ + memset( result, 0, sizeof( result ) ); + + if( hdparm_cmd_get_hpa[0] != 0 ) + { + + fp = popen( hdparm_cmd_get_hpa, "r" ); + + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "hpa_dco_status: Failed to create stream to %s", hdparm_cmd_get_hpa ); + + set_return_value = 1; + } + + if( fp != NULL ) + { + hpa_line_found = 0; //* init */ + + /* Read the output a line at a time - output it. */ + while( fgets( result, sizeof( result ) - 1, fp ) != NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "%s \n%s", hdparm_cmd_get_hpa, result ); + } + + /* Change the output of hdparm to lower case and search using lower case strings, to try + * to avoid minor changes in case in hdparm's output from breaking HPA/DCO detection + */ + strlower( result ); // convert the result to lower case + + /* Scan the hdparm results for HPA is disabled + */ + if( strstr( result, "sg_io: bad/missing sense data" ) != 0 ) + { + c->HPA_status = HPA_UNKNOWN; + nwipe_log( NWIPE_LOG_ERROR, "SG_IO bad/missing sense data %s", hdparm_cmd_get_hpa ); + break; + } + else + { + if( strstr( result, "hpa is disabled" ) != 0 ) + { + c->HPA_status = HPA_DISABLED; + + nwipe_log( NWIPE_LOG_DEBUG, + "hdparm says the host protected area is disabled on %s but this information may or " + "may not be correct, as occurs when you get a SG_IO error and 0/1 sectors and it " + "says HPA is enabled. Further checks are conducted below..", + c->device_name ); + hpa_line_found = 1; + break; + } + else + { + if( strstr( result, "hpa is enabled" ) != 0 ) + { + c->HPA_status = HPA_ENABLED; + nwipe_log( NWIPE_LOG_DEBUG, + "hdparm says the host protected area is enabled on %s but this information may " + "or may not be correct, as occurs when you get a SG_IO error and 0/1 sectors " + "and it says HPA is enabled. Further checks are conducted below..", + c->device_name ); + hpa_line_found = 1; + break; + } + else + { + if( strstr( result, "accessible max address disabled" ) != 0 ) + { + c->HPA_status = HPA_DISABLED; + nwipe_log( NWIPE_LOG_DEBUG, + "hdparm says the accessible max address disabled on %s" + "this means that there are no hidden sectors, " + "", + c->device_name ); + hpa_line_found = 1; + break; + } + else + { + if( strstr( result, "accessible max address enabled" ) != 0 ) + { + c->HPA_status = HPA_ENABLED; + nwipe_log( NWIPE_LOG_DEBUG, + "hdparm says the accessible max address enabled on %s" + "this means that there are hidden sectors", + c->device_name ); + hpa_line_found = 1; + break; + } + else + { + if( strstr( result, "invalid" ) != 0 ) + { + nwipe_log( + NWIPE_LOG_WARNING, + "hdparm reports invalid output, sector information may be invalid, buggy " + "drive firmware on %s?", + c->device_name ); + // We'll assume the HPA values are in the string as we may be able to extract + // something meaningful + hpa_line_found = 1; + break; + } + } + } + } + } + } + } + + /* if the HPA line was found then process the line, + * extracting the 'hpa set' and 'hpa real' values. + */ + if( hpa_line_found == 1 ) + { + /* Extract the 'HPA set' value, the first value in the line and convert + * to binary and save in context */ + + nwipe_log( NWIPE_LOG_INFO, "HPA: %s on %s", result, c->device_name ); + + c->HPA_reported_set = str_ascii_number_to_ll( result ); + + /* Check whether the number was too large or no number found & log */ + if( c->HPA_reported_set == -1 ) + { + nwipe_log( NWIPE_LOG_INFO, "HPA_set_value: HPA set value too large on %s", c->device_name ); + c->HPA_reported_set = 0; + } + else + { + if( c->HPA_reported_set == -2 ) + { + nwipe_log( NWIPE_LOG_INFO, "HPA_set_value: No HPA set value found %s", c->device_name ); + c->HPA_reported_set = 0; + } + } + + /* Extract the 'HPA real' value, the second value in the line and convert + * to binary and save in context, this is a little more difficult as sometimes + * a odd value is returned so instead of nnnnn/nnnnn you get nnnnnn/1(nnnnnn). + * So first we scan for a open bracket '(' then if there is no '(' we then start the + * search immediately after the '/'. + */ + if( ( p = strstr( result, "(" ) ) ) + { + c->HPA_reported_real = str_ascii_number_to_ll( p + 1 ); + } + else + { + if( ( p = strstr( result, "/" ) ) ) + { + c->HPA_reported_real = str_ascii_number_to_ll( p + 1 ); + } + } + + /* Check whether the number was too large or no number found & log */ + if( c->HPA_reported_real == -1 ) + { + nwipe_log( NWIPE_LOG_INFO, "HPA_set_value: HPA real value too large on %s", c->device_name ); + c->HPA_reported_real = 0; + } + else + { + if( c->HPA_reported_real == -2 ) + { + nwipe_log( NWIPE_LOG_INFO, "HPA_set_value: No HPA real value found %s", c->device_name ); + c->HPA_reported_real = 0; + } + } + + nwipe_log( NWIPE_LOG_INFO, + "HPA values %lli / %lli on %s", + c->HPA_reported_set, + c->HPA_reported_real, + c->device_name ); + } + else + { + c->HPA_status = HPA_UNKNOWN; + nwipe_log( NWIPE_LOG_WARNING, + "[UNKNOWN] We can't find the HPA line, has hdparm ouput unknown/changed? %s", + c->device_name ); + } + + /* close */ + r = pclose( fp ); + if( r > 0 ) + { + exit_status = WEXITSTATUS( r ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_WARNING, + "hpa_dco_status(): hdparm failed, \"%s\" exit status = %u", + hdparm_cmd_get_hpa, + exit_status ); + } + + if( exit_status == 127 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Installing hdparm is mandatory !" ); + set_return_value = 2; + if( nwipe_options.nousb ) + { + return set_return_value; + } + } + } + } + } + + /* Initialise the results buffer again, so we don't + * some how inadvertently process a past result */ + memset( result, 0, sizeof( result ) ); + + /* ----------------------------------------------- + * Run the dco identify command and determine the + * real max sectors, store it in the drive context + * for comparison against the hpa reported drive + * size values. + */ + + dco_line_found = 0; + + if( hdparm_cmd_get_dco[0] != 0 ) + { + + fp = popen( hdparm_cmd_get_dco, "r" ); + + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "hpa_dco_status: Failed to create stream to %s", hdparm_cmd_get_dco ); + + set_return_value = 1; + } + + if( fp != NULL ) + { + /* Read the output a line at a time - output it. */ + while( fgets( result, sizeof( result ) - 1, fp ) != NULL ) + { + /* Change the output of hdparm to lower case and search using lower case strings, to try + * to avoid minor changes in case in hdparm's output from breaking HPA/DCO detection */ + strlower( result ); + + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "%s \n%s", hdparm_cmd_get_dco, result ); + } + + if( strstr( result, "real max sectors" ) != 0 ) + { + /* extract the real max sectors, convert to binary and store in drive context */ + dco_line_found = 1; + break; + } + } + /* DCO line found, now process it */ + if( dco_line_found == 1 ) + { + c->DCO_reported_real_max_sectors = str_ascii_number_to_ll( result ); + nwipe_log( NWIPE_LOG_INFO, + "hdparm:DCO Real max sectors reported as %lli on %s", + c->DCO_reported_real_max_sectors, + c->device_name ); + + /* Validate the real max sectors to detect extreme or impossible + * values, so the size must be greater than zero but less than + * 200TB (429496729600 sectors). As its 2023 and the largest drive + * available is 20TB I wonder if somebody in the future will be looking + * at this and thinking, yep we need to increase that value... and I'm + * wondering what year that will be. This validation is necessary all + * because of a bug in hdparm v9.60 (and maybe other versions) which + * produced wildly inaccurate values, often negative. + */ + if( c->DCO_reported_real_max_sectors > 0 && c->DCO_reported_real_max_sectors < 429496729600 ) + { + nwipe_log( NWIPE_LOG_INFO, + "NWipe: DCO Real max sectors reported as %lli on %s", + c->DCO_reported_real_max_sectors, + c->device_name ); + } + else + { + /* Call nwipe's own low level function to retrieve the drive configuration + * overlay and retrieve the real max sectors. We may remove reliance on hdparm + * if nwipes own low level drive access code works well. + */ + c->DCO_reported_real_max_sectors = nwipe_read_dco_real_max_sectors( c->device_name ); + + /* Check our real max sectors function is returning sensible data too */ + if( c->DCO_reported_real_max_sectors > 0 && c->DCO_reported_real_max_sectors < 429496729600 ) + { + nwipe_log( NWIPE_LOG_INFO, + "NWipe: DCO Real max sectors reported as %lli on %s", + c->DCO_reported_real_max_sectors, + c->device_name ); + } + else + { + c->DCO_reported_real_max_sectors = 0; + nwipe_log( NWIPE_LOG_INFO, "DCO Real max sectors not found" ); + } + } + } + else + { + c->DCO_reported_real_max_sectors = 0; + nwipe_log( NWIPE_LOG_INFO, "DCO Real max sectors not found" ); + } + + nwipe_log( + NWIPE_LOG_INFO, + "libata: apparent max sectors reported as %lli with sector size as %i/%i (logical/physical) on %s", + c->device_size_in_sectors, + c->device_sector_size, // logical + c->device_phys_sector_size, // physical + c->device_name ); + + /* close */ + r = pclose( fp ); + if( r > 0 ) + { + exit_status = WEXITSTATUS( r ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_WARNING, + "hpa_dco_status(): hdparm failed, \"%s\" exit status = %u", + hdparm_cmd_get_dco, + exit_status ); + } + + if( exit_status == 127 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Installing hdparm is mandatory !" ); + set_return_value = 2; + if( nwipe_options.nousb ) + { + return set_return_value; + } + } + } + } + } + + /* Compare the results of hdparm -N (HPA set / HPA real) + * and hdparm --dco-identidy (real max sectors). All three + * values may be different or perhaps 'HPA set' and 'HPA real' are + * different and 'HPA real' matches 'real max sectors'. + * + * A perfect HPA disabled result would be where all three + * values are the same. It can then be considered that the + * HPA is disabled. + * + * If 'HPA set' and 'HPA real' are different then it + * can be considered that HPA is enabled, assuming 'HPA set' + * and 'HPA real' are not 0/1 which occurs when a SG_IO error + * occurs. That also is checked for as it often indicates a + * poor USB device that does not have ATA pass through support. + * + * However we also need to consider that more recent drives + * no longer support HPA/DCO such as the Seagate ST10000NM0016, + * ST4000NM0033 and ST1000DM003. If you try to issue those drives + * with the ATA command code 0xB1 (device configuration overlay) + * you will get a generic illegal request in the returned sense data. + * + * One other thing to note, we use HPA enabled/disabled to mean + * hidden area detected or not detected, this could be caused by + * either the dco-setmax being issued or Np, either way an area + * of the disc can be hidden. From the user interface we just call + * it a HPA/DCO hidden area detected (or not) which is more + * meaningful than just saying HDA enabled or disabled and a user + * not familiar with the term HPA or DCO not understanding why a + * HDA being detected could be significant. + */ + + /* Determine, based on the values of 'HPA set', 'HPA real and + * 'real max sectors' whether we set the HPA flag as HPA_DISABLED, + * HPA_ENABLED, HPA_UNKNOWN or HPA_NOT_APPLICABLE. The HPA flag + * will be displayed in the GUI and on the certificate and is + * used to determine whether to reset the HPA. + * + */ + + /* WARNING temp assignments WARNING + * s=28,r=28,rm=0 + * + */ +#if 0 + c->HPA_reported_set = 10; + c->HPA_reported_real = 28; + c->DCO_reported_real_max_sectors = 0; + + c->HPA_reported_set = 28; + c->HPA_reported_real = 28; + c->DCO_reported_real_max_sectors = 0; + + c->HPA_reported_set = 1000; + c->HPA_reported_real = 2048; + c->DCO_reported_real_max_sectors = 2048; +#endif + + /* If any of the HPA or DCO values are larger than the apparent size then HPA is enabled. */ + if( /*c->HPA_reported_set > c->device_size_in_sectors || */ c->HPA_reported_real > c->device_size_in_512byte_sectors + || c->DCO_reported_real_max_sectors > c->device_size_in_512byte_sectors ) + { + c->HPA_status = HPA_ENABLED; + nwipe_log( NWIPE_LOG_WARNING, " *********************************" ); + nwipe_log( NWIPE_LOG_WARNING, " *** HIDDEN SECTORS DETECTED ! *** on %s", c->device_name ); + nwipe_log( NWIPE_LOG_WARNING, " *********************************" ); + } + else + { + /* This occurs when a SG_IO error occurs with USB devices that don't support ATA pass + * through */ + if( c->HPA_reported_set == 0 && c->HPA_reported_real == 0 && c->DCO_reported_real_max_sectors <= 1 ) + { + c->HPA_status = HPA_UNKNOWN; + if( c->device_bus == NWIPE_DEVICE_USB ) + { + nwipe_log( NWIPE_LOG_WARNING, + "HIDDEN SECTORS INDETERMINATE! on %s, Some USB adapters & memory sticks don't support " + "ATA pass through", + c->device_name ); + } + } + else + { + c->HPA_status = HPA_DISABLED; + nwipe_log( NWIPE_LOG_INFO, "No hidden sectors on %s", c->device_name ); + } + } + + c->DCO_reported_real_max_size = c->DCO_reported_real_max_sectors * c->device_sector_size; + + nwipe_dco_real_max_sectors = nwipe_read_dco_real_max_sectors( c->device_name ); + + /* Analyse all the variations to produce the final real max bytes which takes into + * account drives that don't support DCO or HPA. This result is used in the PDF + * creation functions. + */ + + if( c->device_type == NWIPE_DEVICE_NVME || c->device_type == NWIPE_DEVICE_VIRT + || c->HPA_status == HPA_NOT_APPLICABLE ) + { + c->Calculated_real_max_size_in_bytes = c->device_size; + } + else + { + /* If the DCO is reporting a real max sectors > the apparent size + * as reported by libata then that is what we will use as the real disc size + */ + if( c->DCO_reported_real_max_size > c->device_size_in_512byte_sectors ) + { + c->Calculated_real_max_size_in_bytes = c->DCO_reported_real_max_sectors * c->device_sector_size; + } + else + { + /* If HPA is enabled and DCO real max sectors did not exist, then we have to assume - c->HPA_reported_real + * is the value we need, however if that is zero, then c->HPA_reported_set and if that is zero then + * c->device_size as reported by libata + */ + if( c->HPA_reported_real > c->device_size_in_512byte_sectors ) + { + c->Calculated_real_max_size_in_bytes = c->HPA_reported_real * c->device_sector_size; + } + else + { + if( c->HPA_reported_set > c->device_size_in_512byte_sectors ) + { + c->Calculated_real_max_size_in_bytes = c->HPA_reported_set * c->device_sector_size; + } + else + { + c->Calculated_real_max_size_in_bytes = c->device_size; + } + } + } + } + + /* ------------------------------------------------------------------- + * create two variables for later use by the PDF creation function + * based on real max sectors and calculated real max size in bytes. + * + * DCO_reported_real_max_size = real max sectors * sector size = bytes + * DCO_reported_real_max_size_text = human readable string, i.e 1TB etc. + */ + + Determine_C_B_nomenclature( + c->DCO_reported_real_max_size, c->DCO_reported_real_max_size_text, NWIPE_DEVICE_SIZE_TXT_LENGTH ); + Determine_C_B_nomenclature( + c->Calculated_real_max_size_in_bytes, c->Calculated_real_max_size_in_bytes_text, NWIPE_DEVICE_SIZE_TXT_LENGTH ); + + /* ---------------------------------------------------------------------------------- + * Determine the size of the HPA if it's enabled and store the results in the context + */ + + if( c->HPA_status == HPA_ENABLED ) + { + if( c->Calculated_real_max_size_in_bytes != c->device_size ) + { + c->HPA_sectors = + ( (u64) ( c->Calculated_real_max_size_in_bytes - c->device_size ) / c->device_sector_size ); + } + else + { + c->HPA_sectors = 0; + } + + /* Convert the size to a human readable format and save in context */ + Determine_C_B_nomenclature( c->HPA_sectors, c->HPA_size_text, NWIPE_DEVICE_SIZE_TXT_LENGTH ); + } + else + { + /* HPA not enabled so initialise these values */ + c->HPA_sectors = 0; + c->HPA_size_text[0] = 0; + } + + nwipe_log( NWIPE_LOG_DEBUG, + "c->Calculated_real_max_size_in_bytes=%lli, c->device_size=%lli, c->device_sector_size=%lli, " + "c->DCO_reported_real_max_size=%lli, c->DCO_reported_real_max_sectors=%lli, c->HPA_sectors=%lli, " + "c->HPA_reported_set=%lli, c->HPA_reported_real=%lli, c->device_type=%i, " + "libata:c->device_size_in_sectors=%lli ", + "libata:c->device_size_in_512byte_sectors=%lli ", + c->Calculated_real_max_size_in_bytes, + c->device_size, + c->device_sector_size, + c->DCO_reported_real_max_size, + c->DCO_reported_real_max_sectors, + c->HPA_sectors, + c->HPA_reported_set, + c->HPA_reported_real, + c->device_type, + c->device_size_in_sectors, + c->device_size_in_512byte_sectors ); + + return set_return_value; +} + +u64 nwipe_read_dco_real_max_sectors( char* device ) +{ + /* This function sends a device configuration overlay identify command 0xB1 (dco-identify) + * to the drive and extracts the real max sectors. The value is incremented by 1 and + * then returned. We rely upon this function to determine real max sectors as there + * is a bug in hdparm 9.60, including possibly earlier or later versions but which is + * fixed in 9.65, that returns a incorrect (negative) value + * for some drives that are possibly over a certain size. + */ + + /* TODO Add checks in case of failure, especially with recent drives that may not + * support drive configuration overlay commands. + */ + +#define LBA_SIZE 512 +#define CMD_LEN 16 +#define BLOCK_MAX 65535 +#define LBA_MAX ( 1 << 30 ) +#define SENSE_BUFFER_SIZE 32 + + u64 nwipe_real_max_sectors; + + /* This command issues command 0xb1 (dco-identify) 15th byte */ + unsigned char cmd_blk[CMD_LEN] = { 0x85, 0x08, 0x0e, 0x00, 0xc2, 0, 0x01, 0, 0, 0, 0, 0, 0, 0x40, 0xb1, 0 }; + + sg_io_hdr_t io_hdr; + unsigned char buffer[LBA_SIZE]; // Received data block + unsigned char sense_buffer[SENSE_BUFFER_SIZE]; // Sense data + + /* three characters represent one byte of sense data, i.e + * two characters and a space "01 AE 67" + */ + char sense_buffer_hex[( SENSE_BUFFER_SIZE * 3 ) + 1]; + + int i, i2; // index + int fd; // file descripter + + if( ( fd = open( device, O_RDWR ) ) < 0 ) + { + /* Unable to open device */ + return -1; + } + + /****************************************** + * Initialise the sg header for reading the + * device configuration overlay identify data + */ + memset( &io_hdr, 0, sizeof( sg_io_hdr_t ) ); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof( cmd_blk ); + io_hdr.mx_sb_len = sizeof( sense_buffer ); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = LBA_SIZE; + io_hdr.dxferp = buffer; + io_hdr.cmdp = cmd_blk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; + + if( ioctl( fd, SG_IO, &io_hdr ) < 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "IOCTL command failed retrieving DCO" ); + i2 = 0; + for( i = 0, i2 = 0; i < SENSE_BUFFER_SIZE; i++, i2 += 3 ) + { + /* IOCTL returned an error */ + snprintf( &sense_buffer_hex[i2], sizeof( sense_buffer_hex ), "%02x ", sense_buffer[i] ); + } + sense_buffer_hex[i2] = 0; // terminate string + nwipe_log( NWIPE_LOG_DEBUG, "Sense buffer from failed DCO identify cmd:%s", sense_buffer_hex ); + return -2; + } + + /* Close the device */ + close( fd ); + + /*************************************************************** + * Extract the real max sectors from the returned 512 byte block. + * Assuming the first word/byte is 0. We extract the bytes & switch + * the endian. Words 3-6(bytes 6-13) contain the max sector address + */ + nwipe_real_max_sectors = (u64) ( (u64) buffer[13] << 56 ) | ( (u64) buffer[12] << 48 ) | ( (u64) buffer[11] << 40 ) + | ( (u64) buffer[10] << 32 ) | ( (u64) buffer[9] << 24 ) | ( (u64) buffer[8] << 16 ) | ( (u64) buffer[7] << 8 ) + | buffer[6]; + + /* Don't really understand this but hdparm adds 1 to + * the real max sectors too, counting zero as sector? + * but only increment if it's already greater than zero + */ + if( nwipe_real_max_sectors > 0 ) + { + nwipe_real_max_sectors++; + } + + nwipe_log( + NWIPE_LOG_INFO, "func:nwipe_read_dco_real_max_sectors(), DCO real max sectors = %lli", nwipe_real_max_sectors ); + + return nwipe_real_max_sectors; +} + +int ascii2binary_array( char* input, unsigned char* output_bin, int bin_size ) +{ + /* Converts ascii sense data output by hdparm to binary. + * Scans a character string that contains hexadecimal ascii data, ignores spaces + * and extracts and converts the hexadecimal ascii data to binary and places in a array. + * Typically for dco_identify sense data the bin size will be 512 bytes but for error + * sense data this would be 32 bytes. + */ + int idx_in; // Index into ascii input string + int idx_out; // Index into the binary output array + int byte_count; // Counts which 4 bit value we are working on + char upper4bits; + char lower4bits; + + byte_count = 0; + idx_in = 0; + idx_out = 0; + while( input[idx_in] != 0 ) + { + if( input[idx_in] >= '0' && input[idx_in] <= '9' ) + { + if( byte_count == 0 ) + { + upper4bits = input[idx_in] - 0x30; + byte_count++; + } + else + { + lower4bits = input[idx_in] - 0x30; + output_bin[idx_out++] = ( upper4bits << 4 ) | ( lower4bits ); + byte_count = 0; + + if( idx_out >= bin_size ) + { + return 0; // output array full. + } + } + } + else + { + if( input[idx_in] >= 'a' && input[idx_in] <= 'f' ) + { + if( byte_count == 0 ) + { + upper4bits = input[idx_in] - 0x57; + byte_count++; + } + else + { + lower4bits = input[idx_in] - 0x57; + output_bin[idx_out++] = ( upper4bits << 4 ) | ( lower4bits ); + byte_count = 0; + + if( idx_out >= bin_size ) + { + return 0; // output array full. + } + } + } + } + idx_in++; // next byte in the input string + } + return 0; +} diff --git a/src/hpa_dco.h b/src/hpa_dco.h new file mode 100644 index 0000000..edbae65 --- /dev/null +++ b/src/hpa_dco.h @@ -0,0 +1,43 @@ +/*. + * hpa_dco.h: The header file for the host protected area (HPA) and + * disk configuration overlay routines + * + * Copyright https://github.com/PartialVolume/shredos.x86_64 + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef HPA_DCO_H_ +#define HPA_DCO_H_ + +#define HPA_DISABLED 0 +#define HPA_ENABLED 1 +#define HPA_UNKNOWN 2 +#define HPA_NOT_APPLICABLE 3 +#define HPA_NOT_SUPPORTED_BY_DRIVE 4 + +int hpa_dco_status( nwipe_context_t* ); + +u64 nwipe_read_dco_real_max_sectors( char* ); + +typedef struct nwipe_sense_dco_identify_t_t_ +{ + /* This struct contains some of the decoded fields from the sense data after a + * ATA 0xB1 device configuration overlay command has been issued. We mainly + * use it to decode the real max sectors + */ + u64 dco_real_max_sectors; +} nwipe_sense_dco_identify_t_t_; + +#endif /* HPA_DCO_H_ */ diff --git a/src/isaac_rand/isaac64.c b/src/isaac_rand/isaac64.c new file mode 100644 index 0000000..3e4203b --- /dev/null +++ b/src/isaac_rand/isaac64.c @@ -0,0 +1,119 @@ +/* +------------------------------------------------------------------------------ +isaac64.c: My random number generator for 64-bit machines. +By Bob Jenkins, 1996. Public Domain. +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +#include "isaac_standard.h" +#endif +#ifndef ISAAC64 +#include "isaac64.h" +#endif + + +#define ind(mm,x) (*(ub8 *)((ub1 *)(mm) + ((x) & ((RANDSIZ-1)<<3)))) +#define rngstep(mix,a,b,mm,m,m2,r,x) \ +{ \ + x = *m; \ + a = (mix) + *(m2++); \ + *(m++) = y = ind(mm,x) + a + b; \ + *(r++) = b = ind(mm,y>>RANDSIZL) + x; \ +} + +void isaac64(rand64ctx *ctx) +{ + register ub8 a,b,x,y,*m,*mm,*m2,*r,*mend; + mm=ctx->mm; r=ctx->randrsl; + a = ctx->aa; b = ctx->bb + (++ctx->cc); + for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; ) + { + rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x); + rngstep( a^(a>>5) , a, b, mm, m, m2, r, x); + rngstep( a^(a<<12) , a, b, mm, m, m2, r, x); + rngstep( a^(a>>33) , a, b, mm, m, m2, r, x); + } + for (m2 = mm; m2<mend; ) + { + rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x); + rngstep( a^(a>>5) , a, b, mm, m, m2, r, x); + rngstep( a^(a<<12) , a, b, mm, m, m2, r, x); + rngstep( a^(a>>33) , a, b, mm, m, m2, r, x); + } + ctx->bb = b; ctx->aa = a; +} + +#define mix(a,b,c,d,e,f,g,h) \ +{ \ + a-=e; f^=h>>9; h+=a; \ + b-=f; g^=a<<9; a+=b; \ + c-=g; h^=b>>23; b+=c; \ + d-=h; a^=c<<15; c+=d; \ + e-=a; b^=d>>14; d+=e; \ + f-=b; c^=e<<20; e+=f; \ + g-=c; d^=f>>17; f+=g; \ + h-=d; e^=g<<14; g+=h; \ +} + +void rand64init(rand64ctx *ctx, word flag) +{ + word i; + ub8 a,b,c,d,e,f,g,h; + ub8 *mm, *randrsl; + ctx->aa = ctx->bb = ctx->cc = (ub8)0; + mm=ctx->mm; + randrsl=ctx->randrsl; + a=b=c=d=e=f=g=h=0x9e3779b97f4a7c13LL; /* the golden ratio */ + + for (i=0; i<4; ++i) /* scramble it */ + { + mix(a,b,c,d,e,f,g,h); + } + + for (i=0; i<RANDSIZ; i+=8) /* fill in mm[] with messy stuff */ + { + if (flag) /* use all the information in the seed */ + { + a+=randrsl[i ]; b+=randrsl[i+1]; c+=randrsl[i+2]; d+=randrsl[i+3]; + e+=randrsl[i+4]; f+=randrsl[i+5]; g+=randrsl[i+6]; h+=randrsl[i+7]; + } + mix(a,b,c,d,e,f,g,h); + mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d; + mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h; + } + + if (flag) + { /* do a second pass to make all of the seed affect all of mm */ + for (i=0; i<RANDSIZ; i+=8) + { + a+=mm[i ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3]; + e+=mm[i+4]; f+=mm[i+5]; g+=mm[i+6]; h+=mm[i+7]; + mix(a,b,c,d,e,f,g,h); + mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d; + mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h; + } + } + + isaac64(ctx); /* fill in the first set of results */ + ctx->randcnt=RANDSIZ; /* prepare to use the first set of results */ +} + +#ifdef NEVER +int main() +{ + ub8 i,j; + rand64ctx ctx; + ctx.aa=ctx.bb=ctx.cc=(ub8)0; + for (i=0; i<RANDSIZ; ++i) ctx.mm[i]=(ub8)0; + rand64init(&ctx, TRUE); + for (i=0; i<2; ++i) + { + isaac64(&ctx); + for (j=0; j<RANDSIZ; ++j) + { + printf("%.8lx%.8lx",(ub4)(ctx.randrsl[j]>>32),(ub4)ctx.randrsl[j]); + if ((j&3)==3) printf("\n"); + } + } +} +#endif diff --git a/src/isaac_rand/isaac64.h b/src/isaac_rand/isaac64.h new file mode 100644 index 0000000..e2ab55b --- /dev/null +++ b/src/isaac_rand/isaac64.h @@ -0,0 +1,41 @@ +/* +------------------------------------------------------------------------------ +isaac64.h: definitions for a random number generator +Bob Jenkins, 1996, Public Domain +------------------------------------------------------------------------------ +*/ +#ifndef ISAAC64 +#define ISAAC64 + +#include "isaac_standard.h" + +struct rand64ctx +{ + ub8 randrsl[RANDSIZ], randcnt; + ub8 mm[RANDSIZ]; + ub8 aa, bb, cc; +}; +typedef struct rand64ctx rand64ctx; + +/* +------------------------------------------------------------------------------ + If (flag==TRUE), then use the contents of randrsl[0..255] as the seed. +------------------------------------------------------------------------------ +*/ +void rand64init(rand64ctx *r, word flag); + +void isaac64(rand64ctx *ctx); + + +/* +------------------------------------------------------------------------------ + Call rand64() to retrieve a single 64-bit random value +------------------------------------------------------------------------------ +*/ +#define isaac64_rand() \ + (!(r)->randcnt-- ? \ + (isaac64(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->>randcnt]) : \ + (r)->randrsl[(r)->randcnt]) + +#endif /* ISAAC64 */ + diff --git a/src/isaac_rand/isaac_rand.c b/src/isaac_rand/isaac_rand.c new file mode 100644 index 0000000..c9220e0 --- /dev/null +++ b/src/isaac_rand/isaac_rand.c @@ -0,0 +1,169 @@ +/* +------------------------------------------------------------------------------ +rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain. +MODIFIED: + 960327: Creation (addition of randinit, really) + 970719: use context, not global variables, for internal state + 980324: added main (ifdef'ed out), also rearranged randinit() + 010626: Note that this is public domain +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +#include "isaac_standard.h" +#endif +#ifndef RAND +#include "isaac_rand.h" +#endif + + +#define ind(mm,x) (*(ub4 *)((ub1 *)(mm) + ((x) & ((RANDSIZ-1)<<2)))) +#define rngstep(mix,a,b,mm,m,m2,r,x) \ +{ \ + x = *m; \ + a = (a^(mix)) + *(m2++); \ + *(m++) = y = ind(mm,x) + a + b; \ + *(r++) = b = ind(mm,y>>RANDSIZL) + x; \ +} + +void isaac(ctx) +randctx *ctx; +{ + register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend; + mm=ctx->randmem; + r=ctx->randrsl; + a = ctx->randa; + b = ctx->randb + (++ctx->randc); + for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; ) + { + rngstep( a<<13, a, b, mm, m, m2, r, x); + rngstep( a>>6 , a, b, mm, m, m2, r, x); + rngstep( a<<2 , a, b, mm, m, m2, r, x); + rngstep( a>>16, a, b, mm, m, m2, r, x); + } + for (m2 = mm; m2<mend; ) + { + rngstep( a<<13, a, b, mm, m, m2, r, x); + rngstep( a>>6 , a, b, mm, m, m2, r, x); + rngstep( a<<2 , a, b, mm, m, m2, r, x); + rngstep( a>>16, a, b, mm, m, m2, r, x); + } + ctx->randb = b; ctx->randa = a; +} + + +#define mix(a,b,c,d,e,f,g,h) \ +{ \ + a^=b<<11; d+=a; b+=c; \ + b^=c>>2; e+=b; c+=d; \ + c^=d<<8; f+=c; d+=e; \ + d^=e>>16; g+=d; e+=f; \ + e^=f<<10; h+=e; f+=g; \ + f^=g>>4; a+=f; g+=h; \ + g^=h<<8; b+=g; h+=a; \ + h^=a>>9; c+=h; a+=b; \ +} + +/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */ +void randinit(ctx, flag) +randctx *ctx; +word flag; +{ + word i; + ub4 a,b,c,d,e,f,g,h; + ub4 *m,*r; + ctx->randa = ctx->randb = ctx->randc = 0; + m=ctx->randmem; + r=ctx->randrsl; + a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */ + + for (i=0; i<4; ++i) /* scramble it */ + { + mix(a,b,c,d,e,f,g,h); + } + + if (flag) + { + /* initialize using the contents of r[] as the seed */ + for (i=0; i<RANDSIZ; i+=8) + { + a+=r[i ]; + b+=r[i+1]; + c+=r[i+2]; + d+=r[i+3]; + e+=r[i+4]; + f+=r[i+5]; + g+=r[i+6]; + h+=r[i+7]; + mix(a,b,c,d,e,f,g,h); + m[i ]=a; + m[i+1]=b; + m[i+2]=c; + m[i+3]=d; + m[i+4]=e; + m[i+5]=f; + m[i+6]=g; + m[i+7]=h; + } + /* do a second pass to make all of the seed affect all of m */ + for (i=0; i<RANDSIZ; i+=8) + { + a+=m[i ]; + b+=m[i+1]; + c+=m[i+2]; + d+=m[i+3]; + e+=m[i+4]; + f+=m[i+5]; + g+=m[i+6]; + h+=m[i+7]; + mix(a,b,c,d,e,f,g,h); + m[i ]=a; + m[i+1]=b; + m[i+2]=c; + m[i+3]=d; + m[i+4]=e; + m[i+5]=f; + m[i+6]=g; + m[i+7]=h; + } + } + else + { + /* fill in m[] with messy stuff */ + for (i=0; i<RANDSIZ; i+=8) + { + mix(a,b,c,d,e,f,g,h); + m[i ]=a; + m[i+1]=b; + m[i+2]=c; + m[i+3]=d; + m[i+4]=e; + m[i+5]=f; + m[i+6]=g; + m[i+7]=h; + } + } + + isaac(ctx); /* fill in the first set of results */ + ctx->randcnt=RANDSIZ; /* prepare to use the first set of results */ +} + + +#ifdef NEVER +int main() +{ + ub4 i,j; + randctx ctx; + ctx.randa=ctx.randb=ctx.randc=(ub4)0; + for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0; + randinit(&ctx, TRUE); + for (i=0; i<2; ++i) + { + isaac(&ctx); + for (j=0; j<256; ++j) + { + printf("%.8lx",ctx.randrsl[j]); + if ((j&7)==7) printf("\n"); + } + } +} +#endif diff --git a/src/isaac_rand/isaac_rand.h b/src/isaac_rand/isaac_rand.h new file mode 100644 index 0000000..167a2fd --- /dev/null +++ b/src/isaac_rand/isaac_rand.h @@ -0,0 +1,52 @@ +/* +------------------------------------------------------------------------------ +rand.h: definitions for a random number generator +By Bob Jenkins, 1996, Public Domain +MODIFIED: + 960327: Creation (addition of randinit, really) + 970719: use context, not global variables, for internal state + 980324: renamed seed to flag + 980605: recommend RANDSIZL=4 for noncryptography. + 010626: note this is public domain +------------------------------------------------------------------------------ +*/ +#ifndef RAND +#define RAND + +#include "isaac_standard.h" + +/* context of random number generator */ +struct randctx +{ + ub4 randcnt; + ub4 randrsl[RANDSIZ]; + ub4 randmem[RANDSIZ]; + ub4 randa; + ub4 randb; + ub4 randc; +}; +typedef struct randctx randctx; + +/* +------------------------------------------------------------------------------ + If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed. +------------------------------------------------------------------------------ +*/ +void randinit(/*_ randctx *r, word flag _*/); + +void isaac(/*_ randctx *r _*/); + + +/* +------------------------------------------------------------------------------ + Call rand(/o_ randctx *r _o/) to retrieve a single 32-bit random value +------------------------------------------------------------------------------ +*/ +#define isaac_rand(r) \ + (!(r)->randcnt-- ? \ + (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \ + (r)->randrsl[(r)->randcnt]) + +#endif /* RAND */ + + diff --git a/src/isaac_rand/isaac_standard.h b/src/isaac_rand/isaac_standard.h new file mode 100644 index 0000000..5323d3f --- /dev/null +++ b/src/isaac_rand/isaac_standard.h @@ -0,0 +1,60 @@ +/* +------------------------------------------------------------------------------ +Standard definitions and types, Bob Jenkins +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +# define STANDARD +# ifndef STDIO +# include <stdio.h> +# define STDIO +# endif +# ifndef STDDEF +# include <stddef.h> +# define STDDEF +# endif +typedef unsigned long long ub8; +#define UB8MAXVAL 0xffffffffffffffffLL +#define UB8BITS 64 +typedef signed long long sb8; +#define SB8MAXVAL 0x7fffffffffffffffLL +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +#define UB4MAXVAL 0xffffffff +typedef signed long int sb4; +#define UB4BITS 32 +#define SB4MAXVAL 0x7fffffff +typedef unsigned short int ub2; +#define UB2MAXVAL 0xffff +#define UB2BITS 16 +typedef signed short int sb2; +#define SB2MAXVAL 0x7fff +typedef unsigned char ub1; +#define UB1MAXVAL 0xff +#define UB1BITS 8 +typedef signed char sb1; /* signed 1-byte quantities */ +#define SB1MAXVAL 0x7f +typedef int word; /* fastest type available */ + +#define bis(target,mask) ((target) |= (mask)) +#define bic(target,mask) ((target) &= ~(mask)) +#define bit(target,mask) ((target) & (mask)) +#ifndef min +# define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif /* min */ +#ifndef max +# define max(a,b) (((a)<(b)) ? (b) : (a)) +#endif /* max */ +#ifndef align +# define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1))) +#endif /* align */ +#ifndef abs +# define abs(a) (((a)>0) ? (a) : -(a)) +#endif +#define TRUE 1 +#define FALSE 0 +#define SUCCESS 0 /* 1 on VAX */ + +#define RANDSIZL (8) /* I recommend 8 for crypto, 4 for simulations */ +#define RANDSIZ (1<<RANDSIZL) + +#endif /* STANDARD */ diff --git a/src/logging.c b/src/logging.c new file mode 100644 index 0000000..ca103ef --- /dev/null +++ b/src/logging.c @@ -0,0 +1,959 @@ +/* + * logging.c: Logging facilities for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "stdarg.h" +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "logging.h" +#include "create_pdf.h" +#include "miscellaneous.h" + +/* Global array to hold log values to print when logging to STDOUT */ +char** log_lines; +int log_current_element = 0; +int log_elements_allocated = 0; +int log_elements_displayed = 0; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void nwipe_log( nwipe_log_t level, const char* format, ... ) +{ + /** + * Writes a message to the program log file. + * + */ + + extern int terminate_signal; + extern int user_abort; + + char** result; + char* malloc_result; + char message_buffer[MAX_LOG_LINE_CHARS * sizeof( char )]; + int chars_written; + + int message_buffer_length; + int r; /* result buffer */ + + /* A time buffer. */ + time_t t; + + /* A pointer to the system time struct. */ + struct tm* p; + r = pthread_mutex_lock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_lock failed. Code %i \n", r ); + return; + } + + /* Get the current time. */ + t = time( NULL ); + p = localtime( &t ); + + /* Position of writing to current log string */ + int line_current_pos = 0; + + /* initialise characters written */ + chars_written = 0; + + /* Only log messages with the debug label if the command line --verbose + * options has been specified, otherwise just return + */ + if( level == NWIPE_LOG_DEBUG && nwipe_options.verbose == 0 ) + { + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + } + return; + } + + /* Print the date. The rc script uses the same format. */ + if( level != NWIPE_LOG_NOTIMESTAMP ) + { + chars_written = snprintf( message_buffer, + MAX_LOG_LINE_CHARS, + "[%i/%02i/%02i %02i:%02i:%02i] ", + 1900 + p->tm_year, + 1 + p->tm_mon, + p->tm_mday, + p->tm_hour, + p->tm_min, + p->tm_sec ); + } + + /* + * Has the end of the buffer been reached ?, snprintf returns the number of characters that would have been + * written if MAX_LOG_LINE_CHARS had not been reached, it does not return the actual characters written in + * all circumstances, hence why we need to check whether it's greater than MAX_LOG_LINE_CHARS and if so set + * it to MAX_LOG_LINE_CHARS, preventing a buffer overrun further down this function. + */ + + /* check if there was a complete failure to write this part of the message, in which case return */ + if( chars_written < 0 ) + { + fprintf( stderr, "nwipe_log: snprintf error when writing log line to memory.\n" ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + return; + } + } + else + { + if( ( line_current_pos + chars_written ) > MAX_LOG_LINE_CHARS ) + { + fprintf( stderr, + "nwipe_log: Warning! The log line has been truncated as it exceeded %i characters\n", + MAX_LOG_LINE_CHARS ); + line_current_pos = MAX_LOG_LINE_CHARS; + } + else + { + line_current_pos += chars_written; + } + } + + if( line_current_pos < MAX_LOG_LINE_CHARS ) + { + switch( level ) + { + + case NWIPE_LOG_NONE: + case NWIPE_LOG_NOTIMESTAMP: + /* Do nothing. */ + break; + + /* NOTE! The debug labels, i.e. debug, info, notice etc should be left padded with spaces, in order + * to maintain column alignment. Pad a label to achieve the length of whatever the longest label happens + * to be. Important to know if you are thinking of adding another label. + */ + + case NWIPE_LOG_DEBUG: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " debug: " ); + break; + + case NWIPE_LOG_INFO: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " info: " ); + break; + + case NWIPE_LOG_NOTICE: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " notice: " ); + break; + + case NWIPE_LOG_WARNING: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, "warning: " ); + break; + + case NWIPE_LOG_ERROR: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " error: " ); + break; + + case NWIPE_LOG_FATAL: + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " fatal: " ); + break; + + case NWIPE_LOG_SANITY: + /* TODO: Request that the user report the log. */ + chars_written = + snprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, " sanity: " ); + break; + + default: + chars_written = snprintf( + message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos, "level %i: ", level ); + } + + /* + * Has the end of the buffer been reached ? + */ + if( chars_written < 0 ) + { + fprintf( stderr, "nwipe_log: snprintf error when writing log line to memory.\n" ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + return; + } + } + else + { + if( ( line_current_pos + chars_written ) > MAX_LOG_LINE_CHARS ) + { + fprintf( stderr, + "nwipe_log: Warning! The log line has been truncated as it exceeded %i characters\n", + MAX_LOG_LINE_CHARS ); + line_current_pos = MAX_LOG_LINE_CHARS; + } + else + { + line_current_pos += chars_written; + } + } + } + + /* The variable argument pointer. */ + va_list ap; + + /* Fetch the argument list. */ + va_start( ap, format ); + + /* Print the event. */ + if( line_current_pos < MAX_LOG_LINE_CHARS ) + { + chars_written = + vsnprintf( message_buffer + line_current_pos, MAX_LOG_LINE_CHARS - line_current_pos - 1, format, ap ); + + if( chars_written < 0 ) + { + fprintf( stderr, "nwipe_log: snprintf error when writing log line to memory.\n" ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + va_end( ap ); + return; + } + } + else + { + if( ( line_current_pos + chars_written ) > MAX_LOG_LINE_CHARS ) + { + fprintf( stderr, + "nwipe_log: Warning! The log line has been truncated as it exceeded %i characters\n", + MAX_LOG_LINE_CHARS ); + line_current_pos = MAX_LOG_LINE_CHARS; + } + else + { + line_current_pos += chars_written; + } + } + } + + fflush( stdout ); + /* Increase the current log element pointer - we will write here, deallocation is done in cleanup() in nwipe.c */ + if( log_current_element == log_elements_allocated ) + { + log_elements_allocated++; + result = realloc( log_lines, ( log_elements_allocated ) * sizeof( char* ) ); + if( result == NULL ) + { + fprintf( stderr, "nwipe_log: realloc failed when adding a log line.\n" ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + va_end( ap ); + return; + } + } + log_lines = result; + + /* Allocate memory for storing a single log message, deallocation is done in cleanup() in nwipe.c */ + message_buffer_length = strlen( message_buffer ) * sizeof( char ); + malloc_result = malloc( ( message_buffer_length + 1 ) * sizeof( char ) ); + if( malloc_result == NULL ) + { + fprintf( stderr, "nwipe_log: malloc failed when adding a log line.\n" ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + va_end( ap ); + return; + } + } + log_lines[log_current_element] = malloc_result; + } + + strcpy( log_lines[log_current_element], message_buffer ); + + /* + if( level >= NWIPE_LOG_WARNING ) + { + vfprintf( stderr, format, ap ); + } + */ + + /* Release the argument list. */ + va_end( ap ); + + /* + if( level >= NWIPE_LOG_WARNING ) + { + fprintf( stderr, "\n" ); + } + */ + + /* The log file pointer. */ + FILE* fp; + + /* The log file descriptor. */ + int fd; + + if( nwipe_options.logfile[0] == '\0' ) + { + if( nwipe_options.nogui ) + { + printf( "%s\n", log_lines[log_current_element] ); + log_elements_displayed++; + } + } + else + { + /* Open the log file for appending. */ + fp = fopen( nwipe_options.logfile, "a" ); + + if( fp != NULL ) + { + + /* Get the file descriptor of the log file. */ + fd = fileno( fp ); + + /* Block and lock. */ + r = flock( fd, LOCK_EX ); + + if( r != 0 ) + { + perror( "nwipe_log: flock:" ); + fprintf( stderr, "nwipe_log: Unable to lock '%s' for logging.\n", nwipe_options.logfile ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + + /* Unlock the file. */ + r = flock( fd, LOCK_UN ); + fclose( fp ); + return; + } + } + + fprintf( fp, "%s\n", log_lines[log_current_element] ); + + /* Unlock the file. */ + r = flock( fd, LOCK_UN ); + + if( r != 0 ) + { + perror( "nwipe_log: flock:" ); + fprintf( stderr, "Error: Unable to unlock '%s' after logging.\n", nwipe_options.logfile ); + } + + /* Close the stream. */ + r = fclose( fp ); + + if( r != 0 ) + { + perror( "nwipe_log: fclose:" ); + fprintf( stderr, "Error: Unable to close '%s' after logging.\n", nwipe_options.logfile ); + } + } + else + { + /* Tell user we can't create/open the log and terminate nwipe */ + fprintf( + stderr, "\nERROR:Unable to create/open '%s' for logging, permissions?\n\n", nwipe_options.logfile ); + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + } + user_abort = 1; + terminate_signal = 1; + } + } + + log_current_element++; + + r = pthread_mutex_unlock( &mutex1 ); + if( r != 0 ) + { + fprintf( stderr, "nwipe_log: pthread_mutex_unlock failed. Code %i \n", r ); + } + return; + +} /* nwipe_log */ + +void nwipe_perror( int nwipe_errno, const char* f, const char* s ) +{ + /** + * Wrapper for perror(). + */ + + nwipe_log( NWIPE_LOG_ERROR, "%s: %s: %s", f, s, strerror( nwipe_errno ) ); + +} /* nwipe_perror */ + +void nwipe_log_OSinfo() +{ + /* Read /proc/version, format and write to the log */ + + FILE* fp = NULL; + char OS_info_temp[MAX_SIZE_OS_STRING + 1]; + char OS_info[MAX_SIZE_OS_STRING + 1]; + int idx; + int idx2; + int idx3; + int idx4; + + /* initialise OS_info & OS_info_temp strings */ + idx = 0; + while( idx < MAX_SIZE_OS_STRING + 1 ) + { + OS_info_temp[idx] = 0; + OS_info[idx] = 0; + idx++; + } + + /* Open a pipe to /proc/version for reading */ + fp = popen( "cat /proc/version", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "Unable to create a pipe to /proc/version" ); + return; + } + + /* Read the OS info */ + if( fgets( OS_info_temp, MAX_SIZE_OS_STRING, fp ) == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "fget failed to read /proc/version" ); + fclose( fp ); + return; + } + + /* Format the string for the log, place on multiple lines as necessary, + * column aligned, left offset with n (OS_info_Line_offset) spaces */ + idx = 0; + idx2 = 0; + idx3 = OS_info_Line_Length; + + while( OS_info_temp[idx] != 0 ) + { + while( idx2 < idx3 && idx2 < MAX_SIZE_OS_STRING ) + { + /* remove newlines from the source */ + if( OS_info_temp[idx] == 0x0a ) + { + idx++; + } + + /* copy the character */ + OS_info[idx2++] = OS_info_temp[idx++]; + } + if( OS_info_temp[idx] != 0 ) + { + OS_info[idx2++] = 0x0a; + idx4 = 0; + + /* left indent with spaces */ + while( idx4 < OS_info_Line_offset && idx2 < MAX_SIZE_OS_STRING ) + { + OS_info[idx2++] = ' '; + idx4++; + } + + /* calculate idx3 ready for next line */ + idx3 += OS_info_Line_offset + OS_info_Line_Length; + } + else + { + continue; + } + } + + nwipe_log( NWIPE_LOG_INFO, "%s", OS_info ); + fclose( fp ); + return; +} + +int nwipe_log_sysinfo() +{ + FILE* fp; + char path[256]; + int len; + int r; // A result buffer. + + /* + * Remove or add keywords to be searched, depending on what information is to + * be logged, making sure the last entry in the array is a NULL string. To remove + * an entry simply comment out the keyword with // + */ + + /* The 0/1 after the keyword determines whether the data for this + * keyword is displayed when -q (anonymize) has been specified + * by the user. An quick reminder about multi dimensional arrays, the first + * []=the keyword (0-21) including the empty string. The second [] is the + * 1 or 0 value (0 or 1). The third [] is the index value into either string. + */ + char dmidecode_keywords[][2][24] = { + { "bios-version", "1" }, + { "bios-release-date", "1" }, + { "system-manufacturer", "1" }, + { "system-product-name", "1" }, + { "system-version", "1" }, + { "system-serial-number", "0" }, + { "system-uuid", "0" }, + { "baseboard-manufacturer", "1" }, + { "baseboard-product-name", "1" }, + { "baseboard-version", "1" }, + { "baseboard-serial-number", "0" }, + { "baseboard-asset-tag", "0" }, + { "chassis-manufacturer", "1" }, + { "chassis-type", "1" }, + { "chassis-version", "1" }, + { "chassis-serial-number", "0" }, + { "chassis-asset-tag", "0" }, + { "processor-family", "1" }, + { "processor-manufacturer", "1" }, + { "processor-version", "1" }, + { "processor-frequency", "1" }, + { "", "" } // terminates the keyword array. DO NOT REMOVE + }; + + char dmidecode_command[] = "dmidecode -s %s"; + char dmidecode_command2[] = "/sbin/dmidecode -s %s"; + char dmidecode_command3[] = "/usr/bin/dmidecode -s %s"; + char* p_dmidecode_command; + + char cmd[sizeof( dmidecode_keywords ) + sizeof( dmidecode_command2 )]; + + unsigned int keywords_idx; + + keywords_idx = 0; + + p_dmidecode_command = 0; + + if( system( "which dmidecode > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/dmidecode > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/dmidecode > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "Command not found. Install dmidecode !" ); + } + else + { + p_dmidecode_command = &dmidecode_command3[0]; + } + } + else + { + p_dmidecode_command = &dmidecode_command2[0]; + } + } + else + { + p_dmidecode_command = &dmidecode_command[0]; + } + + if( p_dmidecode_command != 0 ) + { + + /* Run the dmidecode command to retrieve each dmidecode keyword, one at a time */ + while( dmidecode_keywords[keywords_idx][0][0] != 0 ) + { + sprintf( cmd, p_dmidecode_command, &dmidecode_keywords[keywords_idx][0][0] ); + fp = popen( cmd, "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_WARNING, "nwipe_log_sysinfo: Failed to create stream to %s", cmd ); + return 1; + } + /* Read the output a line at a time - output it. */ + while( fgets( path, sizeof( path ) - 1, fp ) != NULL ) + { + /* Remove any trailing return from the string, as nwipe_log automatically adds a return */ + len = strlen( path ); + if( path[len - 1] == '\n' ) + { + path[len - 1] = 0; + } + if( nwipe_options.quiet ) + { + if( *( &dmidecode_keywords[keywords_idx][1][0] ) == '0' ) + { + nwipe_log( + NWIPE_LOG_INFO, "%s = %s", &dmidecode_keywords[keywords_idx][0][0], "XXXXXXXXXXXXXXX" ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "%s = %s", &dmidecode_keywords[keywords_idx][0][0], path ); + } + } + else + { + nwipe_log( NWIPE_LOG_INFO, "%s = %s", &dmidecode_keywords[keywords_idx][0][0], path ); + } + } + /* close */ + r = pclose( fp ); + if( r > 0 ) + { + nwipe_log( NWIPE_LOG_WARNING, + "nwipe_log_sysinfo(): dmidecode failed, \"%s\" exit status = %u", + cmd, + WEXITSTATUS( r ) ); + return 1; + } + keywords_idx++; + } + } + return 0; +} + +void nwipe_log_summary( nwipe_context_t** ptr, int nwipe_selected ) +{ + /* Prints two summary tables, the first is the device pass and verification summary + * and the second is the main summary table detaining the drives, status, throughput, + * model and serial number. + * + * This function also calls the create_pdf() function that creates the PDF erasure + * report file. A page report on the success or failure of the erasure operation + */ + + int i; + int idx_src; + int idx_dest; + char device[18]; + char status[9]; + char throughput[13]; + char total_throughput_string[13]; + char summary_top_border[256]; + char summary_top_column_titles[256]; + char blank[3]; + char verify[3]; + // char duration[5]; + char duration[314]; + char model[18]; + char serial_no[NWIPE_SERIALNUMBER_LENGTH + 1]; + char exclamation_flag[2]; + int hours; + int minutes; + int seconds; + u64 total_duration_seconds; + u64 total_throughput; + nwipe_context_t** c; + c = ptr; + + exclamation_flag[0] = 0; + device[0] = 0; + status[0] = 0; + throughput[0] = 0; + summary_top_border[0] = 0; + summary_top_column_titles[0] = 0; + blank[0] = 0; + verify[0] = 0; + duration[0] = 0; + model[0] = 0; + serial_no[0] = 0; + hours = 0; + minutes = 0; + seconds = 0; + + /* A time buffer. */ + time_t t; + + /* A pointer to the system time struct. */ + struct tm* p; + + /* Nothing to do, user never started a wipe so no summary table required. */ + if( global_wipe_status == 0 ) + { + return; + } + + /* Print the pass and verifications table */ + + /* IMPORTANT: Keep maximum columns (line length) to 80 characters for use with 80x30 terminals, Shredos, ALT-F2 etc + * --------------------------------01234567890123456789012345678901234567890123456789012345678901234567890123456789-*/ + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "******************************** Error Summary *********************************" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "! Device | Pass Errors | Verifications Errors | Fdatasync I\\O Errors" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "--------------------------------------------------------------------------------" ); + + for( i = 0; i < nwipe_selected; i++ ) + { + if( c[i]->pass_errors != 0 || c[i]->verify_errors != 0 || c[i]->fsyncdata_errors != 0 ) + { + strncpy( exclamation_flag, "!", 1 ); + exclamation_flag[1] = 0; + } + else + { + strncpy( exclamation_flag, " ", 1 ); + exclamation_flag[1] = 0; + } + + /* Device name, strip any prefixed /dev/.. leaving up to 6 right justified + * characters eg " sda", prefixed with space to 6 characters, note that + * we are processing the strings right to left */ + + idx_dest = 6; + device[idx_dest--] = 0; + idx_src = strlen( c[i]->device_name ); + idx_src--; + + nwipe_strip_path( device, c[i]->device_name ); + + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "%s %s | %10llu | %10llu | %10llu", + exclamation_flag, + device, + c[i]->pass_errors, + c[i]->verify_errors, + c[i]->fsyncdata_errors ); + } + + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "********************************************************************************" ); + + /* Print the main summary table */ + + /* initialise */ + total_throughput = 0; + + /* Get the current time. */ + t = time( NULL ); + p = localtime( &t ); + /* IMPORTANT: Keep maximum columns (line length) to 80 characters for use with 80x30 terminals, Shredos, ALT-F2 etc + * --------------------------------01234567890123456789012345678901234567890123456789012345678901234567890123456789-*/ + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "********************************* Drive Status *********************************" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "! Device | Status | Thru-put | HH:MM:SS | Model/Serial Number" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "--------------------------------------------------------------------------------" ); + /* Example layout: + * "! sdb |--FAIL--| 120MB/s | 01:22:01 | WD6788.8488YNHj/ZX677888388-N " + * ); " sdc | Erased | 120MB/s | 01:25:04 | WD6784.8488JKGG/ZX677888388-N " ); " sdv | Erased | + * 120MB/s | 01:19:07 | WD6788.848HHDDR/ZX677888388-N " ); End of Example layout */ + + for( i = 0; i < nwipe_selected; i++ ) + { + /* Device name, strip any prefixed /dev/.. leaving up to 8 right justified + * characters eg " sda", prefixed with space to 8 characters, note that + * we are processing the strings right to left */ + + nwipe_strip_path( device, c[i]->device_name ); + + extern int user_abort; + + /* Any errors ? if so set the exclamation_flag and fail message, + * All status messages should be eight characters EXACTLY ! + */ + if( c[i]->pass_errors != 0 || c[i]->verify_errors != 0 || c[i]->fsyncdata_errors != 0 ) + { + strncpy( exclamation_flag, "!", 1 ); + exclamation_flag[1] = 0; + + strncpy( status, "-FAILED-", 8 ); + status[8] = 0; + + strcpy( c[i]->wipe_status_txt, "FAILED" ); // copy to context for use by certificate + } + else + { + if( c[i]->wipe_status == 0 /* && user_abort != 1 */ ) + { + strncpy( exclamation_flag, " ", 1 ); + exclamation_flag[1] = 0; + + strncpy( status, " Erased ", 8 ); + status[8] = 0; + + strcpy( c[i]->wipe_status_txt, "ERASED" ); // copy to context for use by certificate + } + else + { + if( c[i]->wipe_status == 1 && user_abort == 1 ) + { + strncpy( exclamation_flag, "!", 1 ); + exclamation_flag[1] = 0; + + strncpy( status, "UABORTED", 8 ); + status[8] = 0; + + strcpy( c[i]->wipe_status_txt, "ABORTED" ); // copy to context for use by certificate + } + else + { + /* If this ever happens, there is a bug ! */ + strncpy( exclamation_flag, " ", 1 ); + exclamation_flag[1] = 0; + + strncpy( status, "INSANITY", 8 ); + status[8] = 0; + + strcpy( c[i]->wipe_status_txt, "INSANITY" ); // copy to context for use by certificate + } + } + } + + /* Determine the size of throughput so that the correct nomenclature can be used */ + Determine_C_B_nomenclature( c[i]->throughput, throughput, 13 ); + + /* write the duration string to the drive context for later use by create_pdf() */ + snprintf( c[i]->throughput_txt, sizeof( c[i]->throughput_txt ), "%s", throughput ); + + /* Add this devices throughput to the total throughput */ + total_throughput += c[i]->throughput; + + /* Retrieve the duration of the wipe in seconds and convert to hours and minutes and seconds */ + + if( c[i]->start_time != 0 && c[i]->end_time != 0 ) + { + /* For a summary when the wipe has finished */ + c[i]->duration = difftime( c[i]->end_time, c[i]->start_time ); + } + else + { + if( c[i]->start_time != 0 && c[i]->end_time == 0 ) + { + /* For a summary in the event of a system shutdown, user abort */ + c[i]->duration = difftime( t, c[i]->start_time ); + + /* If end_time is zero, which may occur if the wipe is aborted, then set + * end_time to current time. Important to do as endtime is used by + * the PDF report function */ + c[i]->end_time = time( &t ); + } + } + + total_duration_seconds = (u64) c[i]->duration; + + /* Convert binary seconds into three binary variables, hours, minutes and seconds */ + convert_seconds_to_hours_minutes_seconds( total_duration_seconds, &hours, &minutes, &seconds ); + + /* write the duration string to the drive context for later use by create_pdf() */ + snprintf( c[i]->duration_str, sizeof( c[i]->duration_str ), "%02i:%02i:%02i", hours, minutes, seconds ); + + /* Device Model */ + strncpy( model, c[i]->device_model, 17 ); + model[17] = 0; + + /* Serial No. */ + strncpy( serial_no, c[i]->device_serial_no, NWIPE_SERIALNUMBER_LENGTH ); + serial_no[NWIPE_SERIALNUMBER_LENGTH] = 0; + model[17] = 0; + + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "%s %s |%s| %s/s | %02i:%02i:%02i | %s/%s", + exclamation_flag, + device, + status, + throughput, + hours, + minutes, + seconds, + model, + serial_no ); + + /* Create the PDF report/certificate */ + if( nwipe_options.PDF_enable == 1 ) + // if( strcmp( nwipe_options.PDFreportpath, "noPDF" ) != 0 ) + { + /* to have some progress indication. can help if there are many/slow disks */ + fprintf( stderr, "." ); + create_pdf( c[i] ); + } + } + + /* Determine the size of throughput so that the correct nomenclature can be used */ + Determine_C_B_nomenclature( total_throughput, total_throughput_string, 13 ); + + /* Blank abbreviations used in summary table B=blank, NB=no blank */ + if( nwipe_options.noblank ) + { + strcpy( blank, "NB" ); + } + else + { + strcpy( blank, "B" ); + } + + /* Verify abbreviations used in summary table */ + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + strcpy( verify, "NV" ); + break; + + case NWIPE_VERIFY_LAST: + strcpy( verify, "VL" ); + break; + + case NWIPE_VERIFY_ALL: + strcpy( verify, "VA" ); + break; + } + + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "--------------------------------------------------------------------------------" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "[%i/%02i/%02i %02i:%02i:%02i] Total Throughput %s/s, %s, %iR+%s+%s", + 1900 + p->tm_year, + 1 + p->tm_mon, + p->tm_mday, + p->tm_hour, + p->tm_min, + p->tm_sec, + total_throughput_string, + nwipe_method_label( nwipe_options.method ), + nwipe_options.rounds, + blank, + verify ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, + "********************************************************************************" ); + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "" ); + + /* Log information regarding where the PDF certificate is saved but log after the summary table so + * this information is only printed once. + */ + if( strcmp( nwipe_options.PDFreportpath, "noPDF" ) != 0 ) + { + nwipe_log( NWIPE_LOG_NOTIMESTAMP, "Creating PDF report in %s\n", nwipe_options.PDFreportpath ); + } +} diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..a8e3432 --- /dev/null +++ b/src/logging.h @@ -0,0 +1,65 @@ +/* + * logging.c: Logging facilities for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef LOGGING_H_ +#define LOGGING_H_ + +/* Maximum size of a log message */ +#define MAX_LOG_LINE_CHARS 1024 + +#define MAX_SIZE_OS_STRING 1024 /* Maximum size of acceptable OS string */ + +#define OS_info_Line_offset 31 /* OS_info line offset in log */ +#define OS_info_Line_Length 48 /* OS_info line length */ + +typedef enum nwipe_log_t_ { + NWIPE_LOG_NONE = 0, + NWIPE_LOG_DEBUG, // Output only when --verbose option used on cmd line. + NWIPE_LOG_INFO, // General Info not specifically relevant to the wipe. + NWIPE_LOG_NOTICE, // Most logging happens at this level related to wiping. + NWIPE_LOG_WARNING, // Things that the user should know about. + NWIPE_LOG_ERROR, // Non-fatal errors that result in failure. + NWIPE_LOG_FATAL, // Errors that cause the program to exit. + NWIPE_LOG_SANITY, // Programming errors. + NWIPE_LOG_NOTIMESTAMP // logs the message without the timestamp +} nwipe_log_t; + +/** + * Writes a string to the log. nwipe_log timestamps the string + * @param level the tag to display: + * NWIPE_LOG_NONE Don't display a tag + * NWIPE_LOG_DEBUG, Very verbose logging. + * NWIPE_LOG_INFO, Verbose logging. + * NWIPE_LOG_NOTICE, Most logging happens at this level. + * NWIPE_LOG_WARNING, Things that the user should know about. + * NWIPE_LOG_ERROR, Non-fatal errors that result in failure. + * NWIPE_LOG_FATAL, Errors that cause the program to exit. + * NWIPE_LOG_SANITY, Programming errors. + * NWIPE_LOG_NOTIMESTAMP logs the message without the timestamp + * @param format the string to be logged + */ +void nwipe_log( nwipe_log_t level, const char* format, ... ); + +void nwipe_perror( int nwipe_errno, const char* f, const char* s ); +void nwipe_log_OSinfo(); +int nwipe_log_sysinfo(); +void nwipe_log_summary( nwipe_context_t**, int ); // This produces the wipe status table on exit + +#endif /* LOGGING_H_ */ diff --git a/src/method.c b/src/method.c new file mode 100644 index 0000000..cbc4e23 --- /dev/null +++ b/src/method.c @@ -0,0 +1,1392 @@ +/* + * method.c: Method implementations for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* HOWTO: Add another wipe method. + * + * 1. Create a new function here and add the prototype to the 'method.h' file. + * 2. Update nwipe_method_label() appropriately. + * 3. Put the passes that you wish to run into a nwipe_pattern_t array. + * 4. Call nwipe_runmethod() with your array of patterns. + * 5. Copy-and-paste within the 'options.c' file so that the new method can be invoked. + * 6. Optionally try to plug your function into 'gui.c'. + * 7. Update the function 'calculate_round_size()' with the new method. + * + * + * WARNING: Remember to pad all pattern arrays with { 0, NULL }. + * + * WARNING: Never change nwipe_options after calling a method. + * + * NOTE: The nwipe_runmethod function appends a user selectable final blanking (zero) pass to all methods. + * + */ + +#include <stdint.h> + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "pass.h" +#include "logging.h" + +/* + * Comment Legend + * + * "method" An ordered set of patterns. + * "pattern" The magic bits that will be written to a device. + * "pass" Reading or writing one pattern to an entire device. + * "rounds" The number of times that a method will be applied to a device. + * + */ + +const char* nwipe_dod522022m_label = "DoD 5220.22-M"; +const char* nwipe_dodshort_label = "DoD Short"; +const char* nwipe_gutmann_label = "Gutmann Wipe"; +const char* nwipe_ops2_label = "RCMP TSSIT OPS-II"; +const char* nwipe_random_label = "PRNG Stream"; +const char* nwipe_zero_label = "Fill With Zeros"; +const char* nwipe_one_label = "Fill With Ones"; +const char* nwipe_verify_zero_label = "Verify Zeros (0x00)"; +const char* nwipe_verify_one_label = "Verify Ones (0xFF)"; +const char* nwipe_is5enh_label = "HMG IS5 Enhanced"; + +const char* nwipe_unknown_label = "Unknown Method (FIXME)"; + +const char* nwipe_method_label( void* method ) +{ + /** + * Returns a pointer to the name of the method function. + * + */ + + if( method == &nwipe_dod522022m ) + { + return nwipe_dod522022m_label; + } + if( method == &nwipe_dodshort ) + { + return nwipe_dodshort_label; + } + if( method == &nwipe_gutmann ) + { + return nwipe_gutmann_label; + } + if( method == &nwipe_ops2 ) + { + return nwipe_ops2_label; + } + if( method == &nwipe_random ) + { + return nwipe_random_label; + } + if( method == &nwipe_zero ) + { + return nwipe_zero_label; + } + if( method == &nwipe_one ) + { + return nwipe_one_label; + } + if( method == &nwipe_verify_zero ) + { + return nwipe_verify_zero_label; + } + if( method == &nwipe_verify_one ) + { + return nwipe_verify_one_label; + } + if( method == &nwipe_is5enh ) + { + return nwipe_is5enh_label; + } + + /* else */ + return nwipe_unknown_label; + +} /* nwipe_method_label */ + +void* nwipe_zero( void* ptr ) +{ + /** + * Fill the device with zeroes. + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* setup for a zero-fill. */ + + char zerofill[1] = { '\x00' }; + nwipe_pattern_t patterns[] = { { 1, &zerofill[0] }, // pass 1: 0s + { 0, NULL } }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_zero */ + +void* nwipe_one( void* ptr ) +{ + /** + * Fill the device with ones. + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* setup for a one-fill. */ + + char onefill[1] = { '\xFF' }; + nwipe_pattern_t patterns[] = { { 1, &onefill[0] }, // pass 1: 1s + { 0, NULL } }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_one */ + +void* nwipe_verify_zero( void* ptr ) +{ + /** + * Verify the device is full of zeros. + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* Do nothing because nwipe_runmethod appends a zero-fill. */ + nwipe_pattern_t patterns[] = { { 0, NULL } }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_verify zeros */ + +void* nwipe_verify_one( void* ptr ) +{ + /** + * Verify the device is full of ones. + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* Do nothing because nwipe_runmethod appends a zero-fill. */ + nwipe_pattern_t patterns[] = { { 0, NULL } }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_verify */ + +void* nwipe_dod522022m( void* ptr ) +{ + /** + * United States Department of Defense 5220.22-M standard wipe. + * + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* A result holder. */ + int r; + + /* Random characters. (Elements 2 and 6 are unused.) */ + char dod[7]; + + nwipe_pattern_t patterns[] = { { 1, &dod[0] }, // Pass 1: A random character. + { 1, &dod[1] }, // Pass 2: The bitwise complement of pass 1. + { -1, "" }, // Pass 3: A random stream. + { 1, &dod[3] }, // Pass 4: A random character. + { 1, &dod[4] }, // Pass 5: A random character. + { 1, &dod[5] }, // Pass 6: The bitwise complement of pass 5. + { -1, "" }, // Pass 7: A random stream. + { 0, NULL } }; + + /* Load the array with random characters. */ + r = read( c->entropy_fd, &dod, sizeof( dod ) ); + + /* NOTE: Only the random data in dod[0], dod[3], and dod[4] is actually used. */ + + /* Check the result. */ + if( r != sizeof( dod ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_dod522022m_label ); + + /* Ensure a negative return. */ + if( r < 0 ) + { + c->result = r; + return NULL; + } + else + { + c->result = -1; + return NULL; + } + } + + /* Pass 2 is the bitwise complement of Pass 1. */ + dod[1] = ~dod[0]; + + /* Pass 4 is the bitwise complement of Pass 3. */ + dod[5] = ~dod[4]; + + /* Run the DoD 5220.22-M method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_dod522022m */ + +void* nwipe_dodshort( void* ptr ) +{ + /** + * United States Department of Defense 5220.22-M short wipe. + * This method is comprised of passes 1,2,7 from the standard wipe. + * + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* A result holder. */ + int r; + + /* Random characters. (Element 3 is unused.) */ + char dod[3]; + + nwipe_pattern_t patterns[] = { { 1, &dod[0] }, // Pass 1: A random character. + { 1, &dod[1] }, // Pass 2: The bitwise complement of pass 1. + { -1, "" }, // Pass 3: A random stream. + { 0, NULL } }; + + /* Load the array with random characters. */ + r = read( c->entropy_fd, &dod, sizeof( dod ) ); + + /* NOTE: Only the random data in dod[0] is actually used. */ + + /* Check the result. */ + if( r != sizeof( dod ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_dodshort_label ); + + /* Ensure a negative return. */ + if( r < 0 ) + { + c->result = r; + return NULL; + } + else + { + c->result = -1; + return NULL; + } + } + + /* Pass 2 is the bitwise complement of Pass 1. */ + dod[1] = ~dod[0]; + + /* Run the DoD 5220.022-M short method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_dodshort */ + +void* nwipe_gutmann( void* ptr ) +{ + /** + * Peter Gutmann's wipe. + * + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* Define the Gutmann method. */ + nwipe_pattern_t book[] = { { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { 3, "\x55\x55\x55" }, // Static pass: 0x555555 01010101 01010101 01010101 + { 3, "\xAA\xAA\xAA" }, // Static pass: 0XAAAAAA 10101010 10101010 10101010 + { 3, "\x92\x49\x24" }, // Static pass: 0x924924 10010010 01001001 00100100 + { 3, "\x49\x24\x92" }, // Static pass: 0x492492 01001001 00100100 10010010 + { 3, "\x24\x92\x49" }, // Static pass: 0x249249 00100100 10010010 01001001 + { 3, "\x00\x00\x00" }, // Static pass: 0x000000 00000000 00000000 00000000 + { 3, "\x11\x11\x11" }, // Static pass: 0x111111 00010001 00010001 00010001 + { 3, "\x22\x22\x22" }, // Static pass: 0x222222 00100010 00100010 00100010 + { 3, "\x33\x33\x33" }, // Static pass: 0x333333 00110011 00110011 00110011 + { 3, "\x44\x44\x44" }, // Static pass: 0x444444 01000100 01000100 01000100 + { 3, "\x55\x55\x55" }, // Static pass: 0x555555 01010101 01010101 01010101 + { 3, "\x66\x66\x66" }, // Static pass: 0x666666 01100110 01100110 01100110 + { 3, "\x77\x77\x77" }, // Static pass: 0x777777 01110111 01110111 01110111 + { 3, "\x88\x88\x88" }, // Static pass: 0x888888 10001000 10001000 10001000 + { 3, "\x99\x99\x99" }, // Static pass: 0x999999 10011001 10011001 10011001 + { 3, "\xAA\xAA\xAA" }, // Static pass: 0xAAAAAA 10101010 10101010 10101010 + { 3, "\xBB\xBB\xBB" }, // Static pass: 0xBBBBBB 10111011 10111011 10111011 + { 3, "\xCC\xCC\xCC" }, // Static pass: 0xCCCCCC 11001100 11001100 11001100 + { 3, "\xDD\xDD\xDD" }, // Static pass: 0xDDDDDD 11011101 11011101 11011101 + { 3, "\xEE\xEE\xEE" }, // Static pass: 0xEEEEEE 11101110 11101110 11101110 + { 3, "\xFF\xFF\xFF" }, // Static pass: 0xFFFFFF 11111111 11111111 11111111 + { 3, "\x92\x49\x24" }, // Static pass: 0x924924 10010010 01001001 00100100 + { 3, "\x49\x24\x92" }, // Static pass: 0x492492 01001001 00100100 10010010 + { 3, "\x24\x92\x49" }, // Static pass: 0x249249 00100100 10010010 01001001 + { 3, "\x6D\xB6\xDB" }, // Static pass: 0x6DB6DB 01101101 10110110 11011011 + { 3, "\xB6\xDB\x6D" }, // Static pass: 0xB6DB6D 10110110 11011011 01101101 + { 3, "\xDB\x6D\xB6" }, // Static pass: 0XDB6DB6 11011011 01101101 10110110 + { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { -1, "" }, // Random pass. + { 0, NULL } }; + + /* Put the book array into this array in random order. */ + nwipe_pattern_t patterns[36]; + + /* An entropy buffer. */ + u16 s[27]; + + /* Load the array with random characters. */ + ssize_t r = read( c->entropy_fd, &s, sizeof( s ) ); + if( r != sizeof( s ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_gutmann_label ); + + /* Ensure a negative return. */ + if( r < 0 ) + { + c->result = r; + return NULL; + } + else + { + c->result = -1; + return NULL; + } + } + + // First 4 random passes + for( int i = 0; i <= 3; ++i ) + { + patterns[i] = book[i]; + } + // Middle 27 passes in random order + for( int i = 26; i >= 0; --i ) + { + /* Get a random integer that is less than the first index 'i'. */ + int n = (int) ( (double) ( s[i] ) / (double) ( 0x0000FFFF + 1 ) * (double) ( i + 1 ) ); + + /* Initialize the secondary index. */ + int j = 3; + + while( n-- >= 0 ) + { + /* Advance 'j' by 'n' positions... */ + j += 1; + + /* ... but don't count 'book' elements that have already been copied. */ + while( book[j].length == 0 ) + { + j += 1; + } + } + + /* Copy the element. */ + patterns[i + 4] = book[j]; + + /* Mark this element as having been used. */ + book[j].length = 0; + } + // Last 4 random passes + for( int i = 31; i <= 34; ++i ) + { + patterns[i] = book[i]; + } + + /* Ensure that the array is terminated. */ + patterns[35].length = 0; + patterns[35].s = NULL; + + /* Run the Gutmann method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_gutmann */ + +void* nwipe_ops2( void* ptr ) +{ + /** + * Royal Canadian Mounted Police + * Technical Security Standard for Information Technology + * Appendix OPS-II: Media Sanitization + * + * NOTE: The last pass of this method is specially handled by nwipe_runmethod. + * + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* A generic array index. */ + int i; + + /* A generic result buffer. */ + int r; + + /* A buffer for random characters. */ + char* s; + + /* A buffer for the bitwise complements of 's'. */ + char* t; + + /* The element count of 's' and 't'. */ + u32 u; + + /* The pattern array for this method is dynamically allocated. */ + nwipe_pattern_t* patterns; + + /* The element count of 'patterns'. */ + u32 q; + + /* We need one random character per round. */ + u = 1 * nwipe_options.rounds; + + /* Allocate the array of random characters. */ + s = malloc( sizeof( char ) * u ); + + if( s == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the random character array." ); + c->result = -1; + return NULL; + } + + /* Allocate the array of complement characters. */ + t = malloc( sizeof( char ) * u ); + + if( t == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the complement character array." ); + c->result = -1; + free( s ); + return NULL; + } + + /* We need eight pattern elements per round, plus one for padding. */ + q = 8 * u + 1; + + /* Allocate the pattern array. */ + patterns = malloc( sizeof( nwipe_pattern_t ) * q ); + + if( patterns == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the pattern array." ); + c->result = -1; + free( s ); + free( t ); + return NULL; + } + + /* Load the array of random characters. */ + r = read( c->entropy_fd, s, u ); + + if( r != u ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_ops2_label ); + + if( r < 0 ) + { + c->result = r; + free( s ); + free( t ); + free( patterns ); + return NULL; + } + else + { + c->result = -1; + free( s ); + free( t ); + free( patterns ); + return NULL; + } + } + + for( i = 0; i < u; i += 1 ) + { + /* Populate the array of complements. */ + t[i] = ~s[i]; + } + + for( i = 0; i < u; i += 8 ) + { + /* Populate the array of patterns. */ + + /* Even elements point to the random characters. */ + patterns[i * 4 + 0].length = 1; + patterns[i * 4 + 0].s = &s[i]; + patterns[i * 4 + 2].length = 1; + patterns[i * 4 + 2].s = &s[i]; + patterns[i * 4 + 4].length = 1; + patterns[i * 4 + 4].s = &s[i]; + patterns[i * 4 + 6].length = 1; + patterns[i * 4 + 6].s = &s[i]; + + /* Odd elements point to the complement characters. */ + patterns[i * 4 + 1].length = 1; + patterns[i * 4 + 1].s = &t[i]; + patterns[i * 4 + 3].length = 1; + patterns[i * 4 + 3].s = &t[i]; + patterns[i * 4 + 5].length = 1; + patterns[i * 4 + 5].s = &t[i]; + patterns[i * 4 + 7].length = 1; + patterns[i * 4 + 7].s = &t[i]; + } + + /* Ensure that the array is terminated. */ + patterns[q - 1].length = 0; + patterns[q - 1].s = NULL; + + /* Run the TSSIT OPS-II method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Release the random character buffer. */ + free( s ); + + /* Release the complement character buffer */ + free( t ); + + /* Release the pattern buffer. */ + free( patterns ); + + /* We're done. */ + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_ops2 */ + +void* nwipe_is5enh( void* ptr ) +{ + nwipe_context_t* c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + c->wipe_status = 1; + + char is5enh[3] = { '\x00', '\xFF', '\x00' }; + nwipe_pattern_t patterns[] = { { 1, &is5enh[0] }, // Pass 1: 0s + { 1, &is5enh[1] }, // Pass 2: 1s + { -1, &is5enh[2] }, // Pass 3: random bytes with verification + { 0, NULL } }; + c->result = nwipe_runmethod( c, patterns ); + + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_is5enh */ + +void* nwipe_random( void* ptr ) +{ + /** + * Fill the device with a stream from the PRNG. + * + */ + + nwipe_context_t* c; + c = (nwipe_context_t*) ptr; + + /* get current time at the start of the wipe */ + time( &c->start_time ); + + /* set wipe in progress flag for GUI */ + c->wipe_status = 1; + + /* Define the random method. */ + nwipe_pattern_t patterns[] = { { -1, "" }, { 0, NULL } }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the wipe_status flag so that the GUI knows */ + c->wipe_status = 0; + + /* get current time at the end of the wipe */ + time( &c->end_time ); + + return NULL; +} /* nwipe_random */ + +int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns ) +{ + /** + * Writes patterns to the device. + * + */ + + /* The result holder. */ + int r; + + /* An index variable. */ + int i = 0; + + /* Variable to track if it is the last pass */ + int lastpass = 0; + + i = 0; + + /* The zero-fill pattern for the final pass of most methods. */ + nwipe_pattern_t pattern_zero = { 1, "\x00" }; + + /* The one-fill pattern for verification of the ones fill */ + nwipe_pattern_t pattern_one = { 1, "\xFF" }; + + /* Create the PRNG state buffer. */ + c->prng_seed.length = NWIPE_KNOB_PRNG_STATE_LENGTH; + c->prng_seed.s = malloc( c->prng_seed.length ); + + /* Check the memory allocation. */ + if( !c->prng_seed.s ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the prng seed buffer." ); + return -1; + } + + /* Count the number of patterns in the array. */ + while( patterns[i].length ) + { + i += 1; + } + + /* Tell the parent the number of device passes that will be run in one round. */ + c->pass_count = i; + + /* Set the number of bytes that will be written across all passes in one round. */ + c->pass_size = c->pass_count * c->device_size; + + /* For the selected method, calculate the correct round_size value (for correct percentage calculation) */ + calculate_round_size( c ); + + /* If only verifying then the round size is the device size */ + if( nwipe_options.method == &nwipe_verify_zero || nwipe_options.method == &nwipe_verify_one ) + { + c->round_size = c->device_size; + } + + /* Initialize the working round counter. */ + c->round_working = 0; + + nwipe_log( + NWIPE_LOG_NOTICE, "Invoking method '%s' on %s", nwipe_method_label( nwipe_options.method ), c->device_name ); + + while( c->round_working < c->round_count ) + { + /* Increment the round counter. */ + c->round_working += 1; + + nwipe_log( + NWIPE_LOG_NOTICE, "Starting round %i of %i on %s", c->round_working, c->round_count, c->device_name ); + + /* Initialize the working pass counter. */ + c->pass_working = 0; + + for( i = 0; i < c->pass_count; i++ ) + { + /* Increment the working pass. */ + c->pass_working += 1; + + /* Check if this is the last pass. */ + if( nwipe_options.verify == NWIPE_VERIFY_LAST && nwipe_options.method != &nwipe_ops2 ) + { + if( nwipe_options.noblank == 1 && c->round_working == c->round_count + && c->pass_working == c->pass_count ) + { + lastpass = 1; + } + } + + nwipe_log( NWIPE_LOG_NOTICE, + "Starting pass %i/%i, round %i/%i, on %s", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + + if( patterns[i].length == 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_runmethod: A non-terminating pattern element has zero length." ); + return -1; + } + + if( patterns[i].length > 0 ) + { + + /* Write a static pass. */ + c->pass_type = NWIPE_PASS_WRITE; + r = nwipe_static_pass( c, &patterns[i] ); + c->pass_type = NWIPE_PASS_NONE; + + /* Log number of bytes written to disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + if( nwipe_options.verify == NWIPE_VERIFY_ALL || lastpass == 1 ) + { + + nwipe_log( NWIPE_LOG_NOTICE, + "Verifying pass %i of %i, round %i of %i, on %s", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + + /* Verify this pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_static_verify( c, &patterns[i] ); + c->pass_type = NWIPE_PASS_NONE; + + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes read from %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + nwipe_log( NWIPE_LOG_NOTICE, + "Verified pass %i of %i, round %i of %i, on '%s'.", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + } + + } /* static pass */ + + else + { + c->pass_type = NWIPE_PASS_WRITE; + + /* Seed the PRNG. */ + r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); + + /* Check the result. */ + if( r < 0 ) + { + c->pass_type = NWIPE_PASS_NONE; + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); + return -1; + } + + /* Check for a partial read. */ + if( r != c->prng_seed.length ) + { + /* TODO: Handle partial reads. */ + nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); + return -1; + } + + /* Write the random pass. */ + r = nwipe_random_pass( c ); + c->pass_type = NWIPE_PASS_NONE; + + /* Log number of bytes written to disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + /* Make sure IS5 enhanced always verifies its PRNG pass regardless */ + /* of the current combination of the --noblank (which influences */ + /* the lastpass variable) and --verify options. */ + if( nwipe_options.verify == NWIPE_VERIFY_ALL || lastpass == 1 || nwipe_options.method == &nwipe_is5enh ) + { + nwipe_log( NWIPE_LOG_NOTICE, + "Verifying pass %i of %i, round %i of %i, on %s", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + + /* Verify this pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_random_verify( c ); + c->pass_type = NWIPE_PASS_NONE; + + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes read from %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + nwipe_log( NWIPE_LOG_NOTICE, + "Verified pass %i of %i, round %i of %i, on '%s'.", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + } + + } /* random pass */ + + nwipe_log( NWIPE_LOG_NOTICE, + "Finished pass %i/%i, round %i/%i, on %s", + c->pass_working, + c->pass_count, + c->round_working, + c->round_count, + c->device_name ); + + } /* for passes */ + + if( c->round_working < c->round_count ) + { + nwipe_log( + NWIPE_LOG_NOTICE, "Finished round %i of %i on %s", c->round_working, c->round_count, c->device_name ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, + "Finished final round %i of %i on %s", + c->round_working, + c->round_count, + c->device_name ); + } + + } /* while rounds */ + + if( nwipe_options.method == &nwipe_ops2 ) + { + /* NOTE: The OPS-II method specifically requires that a random pattern be left on the device. */ + + /* Tell the parent that we are running the final pass. */ + c->pass_type = NWIPE_PASS_FINAL_OPS2; + + /* Seed the PRNG. */ + r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); + return -1; + } + + /* Check for a partial read. */ + if( r != c->prng_seed.length ) + { + /* TODO: Handle partial reads. */ + nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); + return -1; + } + + nwipe_log( NWIPE_LOG_NOTICE, "Writing final random pattern to '%s'.", c->device_name ); + + /* The final ops2 pass. */ + r = nwipe_random_pass( c ); + + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying final random pattern FRP on %s", c->device_name ); + + /* Verify the final zero pass. */ + r = nwipe_random_verify( c ); + + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes read from %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified FRP on '%s' matches", c->device_name ); + } + + } /* final ops2 */ + + else if( nwipe_options.method == &nwipe_verify_zero ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying that %s is zeroed", c->device_name ); + + /* Verify the final zero pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_static_verify( c, &pattern_zero ); + c->pass_type = NWIPE_PASS_NONE; + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + if( c->verify_errors == 0 ) + { + nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is Zeroed.", c->device_name ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "[FAILURE] %s has not been Zeroed .", c->device_name ); + } + + } /* verify */ + + else if( nwipe_options.method == &nwipe_verify_one ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying that %s is Ones (0xFF)", c->device_name ); + + /* Verify the final ones pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_static_verify( c, &pattern_one ); + c->pass_type = NWIPE_PASS_NONE; + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + if( c->verify_errors == 0 ) + { + nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is full of ones (0xFF).", c->device_name ); + } + else + { + nwipe_log( NWIPE_LOG_ERROR, "[FAILURE] %s is not full of ones (0xFF).", c->device_name ); + } + + } /* verify */ + + else if( nwipe_options.noblank == 0 ) + { + /* Tell the user that we are on the final pass. */ + c->pass_type = NWIPE_PASS_FINAL_BLANK; + + nwipe_log( NWIPE_LOG_NOTICE, "Blanking device %s", c->device_name ); + + /* The final zero pass. */ + r = nwipe_static_pass( c, &pattern_zero ); + + /* Log number of bytes written to disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying that %s is empty.", c->device_name ); + + /* Verify the final zero pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_static_verify( c, &pattern_zero ); + c->pass_type = NWIPE_PASS_NONE; + + /* Log number of bytes read from disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes read from %s", c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) + { + return r; + } + + if( c->verify_errors == 0 ) + { + nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is empty.", c->device_name ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, "[FAILURE] %s Verification errors, not empty", c->device_name ); + } + } + + if( c->verify_errors == 0 && c->pass_errors == 0 ) + { + nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Blanked device %s", c->device_name ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, "[FAILURE] %s may not be blanked", c->device_name ); + } + + } /* final blank */ + + /* Release the state buffer. */ + c->prng_seed.length = 0; + free( c->prng_seed.s ); + + /* Tell the parent that we have fininshed the final pass. */ + c->pass_type = NWIPE_PASS_NONE; + + if( c->verify_errors > 0 ) + { + /* We finished, but with non-fatal verification errors. */ + nwipe_log( NWIPE_LOG_ERROR, "%llu verification errors on '%s'.", c->verify_errors, c->device_name ); + } + + if( c->pass_errors > 0 ) + { + /* We finished, but with non-fatal wipe errors. */ + nwipe_log( NWIPE_LOG_ERROR, "%llu wipe errors on '%s'.", c->pass_errors, c->device_name ); + } + + /* FIXME: The 'round_errors' context member is not being used. */ + + if( c->pass_errors > 0 || c->round_errors > 0 || c->verify_errors > 0 ) + { + /* We finished, but with non-fatal errors. */ + return 1; + } + + /* We finished successfully. */ + return 0; + +} /* nwipe_runmethod */ + +void calculate_round_size( nwipe_context_t* c ) +{ + /* This is where the round size is calculated. round_size is used in the running percentage completion + * calculation. round size is calculated based on pass_size, pass_count, number of rounds, blanking + * on/off and verification All/Last/None + * + * To hopefully make this calculation more understandable, I have separated the calculations that apply to + * all methods and processed first then created a switch statement that contains method specific changes if any + */ + + /* Don't change the order of these values as the case statements use their index in the array, New methods + * don't need to be added to this array unless they have complicated calculations like Ops2 and IS5. If you do + * add a method, just add it to the bottom of the array_methods array and also to the bottom of the switch + * statement. + */ + void* array_methods[] = { &nwipe_zero, + &nwipe_ops2, + &nwipe_dodshort, + &nwipe_dod522022m, + &nwipe_gutmann, + &nwipe_random, + &nwipe_is5enh, + NULL }; + int i; + + /* This while loop allows us to effectively create a const that represents a method so we can use a case statement + * rather than if statements. + * + * Using a switch statement looks better than if statments as more methods may get added in the future expanding the + * list. The code could be condensed as some methods have identical adjustments, however as there are only a few + * methods I felt it was easier to understand as it is, however this could be changed if necessary. + */ + + /* Initialise, -1 = no additional calculation required */ + int selected_method = -1; + + i = 0; + while( array_methods[i] != NULL ) + { + if( nwipe_options.method == array_methods[i] ) + { + selected_method = i; + } + i++; + } + + /* On exit from the while loop the selected method either equals an index to a method + * or it equals -1 which means no extra calculations are required that are method specific + */ + + if( nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + /* We must read back all passes, so double the byte count. */ + c->pass_size *= 2; + } + + /* Tell the parent the number of rounds that will be run. */ + c->round_count = nwipe_options.rounds; + + /* Set the initial number of bytes that will be written across all rounds. + c->pass_size includes write AND verification passes if 'verify_all' is selected + but does not include the final blanking pass or the verify_last option */ + c->round_size = c->pass_size; + + /* Multiple the round_size by the number of rounds (times) the user wants to wipe the drive with this method. */ + c->round_size *= c->round_count; + + /* Now increase size based on whether blanking is enabled and verification */ + if( nwipe_options.noblank == 0 ) + { + /* Blanking enabled so increase round size */ + c->round_size += c->device_size; + + if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + c->round_size += c->device_size; + } + } + else + { + /* Blanking not enabled, check for 'Verify_last', increase round size if enabled. */ + if( nwipe_options.verify == NWIPE_VERIFY_LAST ) + { + c->round_size += c->device_size; + } + } + + /* Additional method specific round_size adjustments go in this switch statement */ + + switch( selected_method ) + { + case 0: + /* NWIPE_ZERO - No additional calculation required + * ---------- */ + break; + + case 1: + /* NWIPE_OPS2 + * ---------- */ + + /* Required for mandatory 9th and final random pass */ + c->round_size += c->device_size; + + /* Required for selectable 9th and final random verification */ + if( nwipe_options.verify == NWIPE_VERIFY_ALL || nwipe_options.verify == NWIPE_VERIFY_LAST ) + { + c->round_size += c->device_size; + } + + /* As no final zero blanking pass is permitted by this standard reduce round size if it's selected */ + if( nwipe_options.noblank == 0 ) + { + /* Reduce for blanking pass */ + c->round_size -= c->device_size; + + /* Reduce for blanking pass verification */ + if( nwipe_options.verify == NWIPE_VERIFY_ALL || nwipe_options.verify == NWIPE_VERIFY_LAST ) + { + c->round_size -= c->device_size; + } + } + else + { + if( nwipe_options.verify == NWIPE_VERIFY_LAST ) + { + /* If blanking off & verification on reduce round size */ + c->round_size -= c->device_size; + } + } + + break; + + case 2: + /* DoD Short - No additional calculation required + * --------- */ + + break; + + case 3: + /* DOD 522022m - No additional calculation required + * ----------- */ + + break; + + case 4: + /* GutMann - No additional calculation required + * ------- */ + + break; + + case 5: + /* PRNG (random) - No additional calculation required + * ------------- */ + + break; + + case 6: + /* NWIPE_IS5ENH + * ------------ */ + + /* This method ALWAYS verifies the 3rd pass so increase by device size, + * but NOT if VERIFY_ALL has been selected, but first .. */ + + /* Reduce as Verify_Last already included previously if blanking was off */ + if( nwipe_options.verify == NWIPE_VERIFY_LAST && nwipe_options.noblank == 1 ) + { + c->round_size -= c->device_size; + } + + /* Adjusts for verify on every third pass multiplied by number of rounds */ + if( nwipe_options.verify != NWIPE_VERIFY_ALL ) + { + c->round_size += ( c->device_size * c->round_count ); + } + + break; + + case -1: + /* Method not listed so don't do any extra calculations + * ---------------------------------------------------- */ + break; + } +} + +/* eof */ diff --git a/src/method.h b/src/method.h new file mode 100644 index 0000000..f6fdbc2 --- /dev/null +++ b/src/method.h @@ -0,0 +1,60 @@ +/* + * methods.c: Method implementations for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef METHOD_H_ +#define METHOD_H_ + +/* The argument list for nwipe methods. */ +#define NWIPE_METHOD_SIGNATURE nwipe_context_t* c + +typedef enum nwipe_verify_t_ { + NWIPE_VERIFY_NONE = 0, // Do not read anything back from the device. + NWIPE_VERIFY_LAST, // Check the last pass. + NWIPE_VERIFY_ALL, // Check all passes. +} nwipe_verify_t; + +/* The typedef of the function that will do the wipe. */ +typedef int ( *nwipe_method_t )( void* ptr ); + +typedef struct +{ + int length; // Length of the pattern in bytes, -1 means random. + char* s; // The actual bytes of the pattern. +} nwipe_pattern_t; + +const char* nwipe_method_label( void* method ); +int nwipe_runmethod( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* patterns ); + +void* nwipe_dod522022m( void* ptr ); +void* nwipe_dodshort( void* ptr ); +void* nwipe_gutmann( void* ptr ); +void* nwipe_ops2( void* ptr ); +void* nwipe_is5enh( void* ptr ); +void* nwipe_random( void* ptr ); +void* nwipe_zero( void* ptr ); +void* nwipe_one( void* ptr ); +void* nwipe_verify_zero( void* ptr ); +void* nwipe_verify_one( void* ptr ); + +void calculate_round_size( nwipe_context_t* ); + +#endif /* METHOD_H_ */ diff --git a/src/miscellaneous.c b/src/miscellaneous.c new file mode 100644 index 0000000..bc2dc01 --- /dev/null +++ b/src/miscellaneous.c @@ -0,0 +1,666 @@ +/* + * miscellaneous.c: functions that may be generally used throughout nwipes code, + * mainly string processing functions but also time related functions. + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif + +#include <stdio.h> +#include "nwipe.h" +#include "context.h" +#include "logging.h" +#include "miscellaneous.h" + +/* Convert string to upper case + */ +void strupper( char* str ) +{ + int idx; + + idx = 0; + while( str[idx] != 0 ) + { + /* If upper case alpha character, change to lower case */ + if( str[idx] >= 'A' && str[idx] <= 'Z' ) + { + str[idx] -= 32; + } + + idx++; + } +} + +/* Convert string to lower case + */ +void strlower( char* str ) +{ + int idx; + + idx = 0; + while( str[idx] != 0 ) + { + /* If upper case alpha character, change to lower case */ + if( str[idx] >= 'A' && str[idx] <= 'Z' ) + { + str[idx] += 32; + } + + idx++; + } +} + +void strip_CR_LF( char* str ) +{ + /* In the specified string, replace any CR or LF with a space */ + int idx = 0; + int len = strlen( str ); + while( idx < len ) + { + if( str[idx] == 0x0A || str[idx] == 0x0D ) + { + str[idx] = ' '; + } + idx++; + } +} + +/* Search a string for a positive number, convert the first + * number found to binary and return the binary number. + * returns the number or -1 if number too large or -2 if + * no number found. + */ + +u64 str_ascii_number_to_ll( char* str ) +{ + int idx; + int idx2; + char number_copy[20]; + + idx = 0; // index into the main string we are searching + idx2 = 0; // index used for backup copy of ascii number + + while( str[idx] != 0 ) + { + /* Find the start of the number */ + if( str[idx] >= '0' && str[idx] <= '9' ) + { + while( str[idx] != 0 ) + { + /* Find the end of the number */ + if( str[idx] >= '0' && str[idx] <= '9' ) + { + if( idx2 < sizeof( number_copy ) - 1 ) + { + number_copy[idx2++] = str[idx++]; + } + else + { + /* Number is too large ! */ + return -1; + } + } + else + { + /* end found */ + number_copy[idx2] = 0; // terminate our copy + + /* convert ascii number to longlong */ + return atoll( number_copy ); + } + } + } + else + { + idx++; + } + } + return -2; /* no number found */ +} + +void Determine_C_B_nomenclature( u64 qty, char* result, int result_array_size ) +{ + + /* C_B ? Determine Capacity or Bandwidth nomenclature + * + * A pointer to a result character string with a minimum of 13 characters in length + * should be provided. + * + * Outputs a string of the form xxxTB, xxxGB, xxxMB, xxxKB B depending on the value of 'qty' + */ + + /* Initialise the output array */ + int idx = 0; + + while( idx < result_array_size ) + { + result[idx++] = 0; + } + + /* Determine the size of throughput so that the correct nomenclature can be used */ + if( qty >= INT64_C( 10000000000000 ) ) + { + snprintf( result, result_array_size, "%4llu TB", qty / INT64_C( 1000000000000 ) ); + } + else if( qty >= INT64_C( 10000000000 ) ) + { + snprintf( result, result_array_size, "%4llu GB", qty / INT64_C( 1000000000 ) ); + } + else if( qty >= INT64_C( 10000000 ) ) + { + snprintf( result, result_array_size, "%4llu MB", qty / INT64_C( 1000000 ) ); + } + else if( qty >= INT64_C( 10000 ) ) + { + snprintf( result, result_array_size, "%4llu KB", qty / INT64_C( 1000 ) ); + } + else + { + snprintf( result, result_array_size, "%4llu B", qty / INT64_C( 1 ) ); + } +} + +void convert_seconds_to_hours_minutes_seconds( u64 total_seconds, int* hours, int* minutes, int* seconds ) +{ + /* Convert binary seconds into binary hours, minutes and seconds */ + + if( total_seconds % 60 ) + { + *minutes = total_seconds / 60; + + *seconds = total_seconds - ( *minutes * 60 ); + } + else + { + *minutes = total_seconds / 60; + + *seconds = 0; + } + if( *minutes > 59 ) + { + *hours = *minutes / 60; + if( *minutes % 60 ) + { + *minutes = *minutes - ( *hours * 60 ); + } + else + { + *minutes = 0; + } + } +} + +int nwipe_strip_path( char* output, char* input ) +{ + /* Take the input string, say "/dev/sda" and remove the "/dev/", prefix the result + * with 'length' spaces. So if length=8 and input=/dev/sda, output will + * be " sda", a string 8 characters long right justified with spaces. + */ + int idx_dest; + int idx_src; + idx_dest = 8; + // idx_dest = length; + output[idx_dest--] = 0; + idx_src = strlen( input ); + idx_src--; + + while( idx_dest >= 0 ) + { + /* if the device name contains a / start prefixing spaces */ + if( input[idx_src] == '/' ) + { + output[idx_dest--] = ' '; + continue; + } + if( idx_src >= 0 ) + { + output[idx_dest--] = input[idx_src--]; + } + } + return 0; +} + +void replace_non_alphanumeric( char* str, char replacement_char ) +{ + int i = 0; + while( str[i] != 0 ) + { + if( str[i] < '0' || ( str[i] > '9' && str[i] < 'A' ) || ( str[i] > 'Z' && str[i] < 'a' ) || str[i] > 'z' ) + { + str[i] = replacement_char; + } + i++; + } +} + +void convert_double_to_string( char* output_str, double value ) +{ + int idx = 0; + int idx2; + int idx3 = 0; + + char percstr[512] = ""; + + snprintf( percstr, sizeof( percstr ), "%5.32lf", value ); + + while( percstr[idx] != 0 ) + { + if( percstr[idx] == '.' ) + { + for( idx2 = 0; idx2 < 3; idx2++ ) + { + output_str[idx3++] = percstr[idx++]; + } + break; + } + output_str[idx3++] = percstr[idx++]; + } + output_str[idx3] = 0; +} + +int read_system_datetime( char* year, char* month, char* day, char* hours, char* minutes, char* seconds ) +{ + /* Reads system date & time and populates the caller provided strings. + * Each string is null terminated by this function. The calling program + * must provide the minimum string sizes as shown below. + * + * year 5 bytes (4 numeric digits plus NULL terminator) + * month 3 bytes (2 numeric digits plus NULL terminator) + * day 3 bytes (2 numeric digits plus NULL terminator) + * hours 3 bytes (2 numeric digits plus NULL terminator) + * minutes 3 bytes (2 numeric digits plus NULL terminator) + * seconds 3 bytes (2 numeric digits plus NULL terminator) + * + * return value: + * 0 = success + * -1 = Failure, see nwipe log for detail. + */ + FILE* fp; + int r; // A result buffer. + int idx; // general index + int status = 0; + + /** + * Obtain the year + */ + fp = popen( "date +%Y", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system year using commmand = date +%Y" ); + } + else + { + /* Read the first line and validate it. Should be 4 numeric digits */ + if( fgets( year, FOUR_DIGITS + 1, fp ) != NULL ) + { + idx = 0; + while( idx < 4 ) + { + if( year[idx] >= '0' && year[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error */ + year[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system year using command = date +%Y, but result appears invalid = %s", + year ); + status = -1; + break; + } + } + year[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + /** + * Obtain the month + */ + fp = popen( "date +%m", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system month using the command = date +%m" ); + } + else + { + /* Read the first line and validate it. Should be 2 numeric digits */ + if( fgets( month, TWO_DIGITS + 1, fp ) != NULL ) + { + idx = 0; + while( idx < 2 ) + { + if( month[idx] >= '0' && month[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error */ + month[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system month using command = date +%m, but result appears invalid = %s", + month ); + status = -1; + break; + } + } + month[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + /** + * Obtain the day + */ + fp = popen( "date +\%d", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system day using the command = date +\%d" ); + } + else + { + /* Read the first line and validate it. Should be 2 numeric digits */ + if( fgets( day, TWO_DIGITS + 1, fp ) != NULL ) + { + idx = 0; + while( idx < 2 ) + { + if( day[idx] >= '0' && day[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error */ + day[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system day using command = date +\%d, but result appears invalid = %s", + day ); + status = -1; + break; + } + } + day[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + /** + * Obtain the hours + */ + fp = popen( "date +%H", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system hour using the command = date +%H" ); + } + else + { + /* Read the first line and validate it. Should be 2 numeric digits */ + if( fgets( hours, TWO_DIGITS + 1, fp ) != NULL ) + { + // nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year); + idx = 0; + while( idx < 2 ) + { + if( hours[idx] >= '0' && hours[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error */ + hours[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system hours using command = date +%H, but result appears invalid = %s", + hours ); + status = -1; + break; + } + } + hours[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + /** + * Obtain the minutes + */ + fp = popen( "date +%M", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system minutes using the command = date +%M" ); + } + else + { + /* Read the first line and validate it. Should be 2 numeric digits */ + if( fgets( minutes, TWO_DIGITS + 1, fp ) != NULL ) + { + // nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year); + idx = 0; + while( idx < 2 ) + { + if( minutes[idx] >= '0' && minutes[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log the error */ + minutes[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system minutes using command = date +%H, but result appears invalid = %s", + minutes ); + status = -1; + break; + } + } + minutes[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + /** + * Obtain the seconds + */ + fp = popen( "date +%S", "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system seconds using the command = date +%S" ); + } + else + { + /* Read the first line and validate it. Should be 2 numeric digits */ + if( fgets( seconds, TWO_DIGITS + 1, fp ) != NULL ) + { + // nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year); + idx = 0; + while( idx < 2 ) + { + if( seconds[idx] >= '0' && seconds[idx] <= '9' ) + { + idx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error */ + seconds[++idx] = 0; /* terminate the string, prior to using in nwipe_log */ + nwipe_log( NWIPE_LOG_ERROR, + "Obtained system seconds using command = date +%S, but result appears invalid = %s", + seconds ); + status = -1; + break; + } + } + seconds[idx] = 0; /* terminate the string */ + } + r = pclose( fp ); + } + + return status; +} + +int write_system_datetime( char* year, char* month, char* day, char* hours, char* minutes, char* seconds ) +{ + /* Writes the system date & time using data from the caller provided strings. + * The calling program must provide the minimum string sizes as shown below + * populated with current date and time data. + * + * year 5 bytes (4 numeric digits plus NULL terminator) + * month 3 bytes (2 numeric digits plus NULL terminator) + * day 3 bytes (2 numeric digits plus NULL terminator) + * hours 3 bytes (2 numeric digits plus NULL terminator) + * minutes 3 bytes (2 numeric digits plus NULL terminator) + * seconds 3 bytes (2 numeric digits plus NULL terminator) + * + * return value: + * 0 = success + * -1 = Failure, see nwipe log for detail. + */ + FILE* fp; + int r; // A result buffer. + int idx; // general index + int strIdx; // Index into each string + int bufferIdx; // Index into the buffer + char buffer[5]; + + /** + * Basic validation that confirms the input strings are numeric and of the correct length, we do this + * by first constructing three arrays. The first are the names of the variables in order + * year, month, day, hours, minutes and seconds. The second array contains the address of + * each of those strings. The third array are the lengths. + * This allows us to create a single loop to validate all fields. + */ + + char* names[] = { "year", "month", "day", "hours", "minutes", "seconds" }; + char* pdata[] = { year, month, day, hours, minutes, seconds }; + int lengths[] = { 4, 2, 2, 2, 2, 2 }; + char cmd_format[] = "date %s%s%s%s%s.%s >/dev/null 2>&1"; + char cmd[256]; + + for( idx = 0; idx < 6; idx++ ) + { + strIdx = 0; // initialise string index + + /* check each characters is numeric */ + while( strIdx < lengths[idx] ) + { + if( pdata[idx][strIdx] >= '0' && pdata[idx][strIdx] <= '9' ) + { + strIdx++; + } + else + { + /* if we haven't reached the correct number of digits due to invalid data, log error, + * but first we read the valid data acquired so far into a buffer, this is done to avoid + * writing to the user provided string because if they did not size the string correctly + * writing a zero at the end could cause a segfault. + */ + + for( bufferIdx = 0; bufferIdx < strIdx + 1; bufferIdx++ ) + { + buffer[bufferIdx] = pdata[idx][bufferIdx]; + } + buffer[bufferIdx] = 0; /* terminate the string, prior to using in nwipe_log */ + + /* A typical error will look like .. + * "User provided year data that appear invalid = 202£" */ + nwipe_log( NWIPE_LOG_ERROR, "User provided %s data that appears invalid = %s", names[idx], buffer ); + return -1; + } + } + } + + /** + * Now using the validated strings construct the date command that we will use to write the system date/time + */ + sprintf( cmd, cmd_format, month, day, hours, minutes, year, seconds ); + + /** + * Run the date command to write the new date/time + */ + + fp = popen( cmd, "w" ); + r = pclose( fp ); + + if( fp == NULL || r != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "Failed to write system date/time using command = %s", cmd ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Date/time succesfully writen to system using command = %s", cmd ); + } + + return 0; +} + +void fix_endian_model_names( char* model ) +{ + /* Some IDE USB adapters get the endian wrong, we can't determine the endian from the drive + * as the drive standard doesn't provide that information, so we have to resort to matching + * the model name against known strings with the endian incorrect, then reverse the endian. + */ + + int idx = 0; + int idx2 = 0; + unsigned int length = 0; + char* tmp_string; + + length = strlen( model ); + + tmp_string = calloc( length, 1 ); + + /* "ASSMNU G" = "SAMSUNG ", tested against model Samsung HM160HC so that + * "ASSMNU G MH61H0 C" becomes "SAMSUNG HM160HC ") + */ + if( !( strncmp( model, "ASSMNU G", 8 ) ) ) + { + while( model[idx] != 0 ) + { + tmp_string[idx2 + 1] = model[idx]; + if( model[idx + 1] != 0 ) + { + tmp_string[idx2] = model[idx + 1]; + } + else + { + break; + } + + if( tmp_string[idx2 + 1] == ' ' && model[idx + 2] == ' ' ) + { + idx++; + } + + idx += 2; + idx2 += 2; + } + + tmp_string[idx2 + 1] = 0; + strcpy( model, tmp_string ); + } +} diff --git a/src/miscellaneous.h b/src/miscellaneous.h new file mode 100644 index 0000000..4d89a63 --- /dev/null +++ b/src/miscellaneous.h @@ -0,0 +1,132 @@ +/* + * miscellaneous.h: header file for miscellaneous.c .. + * + * functions that may be generally used throughout nwipes code, + * mainly string processing related functions. + * + * Copyright PartialVolume <https://github.com/PartialVolume>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef MISCELLANEOUS_H_ +#define MISCELLANEOUS_H_ + +#define FOUR_DIGITS 4 +#define TWO_DIGITS 2 + +/** + * Convert the string from lower to upper case + * @param pointer to a null terminated string + * @return void + */ +void strupper( char* ); + +/** + * Convert the string from upper to lower case + * @param pointer to a null terminated string + * @return void + */ +void strlower( char* str ); + +/** + * Search a string for a positive number, convert the first + * number found to binary and return the binary number. + * returns the number or -1 if number too large or -2 if + * no number found. + * + * @param pointer to a null terminated string + * @return longlong returns: + * the number + * -1 = number too large + * -2 = no number found. + */ +u64 str_ascii_number_to_ll( char* ); + +void Determine_C_B_nomenclature( u64, char*, int ); +void convert_seconds_to_hours_minutes_seconds( u64, int*, int*, int* ); +int nwipe_strip_path( char*, char* ); + +/** + * Scan a string and replace any characters that are not alpha-numeric with + * the character_char. + * Example: + * char str[] = 18:21:56; + * calling the function replace_non_alphanumeric( &str, '_' ) + * would result in str changing from 18:21:56 to 18_21_56 + * @param char* pointer to the string to be processed + * @param char the character used to replace non alpha-numeric characters + * @return void + */ +void replace_non_alphanumeric( char*, char ); + +/** + * I found this function necessary when converting a double of say + * 99.999999999999999999 to text using printf. I only wanted 99.99 + * printed but if you specified a precision of %.2f in printf i.e 2 digits + * after the decimal point you get 100.00 and not 99.99 If you increase + * the precision to %.10f then you get 99.9999999999 but I only want + * two significant digits displayed.i.e 99.99% not 100% + * So this function converts to double retaining sufficient precision + * so that a 30TB disc with one hidden sector will display as 99.99% erased + * As an example if the double value to be converted is 99.999999999999999987 + * this function will always output 99.99 unlike printf which outputs 100.00 + * @param char* pointer to the string we write our percentage to. Needs to be + * a minimum of 7 bytes, i.e 100.00 plus null terminator. + * @param double the floating point value to be converted to a string. + * @return void + */ +void convert_double_to_string( char*, double ); + +/** + * Reads system date & time and populates the caller provided strings. + * Each string is null terminated by this function. The calling + * program must provide the minimum string sizes as shown below. + * + * @param char* year 5 bytes (4 numeric digits plus NULL terminator) + * @param char* month 3 bytes (2 numeric digits plus NULL terminator) + * @param char* day 3 bytes (2 numeric digits plus NULL terminator) + * @param char* hours 3 bytes (2 numeric digits plus NULL terminator) + * @param char* minutes 3 bytes (2 numeric digits plus NULL terminator) + * @param char* seconds 3 bytes (2 numeric digits plus NULL terminator) + * @return 0 = success, -1 = failure. See nwipe log for detail. + */ +int read_system_datetime( char*, char*, char*, char*, char*, char* ); + +/** + * Writes system date & time from the caller provided strings. + * The calling program must provide the minimum populated string sizes + * as shown below. + * + * @param char* year 5 bytes (4 numeric digits plus NULL terminator) + * @param char* month 3 bytes (2 numeric digits plus NULL terminator) + * @param char* day 3 bytes (2 numeric digits plus NULL terminator) + * @param char* hours 3 bytes (2 numeric digits plus NULL terminator) + * @param char* minutes 3 bytes (2 numeric digits plus NULL terminator) + * @param char* seconds 3 bytes (2 numeric digits plus NULL terminator) + * @return 0 = success, -1 = failure. See nwipe log for detail. + */ +int write_system_datetime( char*, char*, char*, char*, char*, char* ); + +/** + * Fixes drive model names that have the incorrect endian. This happens + * with some IDE USB adapters. + * + * @param char* pointer to the drive model names + * @return void + */ +void fix_endian_model_names( char* model ); + +#endif /* HPA_DCO_H_ */ diff --git a/src/mt19937ar-cok/mt19937ar-cok.c b/src/mt19937ar-cok/mt19937ar-cok.c new file mode 100644 index 0000000..63ef659 --- /dev/null +++ b/src/mt19937ar-cok/mt19937ar-cok.c @@ -0,0 +1,139 @@ +/* + This code is modified for use in nwipe. + + A C-program for MT19937, with initialization improved 2002/2/10. + Coded by Takuji Nishimura and Makoto Matsumoto. + This is a faster version by taking Shawn Cokus's optimization, + Matthe Bellew's simplification, Isaku Wada's real version. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.keio.ac.jp/matumoto/emt.html + email: matumoto@math.keio.ac.jp +*/ + +#include <stdio.h> +#include "mt19937ar-cok.h" + +/* initializes state[N] with a seed */ +void init_genrand( twister_state_t* state, unsigned long s) +{ + int j; + state->array[0]= s & 0xffffffffUL; + for( j = 1; j < N; j++ ) + { + state->array[j] = (1812433253UL * (state->array[j-1] ^ (state->array[j-1] >> 30)) + j); + state->array[j] &= 0xffffffffUL; /* for >32 bit machines */ + } + state->left = 1; + state->initf = 1; +} + + +void twister_init( twister_state_t* state, unsigned long init_key[], unsigned long key_length ) +{ + int i = 1; + int j = 0; + int k = ( N > key_length ? N : key_length ); + + init_genrand( state, 19650218UL ); + + for( ; k; k-- ) + { + state->array[i] = (state->array[i] ^ ((state->array[i-1] ^ (state->array[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; + state->array[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + ++i; + ++j; + + if ( i >= N ) + { + state->array[0] = state->array[N-1]; + i = 1; + } + + if ( j >= key_length ) + { + j = 0; + } + } + + for( k = N -1; k; k-- ) + { + state->array[i] = (state->array[i] ^ ((state->array[i-1] ^ (state->array[i-1] >> 30)) * 1566083941UL)) - i; + state->array[i] &= 0xffffffffUL; + ++i; + + if ( i >= N ) + { + state->array[0] = state->array[N-1]; + i = 1; + } + } + + state->array[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ + state->left = 1; + state->initf = 1; +} + +static void next_state( twister_state_t* state ) +{ + unsigned long *p = state->array; + int j; + + if( state->initf == 0) { init_genrand( state, 5489UL ); } + state->left = N; + state->next = state->array; + for( j = N - M + 1; --j; p++ ) { *p = p[M] ^ TWIST(p[0], p[1]); } + for( j = M; --j; p++ ) { *p = p[M-N] ^ TWIST(p[0], p[1]); } + *p = p[M-N] ^ TWIST(p[0], state->array[0]); +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long twister_genrand_int32( twister_state_t* state ) +{ + unsigned long y; + + if ( --state->left == 0 ) { next_state( state ); } + y = *state->next++; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} diff --git a/src/mt19937ar-cok/mt19937ar-cok.h b/src/mt19937ar-cok/mt19937ar-cok.h new file mode 100644 index 0000000..afcc873 --- /dev/null +++ b/src/mt19937ar-cok/mt19937ar-cok.h @@ -0,0 +1,32 @@ +/* + * mt19937ar-cok.h: The Mersenne Twister PRNG implementation for nwipe. + * + */ + +#ifndef MT19937AR_H_ +#define MT19937AR_H_ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UMASK 0x80000000UL /* most significant w-r bits */ +#define LMASK 0x7fffffffUL /* least significant r bits */ +#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) +#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) + +typedef struct twister_state_t_ +{ + unsigned long array[N]; + int left; + int initf; + unsigned long *next; +} twister_state_t; + +/* Initialize the MT state. ( 0 < key_length <= 624 ). */ +void twister_init( twister_state_t* state, unsigned long init_key[], unsigned long key_length); + +/* Generate a random integer on the [0,0xffffffff] interval. */ +unsigned long twister_genrand_int32( twister_state_t* state ); + +#endif /* MT19937AR_H_ */ diff --git a/src/nwipe.c b/src/nwipe.c new file mode 100644 index 0000000..9dc8110 --- /dev/null +++ b/src/nwipe.c @@ -0,0 +1,1134 @@ +/* + * nwipe.c: Darik's Wipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <unistd.h> + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "device.h" +#include "logging.h" +#include "gui.h" +#include "temperature.h" +#include "miscellaneous.h" + +#include <sys/ioctl.h> /* FIXME: Twice Included */ +#include <sys/shm.h> +#include <wait.h> + +#include <parted/parted.h> +#include <parted/debug.h> +#include "conf.h" +#include "version.h" +#include "hpa_dco.h" +#include "conf.h" +#include <libconfig.h> + +int terminate_signal; +int user_abort; +int global_wipe_status; + +/* helper function for sorting */ +int devnamecmp( const void* a, const void* b ) +{ + // nwipe_log( NWIPE_LOG_DEBUG, "a: %s, b: %s", ( *( nwipe_context_t** ) a)->device_name, ( *( nwipe_context_t** ) + // b)->device_name ); + + int ldiff = strlen( ( *(nwipe_context_t**) a )->device_name ) - strlen( ( *(nwipe_context_t**) b )->device_name ); + if( ldiff != 0 ) + { + return ldiff; + } + int ret = strcmp( ( *(nwipe_context_t**) a )->device_name, ( *(nwipe_context_t**) b )->device_name ); + return ( ret ); +} + +int main( int argc, char** argv ) +{ + int nwipe_optind; // The result of nwipe_options(). + int nwipe_enumerated; // The number of contexts that have been enumerated. + int nwipe_error = 0; // An error counter. + int nwipe_selected = 0; // The number of contexts that have been selected. + int any_threads_still_running; // used in wipe thread cancellation wait loop + int thread_timeout_counter; // timeout thread cancellation after THREAD_CANCELLATION_TIMEOUT seconds + pthread_t nwipe_gui_thread = 0; // The thread ID of the GUI thread. + pthread_t nwipe_temperature_thread = 0; // The thread ID of the temperature update thread + pthread_t nwipe_sigint_thread; // The thread ID of the sigint handler. + + char modprobe_command[] = "modprobe %s"; + char modprobe_command2[] = "/sbin/modprobe %s"; + char modprobe_command3[] = "/usr/sbin/modprobe %s"; + char module_shortform[50]; + char final_cmd_modprobe[sizeof( modprobe_command ) + sizeof( module_shortform )]; + + /* The entropy source file handle. */ + int nwipe_entropy; + + /* The generic index variables. */ + int i; + int j; + + /* The generic result buffer. */ + int r; + + /* Initialise the termintaion signal, 1=terminate nwipe */ + terminate_signal = 0; + + /* Initialise the user abort signal, 1=User aborted with CNTRL-C,SIGTERM, SIGQUIT, SIGINT etc.. */ + user_abort = 0; + + /* nwipes return status value, set prior to exit at the end of nwipe, as no other exit points allowed */ + int return_status = 0; + + /* Initialise, flag indicating whether a wipe has actually started or not 0=no, 1=yes */ + global_wipe_status = 0; + + /* Initialise flags that indicate whether a fatal or non fatal error occurred on ANY drive */ + int fatal_errors_flag = 0; + int non_fatal_errors_flag = 0; + + /* Two arrays are used, containing pointers to the the typedef for each disk */ + /* The first array (c1) points to all devices, the second points to only */ + /* the disks selected for wiping. */ + + /* The array of pointers to enumerated contexts. */ + /* Initialised and populated in device scan. */ + nwipe_context_t** c1 = 0; + + if( geteuid() != 0 ) + { + printf( "nwipe must run with root permissions, which is not the case.\nAborting\n" ); + exit( 99 ); + } + + int wipe_threads_started = 0; + + /** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** + * Important Note: if you want nwipe_log messages to go into the logfile + * any 'nwipe_log()' commands must appear after the options are parsed here, + * else they will appear in the console but not in the logfile, that is, + * assuming you specified a log file on the command line as an nwipe option. + */ + + /***************************** + * Parse command line options. + */ + + /* Initialise the libconfig code that handles nwipe.conf */ + nwipe_conf_init(); + + nwipe_optind = nwipe_options_parse( argc, argv ); + + /* Log nwipes version */ + nwipe_log( NWIPE_LOG_INFO, "%s", banner ); + + /* Log OS info */ + nwipe_log_OSinfo(); + + /* Check that hdparm exists, we use hdparm for some HPA/DCO detection etc, if not + * exit nwipe. These checks are required if the PATH environment is not setup ! + * Example: Debian sid 'su' as opposed to 'su -' + */ + if( system( "which hdparm > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/hdparm > /dev/null 2>&1" ) ) + { + if( system( "which /usr/bin/hdparm > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "hdparm command not found." ); + nwipe_log( NWIPE_LOG_WARNING, + "Required by nwipe for HPA/DCO detection & correction and ATA secure erase." ); + nwipe_log( NWIPE_LOG_WARNING, "** Please install hdparm **\n" ); + cleanup(); + exit( 1 ); + } + } + } + + /* Check if the given path for PDF reports is a writeable directory */ + if( strcmp( nwipe_options.PDFreportpath, "noPDF" ) != 0 ) + { + if( access( nwipe_options.PDFreportpath, W_OK ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "PDFreportpath %s is not a writeable directory.", nwipe_options.PDFreportpath ); + cleanup(); + exit( 2 ); + } + } + + if( nwipe_optind == argc ) + { + /* File names were not given by the user. Scan for devices. */ + nwipe_enumerated = nwipe_device_scan( &c1 ); + + if( terminate_signal == 1 ) + { + cleanup(); + exit( 1 ); + } + + if( nwipe_enumerated == 0 ) + { + nwipe_log( NWIPE_LOG_INFO, + "Storage devices not found. Nwipe should be run as root or sudo/su, i.e sudo nwipe etc" ); + cleanup(); + return -1; + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Automatically enumerated %i devices.", nwipe_enumerated ); + } + } + else + { + argv += nwipe_optind; + argc -= nwipe_optind; + + nwipe_enumerated = nwipe_device_get( &c1, argv, argc ); + if( nwipe_enumerated == 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "Devices not found. Check you're not excluding drives unnecessarily," ); + nwipe_log( NWIPE_LOG_ERROR, "and you are running nwipe as sudo or as root." ); + printf( "Devices not found, check you're not excluding drives unnecessarily \n and you are running nwipe " + "as sudo or as root." ); + cleanup(); + exit( 1 ); + } + } + + /* sort list of devices here */ + qsort( (void*) c1, (size_t) nwipe_enumerated, sizeof( nwipe_context_t* ), devnamecmp ); + + if( terminate_signal == 1 ) + { + cleanup(); + exit( 1 ); + } + + /* Log the System information */ + nwipe_log_sysinfo(); + + /* The array of pointers to contexts that will actually be wiped. */ + nwipe_context_t** c2 = (nwipe_context_t**) malloc( nwipe_enumerated * sizeof( nwipe_context_t* ) ); + if( c2 == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "memory allocation for c2 failed" ); + cleanup(); + exit( 1 ); + } + + /* Open the entropy source. */ + nwipe_entropy = open( NWIPE_KNOB_ENTROPY, O_RDONLY ); + + /* Check the result. */ + if( nwipe_entropy < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "open" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to open entropy source %s.", NWIPE_KNOB_ENTROPY ); + cleanup(); + free( c2 ); + return errno; + } + + nwipe_log( NWIPE_LOG_NOTICE, "Opened entropy source '%s'.", NWIPE_KNOB_ENTROPY ); + + /* Block relevant signals in main thread. Any other threads that are */ + /* created after this will also block those signals. */ + sigset_t sigset; + sigemptyset( &sigset ); + sigaddset( &sigset, SIGHUP ); + sigaddset( &sigset, SIGTERM ); + sigaddset( &sigset, SIGQUIT ); + sigaddset( &sigset, SIGINT ); + sigaddset( &sigset, SIGUSR1 ); + pthread_sigmask( SIG_SETMASK, &sigset, NULL ); + + /* Create a signal handler thread. This thread will catch all */ + /* signals and decide what to do with them. This will only */ + /* catch nondirected signals. (I.e., if a thread causes a SIGFPE */ + /* then that thread will get that signal. */ + + /* Pass a pointer to a struct containing all data to the signal handler. */ + nwipe_misc_thread_data_t nwipe_misc_thread_data; + nwipe_thread_data_ptr_t nwipe_thread_data_ptr; + + nwipe_thread_data_ptr.c = c2; + nwipe_misc_thread_data.nwipe_enumerated = nwipe_enumerated; + nwipe_misc_thread_data.nwipe_selected = 0; + if( !nwipe_options.nogui ) + nwipe_misc_thread_data.gui_thread = &nwipe_gui_thread; + nwipe_thread_data_ptr.nwipe_misc_thread_data = &nwipe_misc_thread_data; + + if( !nwipe_options.nosignals ) + { + pthread_attr_t pthread_attr; + pthread_attr_init( &pthread_attr ); + pthread_attr_setdetachstate( &pthread_attr, PTHREAD_CREATE_DETACHED ); + + pthread_create( &nwipe_sigint_thread, &pthread_attr, signal_hand, &nwipe_thread_data_ptr ); + } + + /* Makesure the drivetemp module is loaded, else drives hwmon entries won't appear in /sys/class/hwmon */ + final_cmd_modprobe[0] = 0; + + /* The kernel module we are going to load */ + strcpy( module_shortform, "drivetemp" ); + + /* Determine whether we can access modprobe, required if the PATH environment is not setup ! (Debian sid 'su' as + * opposed to 'su -' */ + + if( system( "which modprobe > /dev/null 2>&1" ) ) + { + if( system( "which /sbin/modprobe > /dev/null 2>&1" ) ) + { + if( system( "which /usr/sbin/modprobe > /dev/null 2>&1" ) ) + { + nwipe_log( NWIPE_LOG_WARNING, "modprobe command not found. Install kmod package (modprobe)) !" ); + nwipe_log( NWIPE_LOG_WARNING, "Most temperature monitoring may be unavailable as module drivetemp" ); + nwipe_log( NWIPE_LOG_WARNING, "could not be loaded. drivetemp is not available on kernels < v5.5" ); + } + else + { + sprintf( final_cmd_modprobe, modprobe_command3, module_shortform ); + } + } + else + { + sprintf( final_cmd_modprobe, modprobe_command2, module_shortform ); + } + } + else + { + sprintf( final_cmd_modprobe, modprobe_command, module_shortform ); + } + + /* load the drivetemp module */ + if( system( final_cmd_modprobe ) != 0 ) + { + nwipe_log( NWIPE_LOG_WARNING, "hwmon: Unable to load module drivetemp, temperatures may be unavailable." ); + nwipe_log( NWIPE_LOG_WARNING, "hwmon: It's possible the drivetemp software isn't modular but built-in" ); + nwipe_log( NWIPE_LOG_WARNING, "hwmon: to the kernel, as is the case with ShredOS.x86_64 in which case" ); + nwipe_log( NWIPE_LOG_WARNING, "hwmon: the temperatures will actually be available despite this issue." ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, "hwmon: Module drivetemp loaded, drive temperatures available" ); + } + + /* A context struct for each device has already been created. */ + /* Now set specific nwipe options */ + for( i = 0; i < nwipe_enumerated; i++ ) + { + + /* Set the entropy source. */ + c1[i]->entropy_fd = nwipe_entropy; + + if( nwipe_options.autonuke ) + { + /* When the autonuke option is set, select all disks. */ + // TODO - partitions + // if( c1[i].device_part == 0 ) { c1[i].select = NWIPE_SELECT_TRUE; } + // else { c1[i].select = NWIPE_SELECT_TRUE_PARENT; } + c1[i]->select = NWIPE_SELECT_TRUE; + } + else + { + /* The user must manually select devices. */ + c1[i]->select = NWIPE_SELECT_FALSE; + } + + /* Initialise temperature variables for device */ + nwipe_init_temperature( c1[i] ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_NOTICE, "hwmon: Device %s hwmon path = %s", c1[i]->device_name, c1[i]->temp1_path ); + } + + // nwipe_update_temperature( c1[i] ); + + /* Log the temperature crtical, highest, lowest and lowest critical temperature + * limits to nwipes log file using the INFO catagory + */ + + nwipe_log_drives_temperature_limits( c1[i] ); + } + + /* Check for initialization errors. */ + if( nwipe_error ) + { + nwipe_log( NWIPE_LOG_ERROR, "Initialization error %i\n", nwipe_error ); + cleanup(); + return -1; + } + + /* Set up the data structures to pass the temperature thread the data it needs */ + nwipe_thread_data_ptr_t nwipe_temperature_thread_data; + nwipe_temperature_thread_data.c = c1; + nwipe_temperature_thread_data.nwipe_misc_thread_data = &nwipe_misc_thread_data; + + /* Fork the temperature thread */ + errno = pthread_create( + &nwipe_temperature_thread, NULL, nwipe_update_temperature_thread, &nwipe_temperature_thread_data ); + + /* Start the ncurses interface. */ + if( !nwipe_options.nogui ) + nwipe_gui_init(); + + if( nwipe_options.autonuke == 1 ) + { + /* Print the options window. */ + if( !nwipe_options.nogui ) + nwipe_gui_options(); + } + else + { + /* Get device selections from the user. */ + if( nwipe_options.nogui ) + { + printf( "--nogui option must be used with autonuke option\n" ); + cleanup(); + exit( 1 ); + } + else + { + if( nwipe_options.PDF_preview_details == 1 ) + { + nwipe_gui_preview_org_customer( SHOWING_PRIOR_TO_DRIVE_SELECTION ); + } + + nwipe_gui_select( nwipe_enumerated, c1 ); + } + } + + /* Initialise some of the variables in the drive contexts + */ + for( i = 0; i < nwipe_enumerated; i++ ) + { + /* Set the PRNG implementation, which must always come after the function nwipe_gui_select ! */ + c1[i]->prng = nwipe_options.prng; + c1[i]->prng_seed.length = 0; + c1[i]->prng_seed.s = 0; + c1[i]->prng_state = 0; + + /* Count the number of selected contexts. */ + if( c1[i]->select == NWIPE_SELECT_TRUE ) + { + nwipe_selected += 1; + } + + /* Initialise the wipe result value */ + c1[i]->result = 0; + + /* Initialise the variable that tracks how much of the drive has been erased */ + c1[i]->bytes_erased = 0; + } + + /* Pass the number selected to the struct for other threads */ + nwipe_misc_thread_data.nwipe_selected = nwipe_selected; + + /* Populate the array of selected contexts. */ + for( i = 0, j = 0; i < nwipe_enumerated; i++ ) + { + if( c1[i]->select == NWIPE_SELECT_TRUE ) + { + /* Copy the context. */ + c2[j++] = c1[i]; + } + } + + /* TODO: free c1 and c2 memory. */ + if( user_abort == 0 ) + { + /* Log the wipe options that have been selected immediately prior to the start of the wipe */ + nwipe_options_log(); + + /* The wipe has been initiated */ + global_wipe_status = 1; + + for( i = 0; i < nwipe_selected; i++ ) + { + /* A result buffer for the BLKGETSIZE64 ioctl. */ + u64 size64; + + /* Initialise the spinner character index */ + c2[i]->spinner_idx = 0; + + /* Initialise the start and end time of the wipe */ + c2[i]->start_time = 0; + c2[i]->end_time = 0; + + /* Initialise the wipe_status flag, -1 = wipe not yet started */ + c2[i]->wipe_status = -1; + + /* Open the file for reads and writes. */ + c2[i]->device_fd = open( c2[i]->device_name, O_RDWR ); + + /* Check the open() result. */ + if( c2[i]->device_fd < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "open" ); + nwipe_log( NWIPE_LOG_WARNING, "Unable to open device '%s'.", c2[i]->device_name ); + c2[i]->select = NWIPE_SELECT_DISABLED; + continue; + } + + /* Stat the file. */ + if( fstat( c2[i]->device_fd, &c2[i]->device_stat ) != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fstat" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to stat file '%s'.", c2[i]->device_name ); + nwipe_error++; + continue; + } + + /* Check that the file is a block device. */ + if( !S_ISBLK( c2[i]->device_stat.st_mode ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "'%s' is not a block device.", c2[i]->device_name ); + nwipe_error++; + continue; + } + + /* TODO: Lock the file for exclusive access. */ + /* + if( flock( c2[i]->device_fd, LOCK_EX | LOCK_NB ) != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "flock" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to lock the '%s' file.", c2[i]->device_name ); + nwipe_error++; + continue; + } + */ + + /* Print serial number of device if it exists. */ + if( strlen( (const char*) c2[i]->device_serial_no ) ) + { + nwipe_log( NWIPE_LOG_NOTICE, "%s has serial number %s", c2[i]->device_name, c2[i]->device_serial_no ); + } + + /* Do sector size and block size checking. I don't think this does anything useful as logical/Physical + * sector sizes are obtained by libparted in check.c */ + if( ioctl( c2[i]->device_fd, BLKSSZGET, &c2[i]->device_sector_size ) == 0 ) + { + + if( ioctl( c2[i]->device_fd, BLKBSZGET, &c2[i]->device_block_size ) != 0 ) + { + nwipe_log( NWIPE_LOG_WARNING, "Device '%s' failed BLKBSZGET ioctl.", c2[i]->device_name ); + c2[i]->device_block_size = 0; + } + } + else + { + nwipe_log( NWIPE_LOG_WARNING, "Device '%s' failed BLKSSZGET ioctl.", c2[i]->device_name ); + c2[i]->device_sector_size = 0; + c2[i]->device_block_size = 0; + } + + /* The st_size field is zero for block devices. */ + /* ioctl( c2[i]->device_fd, BLKGETSIZE64, &c2[i]->device_size ); */ + + /* Seek to the end of the device to determine its size. */ + c2[i]->device_size = lseek( c2[i]->device_fd, 0, SEEK_END ); + + /* Also ask the driver for the device size. */ + /* if( ioctl( c2[i]->device_fd, BLKGETSIZE64, &size64 ) ) */ + if( ioctl( c2[i]->device_fd, _IOR( 0x12, 114, size_t ), &size64 ) ) + { + /* The ioctl failed. */ + fprintf( stderr, "Error: BLKGETSIZE64 failed on '%s'.\n", c2[i]->device_name ); + nwipe_log( NWIPE_LOG_ERROR, "BLKGETSIZE64 failed on '%s'.\n", c2[i]->device_name ); + nwipe_error++; + } + c2[i]->device_size = size64; + + /* Check whether the two size values agree. */ + if( c2[i]->device_size != size64 ) + { + /* This could be caused by the linux last-odd-block problem. */ + fprintf( stderr, "Error: Last-odd-block detected on '%s'.\n", c2[i]->device_name ); + nwipe_log( NWIPE_LOG_ERROR, "Last-odd-block detected on '%s'.", c2[i]->device_name ); + nwipe_error++; + } + + if( c2[i]->device_size == (long long) -1 ) + { + /* We cannot determine the size of this device. */ + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to determine the size of '%s'.", c2[i]->device_name ); + nwipe_error++; + } + else + { + /* Reset the file pointer. */ + r = lseek( c2[i]->device_fd, 0, SEEK_SET ); + + if( r == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to reset the '%s' file offset.", c2[i]->device_name ); + nwipe_error++; + } + } + + if( c2[i]->device_size == 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "%s, sect/blk/dev %i/%i/%llu", + c2[i]->device_name, + c2[i]->device_sector_size, + c2[i]->device_block_size, + c2[i]->device_size ); + nwipe_error++; + continue; + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, + "%s, sect/blk/dev %i/%i/%llu", + c2[i]->device_name, + c2[i]->device_sector_size, + c2[i]->device_block_size, + c2[i]->device_size ); + } + + /* Fork a child process. */ + errno = pthread_create( &c2[i]->thread, NULL, nwipe_options.method, (void*) c2[i] ); + if( errno ) + { + nwipe_perror( errno, __FUNCTION__, "pthread_create" ); + if( !nwipe_options.nogui ) + nwipe_gui_free(); + return errno; + } + else + { + wipe_threads_started = 1; + } + } + } + + /* Change the terminal mode to non-blocking input. */ + nodelay( stdscr, 0 ); + + /* Set getch to delay in order to slow screen updates. */ + halfdelay( NWIPE_KNOB_SLEEP * 10 ); + + /* Set up data structs to pass the GUI thread the data it needs. */ + nwipe_thread_data_ptr_t nwipe_gui_data; + if( !nwipe_options.nogui ) + { + nwipe_gui_data.c = c2; + nwipe_gui_data.nwipe_misc_thread_data = &nwipe_misc_thread_data; + /* Fork the GUI thread. */ + errno = pthread_create( &nwipe_gui_thread, NULL, nwipe_gui_status, &nwipe_gui_data ); + } + + /* Wait for all the wiping threads to finish, but don't wait if we receive the terminate signal */ + + /* set getch delay to 2/10th second. */ + halfdelay( 10 ); + + i = 0; + while( i < nwipe_selected && terminate_signal == 0 ) + { + if( i == nwipe_selected ) + { + break; + } + + if( c2[i]->wipe_status != 0 ) + { + i = 0; + } + else + { + i++; + continue; + } + sleep( 1 ); /* DO NOT REMOVE ! Stops the routine hogging CPU cycles */ + } + + if( terminate_signal != 1 ) + { + if( !nwipe_options.nowait && !nwipe_options.autopoweroff ) + { + do + { + sleep( 1 ); + + } while( terminate_signal != 1 ); + } + } + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Exit in progress" ); + } + /* Send a REQUEST for the wipe threads to be cancelled */ + for( i = 0; i < nwipe_selected; i++ ) + { + + if( c2[i]->thread ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Requesting wipe thread cancellation for %s", c2[i]->device_name ); + } + pthread_cancel( c2[i]->thread ); + } + } + + /* Kill the GUI thread */ + if( nwipe_gui_thread ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Cancelling the GUI thread." ); + } + + /* We don't want to use pthread_cancel as our GUI thread is aware of the control-c + * signal and will exit itself we just join the GUI thread and wait for confirmation + */ + r = pthread_join( nwipe_gui_thread, NULL ); + if( r != 0 ) + { + nwipe_log( NWIPE_LOG_WARNING, "main()>pthread_join():Error when waiting for GUI thread to cancel." ); + } + else + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "GUI compute_stats thread has been cancelled" ); + } + } + } + + /* Release the gui. */ + if( !nwipe_options.nogui ) + { + nwipe_gui_free(); + } + + /* Now join the wipe threads and wait until they have terminated */ + any_threads_still_running = 1; + thread_timeout_counter = THREAD_CANCELLATION_TIMEOUT; + while( any_threads_still_running ) + { + /* quit waiting if we've tried 'thread_timeout_counter' times */ + if( thread_timeout_counter == 0 ) + { + break; + } + + any_threads_still_running = 0; + for( i = 0; i < nwipe_selected; i++ ) + { + if( c2[i]->thread ) + { + printf( "\nWaiting for wipe thread to cancel for %s\n", c2[i]->device_name ); + + /* Joins the thread and waits for completion before continuing */ + r = pthread_join( c2[i]->thread, NULL ); + if( r != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Error joining the wipe thread when waiting for thread to cancel.", + c2[i]->device_name ); + + if( r == EDEADLK ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Error joining the wipe thread: EDEADLK: Deadlock detected.", + c2[i]->device_name ); + } + else + { + if( r == EINVAL ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Error joining the wipe thread: %s EINVAL: thread is not joinable.", + c2[i]->device_name ); + } + else + { + if( r == ESRCH ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Error joining the wipe thread: %s ESRCH: no matching thread found", + c2[i]->device_name ); + } + } + } + + any_threads_still_running = 1; + } + else + { + c2[i]->thread = 0; /* Zero the thread so we know it's been cancelled */ + + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Wipe thread for device %s has terminated", c2[i]->device_name ); + } + + /* Close the device file descriptor. */ + close( c2[i]->device_fd ); + } + } + } + thread_timeout_counter--; + sleep( 1 ); + } + + /* Now all the wipe threads have finished, we can issue a terminate_signal = 1 + * which will cause the temperature update thread to terminate, this is necessary + * because in gui mode the terminate_signal is set when the user presses a key to + * exit on completion of all the wipes, however in non gui mode that code isn't + * active (being in the gui section) so here we need to set the terminate signal + * specifically for a completed wipes/s just for non gui mode. + */ + terminate_signal = 1; + + /* Kill the temperature update thread */ + if( nwipe_temperature_thread ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "Cancelling the temperature thread." ); + } + + /* We don't want to use pthread_cancel as our temperature thread is aware of the control-c + * signal and will exit itself we just join the temperature thread and wait for confirmation + */ + r = pthread_join( nwipe_temperature_thread, NULL ); + if( r != 0 ) + { + nwipe_log( NWIPE_LOG_WARNING, + "main()>pthread_join():Error when waiting for temperature thread to cancel." ); + } + else + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_INFO, "temperature thread has been cancelled" ); + } + } + } + + if( nwipe_options.verbose ) + { + for( i = 0; i < nwipe_selected; i++ ) + { + nwipe_log( NWIPE_LOG_DEBUG, + "Status: %s, result=%d, pass_errors=%llu, verify_errors=%llu, fsync_errors=%llu", + c2[i]->device_name, + c2[i]->result, + c2[i]->pass_errors, + c2[i]->verify_errors, + c2[i]->fsyncdata_errors ); + } + } + + /* if no wipe threads started then zero each selected drive result flag, + * as we don't need to report fatal/non fatal errors if no wipes were ever started ! */ + if( wipe_threads_started == 0 ) + { + for( i = 0; i < nwipe_selected; i++ ) + { + c2[i]->result = 0; + } + } + else + { + for( i = 0; i < nwipe_selected; i++ ) + { + /* Check for errors. */ + if( c2[i]->result != 0 || c2[i]->pass_errors != 0 || c2[i]->verify_errors != 0 + || c2[i]->fsyncdata_errors != 0 ) + { + /* If the run_method ever returns anything other than zero then makesure there is at least one pass + * error This is so that the log summary tables correctly show a failure when one occurs as it only + * shows pass, verification and fdatasync errors. */ + if( c2[i]->result != 0 ) + { + if( c2[i]->pass_errors == 0 ) + { + c2[i]->pass_errors = 1; + } + } + + nwipe_log( NWIPE_LOG_FATAL, + "Nwipe exited with errors on device = %s, see log for specific error\n", + c2[i]->device_name ); + nwipe_log( NWIPE_LOG_DEBUG, + "Status: %s, result=%d, pass_errors=%llu, verify_errors=%llu, fsync_errors=%llu", + c2[i]->device_name, + c2[i]->result, + c2[i]->pass_errors, + c2[i]->verify_errors, + c2[i]->fsyncdata_errors ); + non_fatal_errors_flag = 1; + return_status = 1; + } + } + } + + /* Generate and send the drive status summary to the log */ + nwipe_log_summary( c2, nwipe_selected ); + + /* Print a one line status message for the user */ + if( return_status == 0 || return_status == 1 ) + { + if( user_abort == 1 ) + { + if( global_wipe_status == 1 ) + { + nwipe_log( NWIPE_LOG_INFO, + "Nwipe was aborted by the user. Check the summary table for the drive status." ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Nwipe was aborted by the user prior to the wipe starting." ); + } + } + else + { + if( fatal_errors_flag == 1 || non_fatal_errors_flag == 1 ) + { + nwipe_log( NWIPE_LOG_INFO, + "Nwipe exited with errors, check the log & summary table for individual drive status." ); + } + else + { + nwipe_log( NWIPE_LOG_INFO, "Nwipe successfully completed. See summary table for details." ); + } + } + } + + cleanup(); + + check_for_autopoweroff(); + + /* Exit. */ + return return_status; +} + +void* signal_hand( void* ptr ) +{ + int sig; + int hours; + int minutes; + int seconds; + + hours = 0; + minutes = 0; + seconds = 0; + + // Define signals that this handler should react to + sigset_t sigset; + sigemptyset( &sigset ); + sigaddset( &sigset, SIGHUP ); + sigaddset( &sigset, SIGTERM ); + sigaddset( &sigset, SIGQUIT ); + sigaddset( &sigset, SIGINT ); + sigaddset( &sigset, SIGUSR1 ); + + int i; + char eta[9]; + + /* Set up the structs we will use for the data required. */ + nwipe_thread_data_ptr_t* nwipe_thread_data_ptr; + nwipe_context_t** c; + nwipe_misc_thread_data_t* nwipe_misc_thread_data; + + /* Retrieve from the pointer passed to the function. */ + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t*) ptr; + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + + while( 1 ) + { + /* wait for a signal to arrive */ + sigwait( &sigset, &sig ); + + switch( sig ) + { + + // Log current status. All values are automatically updated by the GUI + case SIGUSR1: + compute_stats( ptr ); + + for( i = 0; i < nwipe_misc_thread_data->nwipe_selected; i++ ) + { + + if( c[i]->thread ) + { + char* status = ""; + switch( c[i]->pass_type ) + { + case NWIPE_PASS_FINAL_BLANK: + status = "[blanking]"; + break; + + case NWIPE_PASS_FINAL_OPS2: + status = "[OPS-II final]"; + break; + + case NWIPE_PASS_WRITE: + status = "[writing]"; + break; + + case NWIPE_PASS_VERIFY: + status = "[verifying]"; + break; + + case NWIPE_PASS_NONE: + break; + } + if( c[i]->sync_status ) + { + status = "[syncing]"; + } + + convert_seconds_to_hours_minutes_seconds( c[i]->eta, &hours, &minutes, &seconds ); + + nwipe_log( NWIPE_LOG_INFO, + "%s: %05.2f%%, round %i of %i, pass %i of %i, eta %02i:%02i:%02i, %s", + c[i]->device_name, + c[i]->round_percent, + c[i]->round_working, + c[i]->round_count, + c[i]->pass_working, + c[i]->pass_count, + hours, + minutes, + seconds, + status ); + } + else + { + if( c[i]->result == 0 ) + { + nwipe_log( NWIPE_LOG_INFO, "%s: Success", c[i]->device_name ); + } + else if( c[i]->signal ) + { + nwipe_log( + NWIPE_LOG_INFO, "%s: >>> FAILURE! <<<: signal %i", c[i]->device_name, c[i]->signal ); + } + else + { + nwipe_log( + NWIPE_LOG_INFO, "%s: >>> FAILURE! <<<: code %i", c[i]->device_name, c[i]->result ); + } + } + } + + break; + + case SIGHUP: + case SIGINT: + case SIGQUIT: + case SIGTERM: + /* Set termination flag for main() which will do housekeeping prior to exit */ + terminate_signal = 1; + + /* Set the user abort flag */ + user_abort = 1; + + /* Return control to the main thread, returning the signal received */ + return ( (void*) 0 ); + + break; + } + } + + return ( 0 ); +} + +int cleanup() +{ + int i; + extern int log_elements_displayed; // initialised and found in logging.c + extern int log_elements_allocated; // initialised and found in logging.c + extern char** log_lines; + extern config_t nwipe_cfg; + + /* Print the logs held in memory to the console */ + for( i = log_elements_displayed; i < log_elements_allocated; i++ ) + { + printf( "%s\n", log_lines[i] ); + } + fflush( stdout ); + + /* Deallocate memory used by logging */ + if( log_elements_allocated != 0 ) + { + for( i = 0; i < log_elements_allocated; i++ ) + { + free( log_lines[i] ); + } + log_elements_allocated = 0; // zeroed just in case cleanup is called twice. + free( log_lines ); + } + + /* Deallocate libconfig resources */ + config_destroy( &nwipe_cfg ); + + /* TODO: Any other cleanup required ? */ + + return 0; +} +void check_for_autopoweroff( void ) +{ + char cmd[] = "shutdown -Ph +1 \"System going down in one minute\""; + FILE* fp; + int r; // A result buffer. + + /* User request auto power down ? */ + if( nwipe_options.autopoweroff == 1 ) + { + fp = popen( cmd, "r" ); + if( fp == NULL ) + { + nwipe_log( NWIPE_LOG_INFO, "Failed to autopoweroff to %s", cmd ); + return; + } + r = pclose( fp ); + } +} diff --git a/src/nwipe.h b/src/nwipe.h new file mode 100644 index 0000000..4f1c495 --- /dev/null +++ b/src/nwipe.h @@ -0,0 +1,114 @@ +/*. + * nwipe.h: The header file of the nwipe program. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef NWIPE_H_ +#define NWIPE_H_ + +/* Function prototypes */ +int cleanup(); +void check_for_autopoweroff( void ); +void* signal_hand( void* ); + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +/* Busybox headers. */ +#ifdef BB_VER +#include "busybox.h" +#endif + +/* System headers. */ +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <math.h> +#include <pthread.h> +#include <regex.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +/* workaround for Fedora */ +#ifndef off64_t +#ifndef off_t +#define off64_t int64_t +#else +#define off64_t off_t +#endif +#endif + +/*#include "config.h"*/ + +/* System errors. */ +extern int errno; + +/* 0=wipe not yet started, 1=wipe has been started by the user */ +extern int global_wipe_status; + +/* Ncurses headers. */ +#ifdef NCURSES_IN_SUBDIR +#include <ncurses/ncurses.h> +#else +#include <ncurses.h> +#endif +#ifdef PANEL_IN_SUBDIR +#include <ncurses/panel.h> +#else +#include <panel.h> +#endif + +/* Kernel device headers. */ +#include <linux/hdreg.h> + +/* These types are usually defined in <asm/types.h> for __KERNEL__ code. */ +typedef unsigned long long u64; +typedef unsigned long u32; +typedef unsigned short u16; +typedef unsigned char u8; + +/* This is required for ioctl BLKGETSIZE64, but it conflicts with <wait.h>. */ +/* #include <linux/fs.h> */ + +/* Define ioctls that cannot be included. */ +#define BLKSSZGET _IO( 0x12, 104 ) +#define BLKBSZGET _IOR( 0x12, 112, size_t ) +#define BLKBSZSET _IOW( 0x12, 113, size_t ) +#define BLKGETSIZE64 _IOR( 0x12, 114, sizeof( u64 ) ) + +#define THREAD_CANCELLATION_TIMEOUT 10 + +/* This is required for ioctl FDFLUSH. */ +#include <linux/fd.h> + +#endif /* NWIPE_H_ */ diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..95050db --- /dev/null +++ b/src/options.c @@ -0,0 +1,707 @@ +/* + * options.c: Command line processing routines for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "logging.h" +#include "version.h" +#include "conf.h" + +/* The global options struct. */ +nwipe_options_t nwipe_options; + +int nwipe_options_parse( int argc, char** argv ) +{ + extern char* optarg; // The working getopt option argument. + extern int optind; // The working getopt index into argv. + extern int optopt; // The last unhandled getopt option. + extern int opterr; // The last getopt error number. + + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + + /* The getopt() result holder. */ + int nwipe_opt; + + /* Excluded drive indexes */ + int idx_drive_chr; + int idx_optarg; + int idx_drive; + + /* Array index variable. */ + int i; + + /* The list of acceptable short options. */ + char nwipe_options_short[] = "Vvhl:P:m:p:qr:e:"; + + /* Used when reading value fron nwipe.conf */ + const char* read_value = NULL; + + int ret; + + /* The list of acceptable long options. */ + static struct option nwipe_options_long[] = { + /* Set when the user wants to wipe without a confirmation prompt. */ + { "autonuke", no_argument, 0, 0 }, + + /* Set when the user wants to have the system powerdown on completion of wipe. */ + { "autopoweroff", no_argument, 0, 0 }, + + /* A GNU standard option. Corresponds to the 'h' short option. */ + { "help", no_argument, 0, 'h' }, + + /* The wipe method. Corresponds to the 'm' short option. */ + { "method", required_argument, 0, 'm' }, + + /* Log file. Corresponds to the 'l' short option. */ + { "logfile", required_argument, 0, 'l' }, + + /* PDFreport path. Corresponds to the 'P' short option. */ + { "PDFreportpath", required_argument, 0, 'P' }, + + /* Exclude devices, comma separated list */ + { "exclude", required_argument, 0, 'e' }, + + /* The Pseudo Random Number Generator. */ + { "prng", required_argument, 0, 'p' }, + + /* The number of times to run the method. */ + { "rounds", required_argument, 0, 'r' }, + + /* Whether to blank the disk after wiping. */ + { "noblank", no_argument, 0, 0 }, + + /* Whether to ignore all USB devices. */ + { "nousb", no_argument, 0, 0 }, + + /* Whether to exit after wiping or wait for a keypress. */ + { "nowait", no_argument, 0, 0 }, + + /* Whether to allow signals to interrupt a wipe. */ + { "nosignals", no_argument, 0, 0 }, + + /* Whether to display the gui. */ + { "nogui", no_argument, 0, 0 }, + + /* Whether to anonymize the serial numbers. */ + { "quiet", no_argument, 0, 'q' }, + + /* A flag to indicate whether the devices would be opened in sync mode. */ + { "sync", required_argument, 0, 0 }, + + /* Verify that wipe patterns are being written to the device. */ + { "verify", required_argument, 0, 0 }, + + /* Display program version. */ + { "verbose", no_argument, 0, 'v' }, + + /* Display program version. */ + { "version", no_argument, 0, 'V' }, + + /* Requisite padding for getopt(). */ + { 0, 0, 0, 0 } }; + + /* Set default options. */ + nwipe_options.autonuke = 0; + nwipe_options.autopoweroff = 0; + nwipe_options.method = &nwipe_dodshort; + nwipe_options.prng = ( sizeof( unsigned long int ) >= 8 ) ? &nwipe_isaac64 : &nwipe_isaac; + nwipe_options.rounds = 1; + nwipe_options.noblank = 0; + nwipe_options.nousb = 0; + nwipe_options.nowait = 0; + nwipe_options.nosignals = 0; + nwipe_options.nogui = 0; + nwipe_options.quiet = 0; + nwipe_options.sync = DEFAULT_SYNC_RATE; + nwipe_options.verbose = 0; + nwipe_options.verify = NWIPE_VERIFY_LAST; + memset( nwipe_options.logfile, '\0', sizeof( nwipe_options.logfile ) ); + memset( nwipe_options.PDFreportpath, '\0', sizeof( nwipe_options.PDFreportpath ) ); + strncpy( nwipe_options.PDFreportpath, ".", 2 ); + + /* Read PDF settings from nwipe.conf if available */ + if( ( ret = nwipe_conf_read_setting( "PDF_Certificate.PDF_Enable", &read_value ) ) ) + { + /* error occurred */ + nwipe_log( NWIPE_LOG_ERROR, + "nwipe_conf_read_setting():Error reading PDF_Certificate.PDF_Enable from nwipe.conf, ret code %i", + ret ); + + /* Use default values */ + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "ENABLED" ) ) + { + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "DISABLED" ) ) + { + nwipe_options.PDF_enable = 0; + } + else + { + // error occurred + nwipe_log( + NWIPE_LOG_ERROR, + "PDF_Certificate.PDF_Enable in nwipe.conf returned a value that was neither ENABLED or DISABLED" ); + nwipe_options.PDF_enable = 1; // Default to Enabled + } + } + } + + /* PDF Preview enable/disable */ + if( ( ret = nwipe_conf_read_setting( "PDF_Certificate.PDF_Preview", &read_value ) ) ) + { + /* error occurred */ + nwipe_log( NWIPE_LOG_ERROR, + "nwipe_conf_read_setting():Error reading PDF_Certificate.PDF_Preview from nwipe.conf, ret code %i", + ret ); + + /* Use default values */ + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "ENABLED" ) ) + { + nwipe_options.PDF_preview_details = 1; + } + else + { + if( !strcmp( read_value, "DISABLED" ) ) + { + nwipe_options.PDF_preview_details = 0; + } + else + { + /* error occurred */ + nwipe_log( + NWIPE_LOG_ERROR, + "PDF_Certificate.PDF_Preview in nwipe.conf returned a value that was neither ENABLED or DISABLED" ); + nwipe_options.PDF_preview_details = 1; /* Default to Enabled */ + } + } + } + + /* Initialise each of the strings in the excluded drives array */ + for( i = 0; i < MAX_NUMBER_EXCLUDED_DRIVES; i++ ) + { + nwipe_options.exclude[i][0] = 0; + } + + /* Parse command line options. */ + while( 1 ) + { + /* Get the next command line option with (3)getopt. */ + nwipe_opt = getopt_long( argc, argv, nwipe_options_short, nwipe_options_long, &i ); + + /* Break when we have processed all of the given options. */ + if( nwipe_opt < 0 ) + { + break; + } + + switch( nwipe_opt ) + { + case 0: /* Long options without short counterparts. */ + + if( strcmp( nwipe_options_long[i].name, "autonuke" ) == 0 ) + { + nwipe_options.autonuke = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "autopoweroff" ) == 0 ) + { + nwipe_options.autopoweroff = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "noblank" ) == 0 ) + { + nwipe_options.noblank = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nousb" ) == 0 ) + { + nwipe_options.nousb = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nowait" ) == 0 ) + { + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nosignals" ) == 0 ) + { + nwipe_options.nosignals = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nogui" ) == 0 ) + { + nwipe_options.nogui = 1; + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "verbose" ) == 0 ) + { + nwipe_options.verbose = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "sync" ) == 0 ) + { + if( sscanf( optarg, " %i", &nwipe_options.sync ) != 1 || nwipe_options.sync < 0 ) + { + fprintf( stderr, "Error: The sync argument must be a positive integer or zero.\n" ); + exit( EINVAL ); + } + break; + } + + if( strcmp( nwipe_options_long[i].name, "verify" ) == 0 ) + { + + if( strcmp( optarg, "0" ) == 0 || strcmp( optarg, "off" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_NONE; + break; + } + + if( strcmp( optarg, "1" ) == 0 || strcmp( optarg, "last" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_LAST; + break; + } + + if( strcmp( optarg, "2" ) == 0 || strcmp( optarg, "all" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_ALL; + break; + } + + /* Else we do not know this verification level. */ + fprintf( stderr, "Error: Unknown verification level '%s'.\n", optarg ); + exit( EINVAL ); + } + + /* getopt_long should raise on invalid option, so we should never get here. */ + exit( EINVAL ); + + case 'm': /* Method option. */ + + if( strcmp( optarg, "dod522022m" ) == 0 || strcmp( optarg, "dod" ) == 0 ) + { + nwipe_options.method = &nwipe_dod522022m; + break; + } + + if( strcmp( optarg, "dodshort" ) == 0 || strcmp( optarg, "dod3pass" ) == 0 ) + { + nwipe_options.method = &nwipe_dodshort; + break; + } + + if( strcmp( optarg, "gutmann" ) == 0 ) + { + nwipe_options.method = &nwipe_gutmann; + break; + } + + if( strcmp( optarg, "ops2" ) == 0 ) + { + nwipe_options.method = &nwipe_ops2; + break; + } + + if( strcmp( optarg, "random" ) == 0 || strcmp( optarg, "prng" ) == 0 + || strcmp( optarg, "stream" ) == 0 ) + { + nwipe_options.method = &nwipe_random; + break; + } + + if( strcmp( optarg, "zero" ) == 0 || strcmp( optarg, "quick" ) == 0 ) + { + nwipe_options.method = &nwipe_zero; + break; + } + + if( strcmp( optarg, "one" ) == 0 ) + { + nwipe_options.method = &nwipe_one; + break; + } + + if( strcmp( optarg, "verify_zero" ) == 0 ) + { + nwipe_options.method = &nwipe_verify_zero; + break; + } + + if( strcmp( optarg, "verify_one" ) == 0 ) + { + nwipe_options.method = &nwipe_verify_one; + break; + } + + if( strcmp( optarg, "is5enh" ) == 0 ) + { + nwipe_options.method = &nwipe_is5enh; + break; + } + + /* Else we do not know this wipe method. */ + fprintf( stderr, "Error: Unknown wipe method '%s'.\n", optarg ); + exit( EINVAL ); + + case 'l': /* Log file option. */ + + nwipe_options.logfile[strlen( optarg )] = '\0'; + strncpy( nwipe_options.logfile, optarg, sizeof( nwipe_options.logfile ) ); + break; + + case 'P': /* PDFreport path option. */ + + nwipe_options.PDFreportpath[strlen( optarg )] = '\0'; + strncpy( nwipe_options.PDFreportpath, optarg, sizeof( nwipe_options.PDFreportpath ) ); + + /* Command line options will override what's in nwipe.conf */ + if( strcmp( nwipe_options.PDFreportpath, "noPDF" ) == 0 ) + { + nwipe_options.PDF_enable = 0; + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "DISABLED" ); + } + else + { + if( strcmp( nwipe_options.PDFreportpath, "." ) ) + { + /* and if the user has specified a PDF path then enable PDF */ + nwipe_options.PDF_enable = 1; + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "ENABLED" ); + } + } + + break; + + case 'e': /* exclude drives option */ + + idx_drive_chr = 0; + idx_optarg = 0; + idx_drive = 0; + + /* Create an array of excluded drives from the comma separated string */ + while( optarg[idx_optarg] != 0 && idx_drive < MAX_NUMBER_EXCLUDED_DRIVES ) + { + /* drop the leading '=' character if used */ + if( optarg[idx_optarg] == '=' && idx_optarg == 0 ) + { + idx_optarg++; + continue; + } + + if( optarg[idx_optarg] == ',' ) + { + /* terminate string and move onto next drive */ + nwipe_options.exclude[idx_drive++][idx_drive_chr] = 0; + idx_drive_chr = 0; + idx_optarg++; + } + else + { + if( idx_drive_chr < MAX_DRIVE_PATH_LENGTH ) + { + nwipe_options.exclude[idx_drive][idx_drive_chr++] = optarg[idx_optarg++]; + } + else + { + /* This section deals with file names that exceed MAX_DRIVE_PATH_LENGTH */ + nwipe_options.exclude[idx_drive][idx_drive_chr] = 0; + while( optarg[idx_optarg] != 0 && optarg[idx_optarg] != ',' ) + { + idx_optarg++; + } + } + } + if( idx_drive == MAX_NUMBER_EXCLUDED_DRIVES ) + { + fprintf( + stderr, + "The number of excluded drives has reached the programs configured limit, aborting\n" ); + exit( 130 ); + } + } + break; + + case 'h': /* Display help. */ + + display_help(); + break; + + case 'p': /* PRNG option. */ + + if( strcmp( optarg, "mersenne" ) == 0 || strcmp( optarg, "twister" ) == 0 ) + { + nwipe_options.prng = &nwipe_twister; + break; + } + + if( strcmp( optarg, "isaac" ) == 0 ) + { + nwipe_options.prng = &nwipe_isaac; + break; + } + + if( strcmp( optarg, "isaac64" ) == 0 ) + { + nwipe_options.prng = &nwipe_isaac64; + break; + } + + /* Else we do not know this PRNG. */ + fprintf( stderr, "Error: Unknown prng '%s'.\n", optarg ); + exit( EINVAL ); + + case 'q': /* Anonymize serial numbers */ + + nwipe_options.quiet = 1; + break; + + case 'r': /* Rounds option. */ + + if( sscanf( optarg, " %i", &nwipe_options.rounds ) != 1 || nwipe_options.rounds < 1 ) + { + fprintf( stderr, "Error: The rounds argument must be a positive integer.\n" ); + exit( EINVAL ); + } + + break; + + case 'v': /* verbose */ + + nwipe_options.verbose = 1; + break; + + case 'V': /* Version option. */ + + printf( "%s version %s\n", program_name, version_string ); + exit( EXIT_SUCCESS ); + + default: + + /* Bogus command line argument. */ + display_help(); + exit( EINVAL ); + + } /* method */ + + } /* command line options */ + + /* Return the number of options that were processed. */ + return optind; +} + +void nwipe_options_log( void ) +{ + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + + /** + * Prints a manifest of options to the log. + */ + + nwipe_log( NWIPE_LOG_NOTICE, "Program options are set as follows..." ); + + if( nwipe_options.autonuke ) + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (on)", nwipe_options.autonuke ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (off)", nwipe_options.autonuke ); + } + + if( nwipe_options.autopoweroff ) + { + nwipe_log( NWIPE_LOG_NOTICE, " autopoweroff = %i (on)", nwipe_options.autopoweroff ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " autopoweroff = %i (off)", nwipe_options.autopoweroff ); + } + + if( nwipe_options.noblank ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not perform a final blank pass" ); + } + + if( nwipe_options.nowait ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not wait for a key before exiting" ); + } + + if( nwipe_options.nosignals ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not allow signals to interrupt a wipe" ); + } + + if( nwipe_options.nogui ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not show GUI interface" ); + } + + nwipe_log( NWIPE_LOG_NOTICE, " banner = %s", banner ); + + if( nwipe_options.prng == &nwipe_twister ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Mersenne Twister" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Isaac" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac64 ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Isaac64" ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Undefined" ); + } + } + } + + nwipe_log( NWIPE_LOG_NOTICE, " method = %s", nwipe_method_label( nwipe_options.method ) ); + nwipe_log( NWIPE_LOG_NOTICE, " quiet = %i", nwipe_options.quiet ); + nwipe_log( NWIPE_LOG_NOTICE, " rounds = %i", nwipe_options.rounds ); + nwipe_log( NWIPE_LOG_NOTICE, " sync = %i", nwipe_options.sync ); + + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (off)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_LAST: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (last pass)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_ALL: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (all passes)", nwipe_options.verify ); + break; + + default: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i", nwipe_options.verify ); + break; + } +} + +void display_help() +{ + /** + * displays the help section to STDOUT and exits. + */ + + printf( "Usage: %s [options] [device1] [device2] ...\n", program_name ); + printf( "Options:\n" ); + /* Limit line length to a maximum of 80 characters so it looks good in 80x25 terminals i.e shredos */ + /* ___12345678901234567890123456789012345678901234567890123456789012345678901234567890< Do not exceed */ + puts( " -V, --version Prints the version number\n" ); + puts( " -v, --verbose Prints more messages to the log\n" ); + puts( " -h, --help Prints this help\n" ); + puts( " --autonuke If no devices have been specified on the command line," ); + puts( " starts wiping all devices immediately. If devices have" ); + puts( " been specified, starts wiping only those specified" ); + puts( " devices immediately.\n" ); + puts( " --autopoweroff Power off system on completion of wipe delayed for" ); + puts( " for one minute. During this one minute delay you can" ); + puts( " abort the shutdown by typing sudo shutdown -c\n" ); + printf( " --sync=NUM Will perform a sync after NUM writes (default: %d)\n", DEFAULT_SYNC_RATE ); + puts( " 0 - fdatasync after the disk is completely written" ); + puts( " fdatasync errors not detected until completion." ); + puts( " 0 is not recommended as disk errors may cause" ); + puts( " nwipe to appear to hang" ); + puts( " 1 - fdatasync after every write" ); + puts( " Warning: Lower values will reduce wipe speeds." ); + puts( " 1000 - fdatasync after 1000 writes etc.\n" ); + puts( " --verify=TYPE Whether to perform verification of erasure" ); + puts( " (default: last)" ); + puts( " off - Do not verify" ); + puts( " last - Verify after the last pass" ); + puts( " all - Verify every pass\n" ); + puts( " -m, --method=METHOD The wiping method. See man page for more details." ); + puts( " (default: dodshort)" ); + puts( " dod522022m / dod - 7 pass DOD 5220.22-M method" ); + puts( " dodshort / dod3pass - 3 pass DOD method" ); + puts( " gutmann - Peter Gutmann's Algorithm" ); + puts( " ops2 - RCMP TSSIT OPS-II" ); + puts( " random / prng / stream - PRNG Stream" ); + puts( " zero / quick - Overwrite with zeros" ); + puts( " one - Overwrite with ones (0xFF)" ); + puts( " verify_zero - Verifies disk is zero filled" ); + puts( " verify_one - Verifies disk is 0xFF filled\n" ); + puts( " -l, --logfile=FILE Filename to log to. Default is STDOUT\n" ); + puts( " -P, --PDFreportpath=PATH Path to write PDF reports to. Default is \".\"" ); + puts( " If set to \"noPDF\" no PDF reports are written.\n" ); + puts( " -p, --prng=METHOD PRNG option (mersenne|twister|isaac|isaac64)\n" ); + puts( " -q, --quiet Anonymize logs and the GUI by removing unique data, i.e." ); + puts( " serial numbers, LU WWN Device ID, and SMBIOS/DMI data" ); + puts( " XXXXXX = S/N exists, ????? = S/N not obtainable\n" ); + puts( " -r, --rounds=NUM Number of times to wipe the device using the selected" ); + puts( " method (default: 1)\n" ); + puts( " --noblank Do NOT blank disk after wipe" ); + puts( " (default is to complete a final blank pass)\n" ); + puts( " --nowait Do NOT wait for a key before exiting" ); + puts( " (default is to wait)\n" ); + puts( " --nosignals Do NOT allow signals to interrupt a wipe" ); + puts( " (default is to allow)\n" ); + puts( " --nogui Do NOT show the GUI interface. Automatically invokes" ); + puts( " the nowait option. Must be used with the --autonuke" ); + puts( " option. Send SIGUSR1 to log current stats\n" ); + puts( " --nousb Do NOT show or wipe any USB devices whether in GUI" ); + puts( " mode, --nogui or --autonuke modes.\n" ); + puts( " -e, --exclude=DEVICES Up to ten comma separated devices to be excluded" ); + puts( " --exclude=/dev/sdc" ); + puts( " --exclude=/dev/sdc,/dev/sdd" ); + puts( " --exclude=/dev/sdc,/dev/sdd,/dev/mapper/cryptswap1\n" ); + puts( "" ); + exit( EXIT_SUCCESS ); +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..96aeefc --- /dev/null +++ b/src/options.h @@ -0,0 +1,76 @@ +/* + * options.h: Command line processing routines for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ + +/* Program knobs. */ +#define NWIPE_KNOB_ENTROPY "/dev/urandom" +#define NWIPE_KNOB_IDENTITY_SIZE 512 +#define NWIPE_KNOB_LABEL_SIZE 128 +#define NWIPE_KNOB_LOADAVG "/proc/loadavg" +#define NWIPE_KNOB_LOG_BUFFERSIZE 1024 // Maximum length of a log event. +#define NWIPE_KNOB_PARTITIONS "/proc/partitions" +#define NWIPE_KNOB_PARTITIONS_PREFIX "/dev/" +#define NWIPE_KNOB_PRNG_STATE_LENGTH 512 // 128 words +#define NWIPE_KNOB_SCSI "/proc/scsi/scsi" +#define NWIPE_KNOB_SLEEP 1 +#define NWIPE_KNOB_STAT "/proc/stat" +#define MAX_NUMBER_EXCLUDED_DRIVES 32 +#define MAX_DRIVE_PATH_LENGTH 200 // e.g. /dev/sda is only 8 characters long, so 200 should be plenty. +#define DEFAULT_SYNC_RATE 100000 +#define PATHNAME_MAX 2048 + +/* Function prototypes for loading options from the environment and command line. */ +int nwipe_options_parse( int argc, char** argv ); +void nwipe_options_log( void ); + +/* Function to display help text */ +void display_help(); + +typedef struct +{ + int autonuke; // Do not prompt the user for confirmation when set. + int autopoweroff; // Power off on completion of wipe + int noblank; // Do not perform a final blanking pass. + int nousb; // Do not show or wipe any USB devices. + int nowait; // Do not wait for a final key before exiting. + int nosignals; // Do not allow signals to interrupt a wipe. + int nogui; // Do not show the GUI. + char* banner; // The product banner shown on the top line of the screen. + void* method; // A function pointer to the wipe method that will be used. + char logfile[FILENAME_MAX]; // The filename to log the output to. + char PDFreportpath[PATHNAME_MAX]; // The path to write the PDF report to. + char exclude[MAX_NUMBER_EXCLUDED_DRIVES][MAX_DRIVE_PATH_LENGTH]; // Drives excluded from the search. + nwipe_prng_t* prng; // The pseudo random number generator implementation. pointer to the function. + int quiet; // Anonymize serial numbers + int rounds; // The number of times that the wipe method should be called. + int sync; // A flag to indicate whether and how often writes should be sync'd. + int verbose; // Make log more verbose + int PDF_enable; // 0=PDF creation disabled, 1=PDF creation enabled + int PDF_preview_details; // 0=Disable preview Org/Cust/date/time before drive selection, 1=Enable Preview + nwipe_verify_t verify; // A flag to indicate whether writes should be verified. +} nwipe_options_t; + +extern nwipe_options_t nwipe_options; + +#endif /* OPTIONS_H_ */ diff --git a/src/pass.c b/src/pass.c new file mode 100644 index 0000000..9c730da --- /dev/null +++ b/src/pass.c @@ -0,0 +1,911 @@ +/* + * pass.c: Routines that read and write patterns to block devices. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#define _POSIX_C_SOURCE 200809L + +#include <stdint.h> +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "pass.h" +#include "logging.h" +#include "gui.h" + +int nwipe_random_verify( nwipe_context_t* c ) +{ + /** + * Verifies that a random pass was correctly written to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + off64_t offset; + + /* The input buffer. */ + char* b; + + /* The pattern buffer that is used to check the input buffer. */ + char* d; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + if( c->prng_seed.s == NULL ) + { + nwipe_log( NWIPE_LOG_SANITY, "Null seed pointer." ); + return -1; + } + + if( c->prng_seed.length <= 0 ) + { + nwipe_log( NWIPE_LOG_SANITY, "The entropy length member is %i.", c->prng_seed.length ); + return -1; + } + + /* Create the input buffer. */ + b = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( !b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the input buffer." ); + return -1; + } + + /* Create the pattern buffer */ + d = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( !d ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + free( b ); + return -1; + } + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + free( b ); + free( d ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "lseek() returned a bogus offset on '%s'.", c->device_name ); + free( b ); + free( d ); + return -1; + } + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + c->fsyncdata_errors++; + } + + /* Reseed the PRNG. */ + c->prng->init( &c->prng_state, &c->prng_seed ); + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, + c->device_name, + c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + c->prng->read( &c->prng_state, d, blocksize ); + + /* Read the buffer in from the device. */ + r = read( c->device_fd, b, blocksize ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to read from '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial read. */ + if( r != blocksize ) + { + /* TODO: Handle a partial read. */ + + /* The number of bytes that were not read. */ + int s = blocksize - r; + + nwipe_log( + NWIPE_LOG_WARNING, "%s: Partial read from '%s', %i bytes short.", __FUNCTION__, c->device_name, s ); + + /* Increment the error count. */ + c->verify_errors += 1; + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( + NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial read.", c->device_name ); + return -1; + } + + } /* partial read */ + + /* Compare buffer contents. */ + if( memcmp( b, d, blocksize ) != 0 ) + { + c->verify_errors += 1; + } + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* while bytes remaining */ + + /* Release the buffers. */ + free( b ); + free( d ); + + /* We're done. */ + return 0; + +} /* nwipe_random_verify */ + +int nwipe_random_pass( NWIPE_METHOD_SIGNATURE ) +{ + /** + * Writes a random pattern to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + off64_t offset; + + /* The output buffer. */ + char* b; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + /* Number of writes to do before a fdatasync. */ + int syncRate = nwipe_options.sync; + + /* Counter to track when to do a fdatasync. */ + int i = 0; + + /* general index counter */ + int idx; + + if( c->prng_seed.s == NULL ) + { + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: Null seed pointer." ); + return -1; + } + + if( c->prng_seed.length <= 0 ) + { + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: The entropy length member is %i.", c->prng_seed.length ); + return -1; + } + + /* Create the initialised output buffer. Initialised because we don't want memory leaks + * to disk in the event of some future undetected bug in a prng or its implementation. */ + b = calloc( c->device_stat.st_blksize, sizeof( char ) ); + + /* Check the memory allocation. */ + if( !b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the output buffer." ); + return -1; + } + + /* Seed the PRNG. */ + c->prng->init( &c->prng_state, &c->prng_seed ); + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + free( b ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: lseek() returned a bogus offset on '%s'.", c->device_name ); + free( b ); + return -1; + } + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, + c->device_name, + c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + c->prng->read( &c->prng_state, b, blocksize ); + + /* For the first block only, check the prng actually wrote something to the buffer */ + if( z == c->device_size ) + { + idx = c->device_stat.st_blksize; + while( idx > 0 ) + { + if( b[idx] != 0 ) + { + nwipe_log( NWIPE_LOG_NOTICE, "prng stream is active" ); + break; + } + idx--; + } + if( idx == 0 ) + { + nwipe_log( NWIPE_LOG_FATAL, "ERROR, prng wrote nothing to the buffer" ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + } + + /* Write the next block out to the device. */ + r = write( c->device_fd, b, blocksize ); + + /* Check the result for a fatal error. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "write" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to read from '%s'.", c->device_name ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + /* Check for a partial write. */ + if( r != blocksize ) + { + /* TODO: Handle a partial write. */ + + /* The number of bytes that were not written. */ + int s = blocksize - r; + + /* Increment the error count by the number of bytes that were not written. */ + c->pass_errors += s; + + nwipe_log( NWIPE_LOG_WARNING, "Partial write on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( + NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial write.", c->device_name ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + } /* partial write */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + /* Perodic Sync */ + if( syncRate > 0 ) + { + i++; + + if( i >= syncRate ) + { + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + nwipe_log( NWIPE_LOG_WARNING, "Wrote %llu bytes on '%s'.", c->pass_done, c->device_name ); + c->fsyncdata_errors++; + free( b ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + i = 0; + } + } + + pthread_testcancel(); + + /* If statement required so that it does not reset on subsequent passes */ + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + + } /* /remaining bytes */ + + /* Release the output buffer. */ + free( b ); + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + c->fsyncdata_errors++; + if( c->bytes_erased < ( c->device_size - z - blocksize ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z - blocksize; + } + return -1; + } + + /* We're done. */ + return 0; + +} /* nwipe_random_pass */ + +int nwipe_static_verify( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern ) +{ + /** + * Verifies that a static pass was correctly written to the device. + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + off64_t offset; + + /* The input buffer. */ + char* b; + + /* The pattern buffer that is used to check the input buffer. */ + char* d; + + /* A pointer into the pattern buffer. */ + char* q; + + /* The pattern buffer window offset. */ + int w = 0; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + if( pattern == NULL ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: Null entropy pointer." ); + return -1; + } + + if( pattern->length <= 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: The pattern length member is %i.", pattern->length ); + return -1; + } + + /* Create the input buffer. */ + b = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( !b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the input buffer." ); + return -1; + } + + /* Create the pattern buffer */ + d = malloc( c->device_stat.st_blksize + pattern->length * 2 ); + + /* Check the memory allocation. */ + if( !d ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + free( b ); + return -1; + } + + for( q = d; q < d + c->device_stat.st_blksize + pattern->length; q += pattern->length ) + { + /* Fill the pattern buffer with the pattern. */ + memcpy( q, pattern->s, pattern->length ); + } + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + c->fsyncdata_errors++; + } + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + free( b ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: lseek() returned a bogus offset on '%s'.", c->device_name ); + free( b ); + free( d ); + return -1; + } + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, + c->device_name, + c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + /* Read the buffer in from the device. */ + r = read( c->device_fd, b, blocksize ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to read from '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial read. */ + if( r == blocksize ) + { + /* Check every byte in the buffer. */ + if( memcmp( b, &d[w], r ) != 0 ) + { + c->verify_errors += 1; + } + } + else + { + /* The number of bytes that were not read. */ + int s = blocksize - r; + + /* TODO: Handle a partial read. */ + + /* Increment the error count. */ + c->verify_errors += 1; + + nwipe_log( NWIPE_LOG_WARNING, "Partial read on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( + NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial read.", c->device_name ); + return -1; + } + + } /* partial read */ + + /* Adjust the window. */ + w = ( c->device_stat.st_blksize + w ) % pattern->length; + + /* Intuition check: + * If the pattern length evenly divides the block size + * then ( w == 0 ) always. + */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* while bytes remaining */ + + /* Release the buffers. */ + free( b ); + free( d ); + + /* We're done. */ + return 0; + +} /* nwipe_static_verify */ + +int nwipe_static_pass( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern ) +{ + /** + * Writes a static pattern to the device. + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + off64_t offset; + + /* The output buffer. */ + char* b; + + /* A pointer into the output buffer. */ + char* p; + + /* The output buffer window offset. */ + int w = 0; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + /* Number of writes to do before a fdatasync. */ + int syncRate = nwipe_options.sync; + + /* Counter to track when to do a fdatasync. */ + int i = 0; + + if( pattern == NULL ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: Null pattern pointer." ); + return -1; + } + + if( pattern->length <= 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: The pattern length member is %i.", pattern->length ); + return -1; + } + + /* Create the output buffer. */ + b = malloc( c->device_stat.st_blksize + pattern->length * 2 ); + + /* Check the memory allocation. */ + if( !b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + return -1; + } + + for( p = b; p < b + c->device_stat.st_blksize + pattern->length; p += pattern->length ) + { + /* Fill the output buffer with the pattern. */ + memcpy( p, pattern->s, pattern->length ); + } + /// + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: lseek() returned a bogus offset on '%s'.", c->device_name ); + return -1; + } + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, + c->device_name, + c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + /* Write the next block out to the device. */ + r = write( c->device_fd, &b[w], blocksize ); + + /* Check the result for a fatal error. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "write" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to write to '%s'.", c->device_name ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + /* Check for a partial write. */ + if( r != blocksize ) + { + /* TODO: Handle a partial write. */ + + /* The number of bytes that were not written. */ + int s = blocksize - r; + + /* Increment the error count. */ + c->pass_errors += s; + + nwipe_log( NWIPE_LOG_WARNING, "Partial write on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (off64_t) -1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( + NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial write.", c->device_name ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + } /* partial write */ + + /* Adjust the window. */ + w = ( c->device_stat.st_blksize + w ) % pattern->length; + + /* Intuition check: + * + * If the pattern length evenly divides the block size + * then ( w == 0 ) always. + */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counterr. */ + c->pass_done += r; + c->round_done += r; + + /* Perodic Sync */ + if( syncRate > 0 ) + { + i++; + + if( i >= syncRate ) + { + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + nwipe_log( NWIPE_LOG_WARNING, "Wrote %llu bytes on '%s'.", c->pass_done, c->device_name ); + c->fsyncdata_errors++; + free( b ); + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + return -1; + } + + i = 0; + } + } + + pthread_testcancel(); + + if( c->bytes_erased < ( c->device_size - z ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z; + } + + } /* /remaining bytes */ + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + c->fsyncdata_errors++; + if( c->bytes_erased < ( c->device_size - z - blocksize ) ) // How much of the device has been erased? + { + c->bytes_erased = c->device_size - z - blocksize; + } + return -1; + } + + /* Release the output buffer. */ + free( b ); + + /* We're done. */ + return 0; + +} /* nwipe_static_pass */ diff --git a/src/pass.h b/src/pass.h new file mode 100644 index 0000000..8f27f43 --- /dev/null +++ b/src/pass.h @@ -0,0 +1,33 @@ +/* + * pass.h: Routines that read and write patterns to block devices. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef PASS_H_ +#define PASS_H_ + +int nwipe_random_pass( nwipe_context_t* c ); +int nwipe_random_verify( nwipe_context_t* c ); +int nwipe_static_pass( nwipe_context_t* c, nwipe_pattern_t* pattern ); +int nwipe_static_verify( nwipe_context_t* c, nwipe_pattern_t* pattern ); + +void test_functionn( int count, nwipe_context_t** c ); + +#endif /* PASS_H_ */ diff --git a/src/prng.c b/src/prng.c new file mode 100644 index 0000000..45c6cb7 --- /dev/null +++ b/src/prng.c @@ -0,0 +1,252 @@ +/* + * prng.c: Pseudo Random Number Generator abstractions for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "nwipe.h" +#include "prng.h" +#include "context.h" +#include "logging.h" + +#include "mt19937ar-cok/mt19937ar-cok.h" +#include "isaac_rand/isaac_rand.h" +#include "isaac_rand/isaac64.h" + +nwipe_prng_t nwipe_twister = { "Mersenne Twister (mt19937ar-cok)", nwipe_twister_init, nwipe_twister_read }; + +nwipe_prng_t nwipe_isaac = { "ISAAC (rand.c 20010626)", nwipe_isaac_init, nwipe_isaac_read }; +nwipe_prng_t nwipe_isaac64 = { "ISAAC-64 (isaac64.c)", nwipe_isaac64_init, nwipe_isaac64_read }; + +/* Print given number of bytes from unsigned integer number to a byte stream buffer starting with low-endian. */ +static inline void u32_to_buffer( u8* restrict buffer, u32 val, const int len ) +{ + for( int i = 0; i < len; ++i ) + { + buffer[i] = (u8) ( val & 0xFFUL ); + val >>= 8; + } +} +static inline void u64_to_buffer( u8* restrict buffer, u64 val, const int len ) +{ + for( int i = 0; i < len; ++i ) + { + buffer[i] = (u8) ( val & 0xFFULL ); + val >>= 8; + } +} +static inline u32 isaac_nextval( randctx* restrict ctx ) +{ + if( ctx->randcnt == 0 ) + { + isaac( ctx ); + ctx->randcnt = RANDSIZ; + } + ctx->randcnt--; + return ctx->randrsl[ctx->randcnt]; +} +static inline u64 isaac64_nextval( rand64ctx* restrict ctx ) +{ + if( ctx->randcnt == 0 ) + { + isaac64( ctx ); + ctx->randcnt = RANDSIZ; + } + ctx->randcnt--; + return ctx->randrsl[ctx->randcnt]; +} + +int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + nwipe_log( NWIPE_LOG_NOTICE, "Initialising Mersenne Twister prng" ); + + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( twister_state_t ) ); + } + twister_init( (twister_state_t*) *state, (u32*) ( seed->s ), seed->length / sizeof( u32 ) ); + return 0; +} + +int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + u8* restrict bufpos = buffer; + size_t words = count / SIZE_OF_TWISTER; // the values of twister_genrand_int32 is strictly 4 bytes + + /* Twister returns 4-bytes per call, so progress by 4 bytes. */ + for( size_t ii = 0; ii < words; ++ii ) + { + u32_to_buffer( bufpos, twister_genrand_int32( (twister_state_t*) *state ), SIZE_OF_TWISTER ); + bufpos += SIZE_OF_TWISTER; + } + + /* If there is some remainder copy only relevant number of bytes to not + * overflow the buffer. */ + const size_t remain = count % SIZE_OF_TWISTER; // SIZE_OF_TWISTER is strictly 4 bytes + if( remain > 0 ) + { + u32_to_buffer( bufpos, twister_genrand_int32( (twister_state_t*) *state ), remain ); + } + + return 0; +} + +int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + int count; + randctx* isaac_state = *state; + + nwipe_log( NWIPE_LOG_NOTICE, "Initialising Isaac prng" ); + + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( randctx ) ); + isaac_state = *state; + + /* Check the memory allocation. */ + if( isaac_state == 0 ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the isaac state." ); + return -1; + } + } + + /* Take the minimum of the isaac seed size and available entropy. */ + if( sizeof( isaac_state->randrsl ) < seed->length ) + { + count = sizeof( isaac_state->randrsl ); + } + else + { + memset( isaac_state->randrsl, 0, sizeof( isaac_state->randrsl ) ); + count = seed->length; + } + + if( count == 0 ) + { + /* Start ISACC without a seed. */ + randinit( isaac_state, 0 ); + } + else + { + /* Seed the ISAAC state with entropy. */ + memcpy( isaac_state->randrsl, seed->s, count ); + + /* The second parameter indicates that randrsl is non-empty. */ + randinit( isaac_state, 1 ); + } + + return 0; +} + +int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + randctx* isaac_state = *state; + u8* restrict bufpos = buffer; + size_t words = count / SIZE_OF_ISAAC; // the values of isaac is strictly 4 bytes + + /* Isaac returns 4-bytes per call, so progress by 4 bytes. */ + for( size_t ii = 0; ii < words; ++ii ) + { + /* get the next 32bit random number */ + u32_to_buffer( bufpos, isaac_nextval( isaac_state ), SIZE_OF_ISAAC ); + bufpos += SIZE_OF_ISAAC; + } + + /* If there is some remainder copy only relevant number of bytes to not overflow the buffer. */ + const size_t remain = count % SIZE_OF_ISAAC; // SIZE_OF_ISAAC is strictly 4 bytes + if( remain > 0 ) + { + u32_to_buffer( bufpos, isaac_nextval( isaac_state ), remain ); + } + + return 0; +} + +int nwipe_isaac64_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + int count; + rand64ctx* isaac_state = *state; + + nwipe_log( NWIPE_LOG_NOTICE, "Initialising ISAAC-64 prng" ); + + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( rand64ctx ) ); + isaac_state = *state; + + /* Check the memory allocation. */ + if( isaac_state == 0 ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the isaac state." ); + return -1; + } + } + + /* Take the minimum of the isaac seed size and available entropy. */ + if( sizeof( isaac_state->randrsl ) < seed->length ) + { + count = sizeof( isaac_state->randrsl ); + } + else + { + memset( isaac_state->randrsl, 0, sizeof( isaac_state->randrsl ) ); + count = seed->length; + } + + if( count == 0 ) + { + /* Start ISACC without a seed. */ + rand64init( isaac_state, 0 ); + } + else + { + /* Seed the ISAAC state with entropy. */ + memcpy( isaac_state->randrsl, seed->s, count ); + + /* The second parameter indicates that randrsl is non-empty. */ + rand64init( isaac_state, 1 ); + } + + return 0; +} + +int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + rand64ctx* isaac_state = *state; + u8* restrict bufpos = buffer; + size_t words = count / SIZE_OF_ISAAC64; // the values of ISAAC-64 is strictly 8 bytes + + for( size_t ii = 0; ii < words; ++ii ) + { + u64_to_buffer( bufpos, isaac64_nextval( isaac_state ), SIZE_OF_ISAAC64 ); + bufpos += SIZE_OF_ISAAC64; + } + + /* If there is some remainder copy only relevant number of bytes to not overflow the buffer. */ + const size_t remain = count % SIZE_OF_ISAAC64; // SIZE_OF_ISAAC64 is strictly 8 bytes + if( remain > 0 ) + { + u64_to_buffer( bufpos, isaac64_nextval( isaac_state ), remain ); + } + + return 0; +} diff --git a/src/prng.h b/src/prng.h new file mode 100644 index 0000000..8dfa3d7 --- /dev/null +++ b/src/prng.h @@ -0,0 +1,65 @@ +/* + * prng.h: Pseudo Random Number Generator abstractions for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef PRNG_H_ +#define PRNG_H_ + +#include <sys/types.h> + +/* A chunk of random data. */ +typedef struct +{ + size_t length; // Length of the entropy string in bytes. + u8* s; // The actual bytes of the entropy string. +} nwipe_entropy_t; + +#define NWIPE_PRNG_INIT_SIGNATURE void **state, nwipe_entropy_t *seed +#define NWIPE_PRNG_READ_SIGNATURE void **state, void *buffer, size_t count + +/* Function pointers for PRNG actions. */ +typedef int ( *nwipe_prng_init_t )( NWIPE_PRNG_INIT_SIGNATURE ); +typedef int ( *nwipe_prng_read_t )( NWIPE_PRNG_READ_SIGNATURE ); + +/* The generic PRNG definition. */ +typedef struct +{ + const char* label; // The name of the pseudo random number generator. + nwipe_prng_init_t init; // Inialize the prng state with the seed. + nwipe_prng_read_t read; // Read data from the prng. +} nwipe_prng_t; + +/* Mersenne Twister prototypes. */ +int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE ); +int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE ); + +/* ISAAC prototypes. */ +int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE ); +int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE ); +int nwipe_isaac64_init( NWIPE_PRNG_INIT_SIGNATURE ); +int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE ); + +/* Size of the twister is not derived from the architecture, but it is strictly 4 bytes */ +#define SIZE_OF_TWISTER 4 + +/* Size of the isaac/isaac64 is not derived from the architecture, but it is strictly 4 or 8 bytes */ +#define SIZE_OF_ISAAC 4 +#define SIZE_OF_ISAAC64 8 + +#endif /* PRNG_H_ */ diff --git a/src/redcross.jpg b/src/redcross.jpg Binary files differnew file mode 100644 index 0000000..88fffe9 --- /dev/null +++ b/src/redcross.jpg diff --git a/src/te.jpg b/src/te.jpg Binary files differnew file mode 100644 index 0000000..3710146 --- /dev/null +++ b/src/te.jpg diff --git a/src/temperature.c b/src/temperature.c new file mode 100644 index 0000000..19f9446 --- /dev/null +++ b/src/temperature.c @@ -0,0 +1,495 @@ +/* + * temperature.c: functions that populate the drive temperature variables + * in each drives context structure. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +//#define _LARGEFILE64_SOURCE +//#define _FILE_OFFSET_BITS 64 +#define _BSD_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <dirent.h> +#include <sys/time.h> + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "device.h" +#include "prng.h" +#include "options.h" +#include "device.h" +#include "logging.h" +#include "temperature.h" +#include "miscellaneous.h" + +extern int terminate_signal; + +int nwipe_init_temperature( nwipe_context_t* c ) +{ + /* See header definition for description of function + */ + DIR* dir; + DIR* dir2; + const char dirpath[] = "/sys/class/hwmon"; + char dirpath_tmp[256]; + char dirpath_tmp2[256]; + char dirpath_hwmonX[256]; + char device[256]; + char device_context_name[256]; + // const char dirpath[] = "/home/nick/mouse/hwmon1"; + struct dirent* dp; + struct dirent* dp2; + + /* Why Initialise with 1000000 (defined as NO_TEMPERATURE_DATA)? + * Because the GUI needs to know whether data has been obtained + * so it can display appropriate information when a + * device is unable to provide temperature data */ + + c->templ_has_hwmon_data = 0; + c->temp1_crit = NO_TEMPERATURE_DATA; + c->temp1_highest = NO_TEMPERATURE_DATA; + c->temp1_input = NO_TEMPERATURE_DATA; + c->temp1_lcrit = NO_TEMPERATURE_DATA; + c->temp1_lowest = NO_TEMPERATURE_DATA; + c->temp1_max = NO_TEMPERATURE_DATA; + c->temp1_min = NO_TEMPERATURE_DATA; + c->temp1_monitored_wipe_max = NO_TEMPERATURE_DATA; + c->temp1_monitored_wipe_min = NO_TEMPERATURE_DATA; + c->temp1_monitored_wipe_avg = NO_TEMPERATURE_DATA; + c->temp1_flash_rate = 0; + c->temp1_flash_rate_counter = 0; + c->temp1_path[0] = 0; + c->temp1_time = 0; + + /* Each hwmonX directory is processed in turn and once a hwmonX directory has been + * found that is a block device and the block device name matches the drive + * name in the current context then the path to ../hwmonX is constructed and written + * to the drive context structure '* c'. This path is used in the nwipe_update_temperature + * function to retrieve temperature data and store it in the device context + */ + + if( ( dir = opendir( dirpath ) ) != NULL ) + { + /* Process each hwmonX sub directory in turn */ + while( ( dp = readdir( dir ) ) != NULL ) + { + /* Does the directory start with 'hwmon' */ + if( strstr( dp->d_name, "hwmon" ) != NULL ) + { + if( nwipe_options.verbose ) + { + /* print a empty line to separate the different hwmon sensors */ + nwipe_log( NWIPE_LOG_DEBUG, "hwmon:" ); + } + strcpy( dirpath_tmp, dirpath ); + strcat( dirpath_tmp, "/" ); + strcat( dirpath_tmp, dp->d_name ); + strcpy( dirpath_hwmonX, dirpath_tmp ); + strcat( dirpath_tmp, "/device/block" ); + + /* Depending on the class of block device, the device name may + * appear in different sub-directories. So we try to open each + * directory that are known to contain block devices. These are + * /sys/class/hwmon/hwmonX/device/block + * /sys/class/hwmon/hwmonX/device/nvme/nvme0 + * /sys/class/hwmon/hwmonX/device/ + */ + + if( ( dir2 = opendir( dirpath_tmp ) ) == NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "hwmon: %s doesn't exist, trying next path", dirpath_tmp ); + } + strcpy( dirpath_tmp2, dirpath_hwmonX ); + strcat( dirpath_tmp2, "/device/nvme/nvme0" ); + strcpy( dirpath_tmp, dirpath_tmp2 ); + + if( ( dir2 = opendir( dirpath_tmp ) ) == NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "hwmon: %s doesn't exist, trying next path", dirpath_tmp ); + } + + strcpy( dirpath_tmp2, dirpath_hwmonX ); + strcat( dirpath_tmp2, "/device" ); + strcpy( dirpath_tmp, dirpath_tmp2 ); + + if( ( dir2 = opendir( dirpath_tmp ) ) == NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( + NWIPE_LOG_DEBUG, "hwmon: %s doesn't exist, no more paths to try", dirpath_tmp ); + } + continue; + } + } + } + + if( dir2 != NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "hwmon: Found %s", dirpath_tmp ); + } + + /* Read the device name */ + while( ( dp2 = readdir( dir2 ) ) != NULL ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "hwmon: dirpath_tmp=%s/%s", dirpath_tmp, &dp2->d_name[0] ); + } + + /* Skip the '.' and '..' directories */ + if( dp2->d_name[0] == '.' ) + { + continue; + } + strcpy( device, dp2->d_name ); + + /* Create a copy of the device name from the context but strip the path from it, right justify + * device name, prefix with spaces so length is 8. */ + nwipe_strip_path( device_context_name, c->device_name ); + + /* Remove leading/training whitespace from a string and left justify result */ + trim( device_context_name ); + + /* Does the hwmon device match the device for this drive context */ + if( strcmp( device, device_context_name ) != 0 ) + { + /* No, so try next hwmon device */ + continue; + } + else + { + /* Match ! This hwmon device matches this context, so write the hwmonX path to the context + */ + nwipe_log( NWIPE_LOG_NOTICE, "hwmon: %s has temperature monitoring", device, dirpath_tmp ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_DEBUG, "hwmon: %s found in %s", device, dirpath_tmp ); + } + /* Copy the hwmon path to the drive context structure */ + strcpy( c->temp1_path, dirpath_hwmonX ); + c->templ_has_hwmon_data = 1; + } + } + closedir( dir2 ); + } + } + } + closedir( dir ); + } + /* if no hwmon data available try scsi access (SAS Disks are known to be not working in hwmon */ + if( c->templ_has_hwmon_data == 0 && ( c->device_type == NWIPE_DEVICE_SAS || c->device_type == NWIPE_DEVICE_SCSI ) ) + { + nwipe_log( NWIPE_LOG_NOTICE, "no hwmon data for %s, try to get SCSI data", c->device_name ); + if( nwipe_init_scsi_temperature( c ) == 0 ) + { + c->templ_has_scsitemp_data = 1; + nwipe_log( NWIPE_LOG_INFO, "got SCSI temperature data for %s", c->device_name ); + } + else + { + c->templ_has_scsitemp_data = 0; + nwipe_log( NWIPE_LOG_INFO, "got no SCSI temperature data for %s", c->device_name ); + } + } + + return 0; +} + +float timedifference_msec( struct timeval tv_start, struct timeval tv_end ) +{ + /* helper function for time measurement in msec */ + return ( tv_end.tv_sec - tv_start.tv_sec ) * 1000.0f + ( tv_end.tv_usec - tv_start.tv_usec ) / 1000.0f; +} + +void* nwipe_update_temperature_thread( void* ptr ) +{ + int i; + + /* Set up the structs we will use for the data required. */ + nwipe_thread_data_ptr_t* nwipe_thread_data_ptr; + nwipe_context_t** c; + nwipe_misc_thread_data_t* nwipe_misc_thread_data; + + /* Retrieve from the pointer passed to the function. */ + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t*) ptr; + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + + /* mark start second of update */ + time_t nwipe_timemark = time( NULL ); + + /* update immediately on entry to thread */ + for( i = 0; i < nwipe_misc_thread_data->nwipe_enumerated; i++ ) + { + nwipe_update_temperature( c[i] ); + if( terminate_signal == 1 ) + { + break; + } + } + + while( terminate_signal != 1 ) + { + /* Update all drive/s but never repeat checking the + * set of drive/s faster than once every 2 seconds */ + if( time( NULL ) > ( nwipe_timemark + 1 ) ) + { + nwipe_timemark = time( NULL ); + + for( i = 0; i < nwipe_misc_thread_data->nwipe_enumerated; i++ ) + { + nwipe_update_temperature( c[i] ); + } + } + else + { + sleep( 1 ); + } + } + return NULL; +} + +void nwipe_update_temperature( nwipe_context_t* c ) +{ + /* Warning !! This function should only be called by nwipe_update_temperature_thread() + * Due to delays of upto 2 seconds with some drives, especially SAS in obtaining + * temperatures while wiping, the delays being worse the more drives you are wiping. Updating + * temperatures are performed within it's own thread so it doesn't cause momentary freezes + * in the GUI interface. + * + * For the given drive context obtain the path to it's hwmon temperature settings + * and read then write the temperature values back to the context. A numeric ascii to integer conversion is + * performed. The temperaures should be updated no more frequently than every 60 seconds + */ + + char temperature_label[NUMBER_OF_FILES][20] = { + "temp1_crit", "temp1_highest", "temp1_input", "temp1_lcrit", "temp1_lowest", "temp1_max", "temp1_min" }; + int* temperature_pcontext[NUMBER_OF_FILES] = { + + &( c->temp1_crit ), + &( c->temp1_highest ), + &( c->temp1_input ), + &( c->temp1_lcrit ), + &( c->temp1_lowest ), + &( c->temp1_max ), + &( c->temp1_min ) }; + + char path[256]; + char temperature[256]; + FILE* fptr; + int idx; + int result; + struct timeval tv_start; + struct timeval tv_end; + float delta_t; + + /* avoid being called more often than 1x per 60 seconds */ + time_t nwipe_time_now = time( NULL ); + if( nwipe_time_now - c->temp1_time < 60 ) + { + return; + } + + /* measure time it takes to get the temperatures */ + gettimeofday( &tv_start, 0 ); + + /* try to get temperatures from hwmon, standard */ + if( c->templ_has_hwmon_data == 1 ) + { + for( idx = 0; idx < NUMBER_OF_FILES; idx++ ) + { + /* Construct the full path including filename */ + strcpy( path, c->temp1_path ); + strcat( path, "/" ); + strcat( path, &( temperature_label[idx][0] ) ); + + /* Open the file */ + if( ( fptr = fopen( path, "r" ) ) != NULL ) + { + /* Acquire data until we reach a newline */ + result = fscanf( fptr, "%[^\n]", temperature ); + + /* Convert numeric ascii to binary integer */ + *( temperature_pcontext[idx] ) = atoi( temperature ); + + /* Divide by 1000 to get degrees celsius */ + *( temperature_pcontext[idx] ) = *( temperature_pcontext[idx] ) / 1000; + + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_NOTICE, "hwmon: %s %dC", path, *( temperature_pcontext[idx] ) ); + } + + fclose( fptr ); + } + else + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_NOTICE, "hwmon: Unable to open %s", path ); + } + } + } + } + else + { + /* alternative method to get temperature from SCSI/SAS disks */ + if( c->device_type == NWIPE_DEVICE_SAS || c->device_type == NWIPE_DEVICE_SCSI ) + { + if( c->templ_has_scsitemp_data == 1 ) + { + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_crit %dC", c->device_name, c->temp1_crit ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_highest %dC", c->device_name, c->temp1_highest ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_input %dC", c->device_name, c->temp1_input ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_lcrit %dC", c->device_name, c->temp1_lcrit ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_lowest %dC", c->device_name, c->temp1_lowest ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_max %dC", c->device_name, c->temp1_max ); + nwipe_log( NWIPE_LOG_NOTICE, "hddtemp: %s temp1_min %dC", c->device_name, c->temp1_min ); + } + if( nwipe_get_scsi_temperature( c ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "get_scsi_temperature error" ); + } + } + } + } + + /* Update the time stamp that records when we checked the temperature, + * this is used by the GUI to check temperatures periodically, typically + * every 60 seconds */ + c->temp1_time = time( NULL ); + + gettimeofday( &tv_end, 0 ); + delta_t = timedifference_msec( tv_start, tv_end ); + if( nwipe_options.verbose ) + { + nwipe_log( NWIPE_LOG_NOTICE, "get temperature for %s took %f ms", c->device_name, delta_t ); + } + + return; +} + +void nwipe_log_drives_temperature_limits( nwipe_context_t* c ) +{ + /* See header for description of function + */ + + char temperature_limits_txt[500]; + + int idx = 0; + + /* + * Initialise the character string, as we are building it a few + * characters at a time and it's important there it is populated + * with all zeros as we are using strlen() as we build the line up. + */ + memset( &temperature_limits_txt, 0, sizeof( temperature_limits_txt ) ); + + if( c->temp1_crit != NO_TEMPERATURE_DATA ) + { + snprintf( temperature_limits_txt, + sizeof( temperature_limits_txt ), + "Temperature limits for %s, critical=%ic, ", + c->device_name, + c->temp1_crit ); + } + else + { + snprintf( temperature_limits_txt, + sizeof( temperature_limits_txt ), + "Temperature limits for %s, critical=N/A, ", + c->device_name ); + } + + idx = strlen( temperature_limits_txt ); + + if( c->temp1_max != NO_TEMPERATURE_DATA ) + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "max=%ic, ", c->temp1_max ); + } + else + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "max=N/A, " ); + } + + idx = strlen( temperature_limits_txt ); + + if( c->temp1_highest != NO_TEMPERATURE_DATA ) + { + snprintf( &temperature_limits_txt[idx], + ( sizeof( temperature_limits_txt ) - idx ), + "highest=%ic, ", + c->temp1_highest ); + } + else + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "highest=N/A, " ); + } + + idx = strlen( temperature_limits_txt ); + + if( c->temp1_lowest != NO_TEMPERATURE_DATA ) + { + snprintf( + &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "lowest=%ic, ", c->temp1_lowest ); + } + else + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "lowest=N/A, " ); + } + + idx = strlen( temperature_limits_txt ); + + if( c->temp1_min != NO_TEMPERATURE_DATA ) + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "min=%ic, ", c->temp1_min ); + } + else + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "min=N/A, " ); + } + + idx = strlen( temperature_limits_txt ); + + if( c->temp1_lcrit != NO_TEMPERATURE_DATA ) + { + snprintf( &temperature_limits_txt[idx], + ( sizeof( temperature_limits_txt ) - idx ), + "low critical=%ic.", + c->temp1_lcrit ); + } + else + { + snprintf( &temperature_limits_txt[idx], ( sizeof( temperature_limits_txt ) - idx ), "low critical=N/A. " ); + } + + nwipe_log( NWIPE_LOG_INFO, "%s", temperature_limits_txt ); + + return; +} diff --git a/src/temperature.h b/src/temperature.h new file mode 100644 index 0000000..b07b091 --- /dev/null +++ b/src/temperature.h @@ -0,0 +1,61 @@ +/* + * temperature.h: The header file for disk drive temperature sensing + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef TEMPERATURE_H_ +#define TEMPERATURE_H_ + +#include <sys/types.h> +#include "context.h" + +/** + * This function is called after each nwipe_context_t has been created. + * It initialises the temperature variables in each context and then + * constructs a path that is placed in the context that points to the + * appropriate /sys/class/hwmon/hwmonX directory that corresponds with + * the particular drive represented in the context structure. + * @param pointer to a drive context + * @return returns 0 on success < 1 on error + */ +int nwipe_init_temperature( nwipe_context_t* ); + +void nwipe_update_temperature( nwipe_context_t* ); + +/** + * Workaround for obtaining temperatures from SCSI/SAS drives + * @param pointer to a drive context + * @return returns 0 on success < 1 on error + */ +int nwipe_init_scsi_temperature( nwipe_context_t* ); +int nwipe_get_scsi_temperature( nwipe_context_t* ); +void nwipe_shut_scsi_temperature( nwipe_context_t* ); +void* nwipe_update_temperature_thread( void* ptr ); + +/** + * This function is normally called only once. It's called after both the + * nwipe_init_temperature() function and nwipe_update_temperature() + * functions have been called. It logs the drives critical, highest, lowest + * and lowest critical temperatures. Not all drives report four temperatures. + * @param pointer to a drive context + */ +void nwipe_log_drives_temperature_limits( nwipe_context_t* ); + +#define NUMBER_OF_FILES 7 + +#define NO_TEMPERATURE_DATA 1000000 + +#endif /* TEMPERATURE_H_ */ diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..cbaa106 --- /dev/null +++ b/src/version.c @@ -0,0 +1,17 @@ +/** + * version_string and program_name are used by siege + * and configure; author_name and email_address are + * used by configure to dynamically assign those values + * to documentation files. + */ +const char* version_string = "0.36"; +const char* program_name = "nwipe"; +const char* author_name = "Martijn van Brummelen"; +const char* email_address = "git@brumit.nl"; +const char* years = "2024"; +const char* copyright = "Copyright Darik Horn <dajhorn-dban@vanadac.com>\n\ +Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com>\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty; not even for MERCHANTABILITY or FITNESS\n\ +FOR A PARTICULAR PURPOSE.\n"; +const char* banner = "nwipe 0.36"; diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..b1214b2 --- /dev/null +++ b/src/version.h @@ -0,0 +1,11 @@ +#ifndef __VERSION_H +#define __VERSION_H + +extern char* version_string; +extern char* program_name; +extern char* author_name; +extern char* email_address; +extern char* copyright; +extern char* banner; + +#endif /*__VERSION_H*/ |