From f06c70feed0941b5bceedcecf89e9aa22034aca8 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Fri, 1 Feb 2013 10:27:10 +0800 Subject: [PATCH] sync with rtgui-0.6 --- components/external/lzo/README.LZO | 248 +-- components/external/lzo/lzo.c | 7 +- components/external/tjpgd1a/SConscript | 8 +- components/rtgui/.gitignore | 2 + components/rtgui/Doxyfile | 1826 +++++++++++++++++ components/rtgui/SConscript | 2 + components/rtgui/common/asc12font.c | 291 +-- components/rtgui/common/asc16font.c | 356 +--- components/rtgui/common/dc_hw.c | 7 - components/rtgui/common/font_bmp.c | 5 +- components/rtgui/common/image_jpg.c | 2 + components/rtgui/common/region.c | 10 + components/rtgui/common/rtgui_app.c | 90 +- components/rtgui/common/rtgui_mv_model.c | 2 +- components/rtgui/common/rtgui_system.c | 60 +- components/rtgui/common/rtgui_theme.c | 23 +- components/rtgui/doc/ANNOUNCE.0.6.md | 69 + .../rtgui/doc/{ => historical}/road_map.txt | 0 components/rtgui/doc/mv-model.dox | 81 + components/rtgui/include/rtgui/dc.h | 8 + components/rtgui/include/rtgui/driver.h | 39 +- components/rtgui/include/rtgui/event.h | 6 +- components/rtgui/include/rtgui/region.h | 111 +- components/rtgui/include/rtgui/rtgui.h | 5 + components/rtgui/include/rtgui/rtgui_app.h | 23 +- components/rtgui/include/rtgui/rtgui_server.h | 4 +- components/rtgui/include/rtgui/rtgui_system.h | 12 +- .../rtgui/include/rtgui/widgets/digfont.h | 36 + .../rtgui/include/rtgui/widgets/digtube.h | 68 + components/rtgui/include/rtgui/widgets/menu.h | 2 +- .../rtgui/include/rtgui/widgets/textbox.h | 22 +- .../rtgui/include/rtgui/widgets/widget.h | 199 +- .../rtgui/include/rtgui/widgets/window.h | 2 +- components/rtgui/server/driver.c | 37 + components/rtgui/server/mouse.c | 15 + components/rtgui/server/mouse.h | 2 + components/rtgui/server/server.c | 73 +- components/rtgui/server/topwin.c | 20 +- components/rtgui/utils/perfect_hash/README | 49 + .../rtgui/utils/perfect_hash/__init__.py | 0 .../rtgui/utils/perfect_hash/animals.txt | 7 + .../rtgui/utils/perfect_hash/doc/Makefile | 22 + .../utils/perfect_hash/doc/czech92optimal.pdf | Bin 0 -> 191651 bytes .../rtgui/utils/perfect_hash/doc/doc.html | 136 ++ .../rtgui/utils/perfect_hash/doc/doc.in | 130 ++ .../rtgui/utils/perfect_hash/doc/doc.txt | 141 ++ .../rtgui/utils/perfect_hash/doc/mktable.py | 22 + .../utils/perfect_hash/doc/parameters.txt | 11 + .../utils/perfect_hash/example-C++/Makefile | 31 + .../utils/perfect_hash/example-C++/main.cc | 24 + .../perfect_hash/example-C++/mk_header.py | 10 + .../perfect_hash/example-C++/states-code.hh | 19 + .../perfect_hash/example-C++/states-tmpl.cc | 55 + .../utils/perfect_hash/example-C++/states.dat | 52 + .../perfect_hash/example-PyModule/Makefile | 26 + .../example-PyModule/stations-tmpl.h | 12 + .../example-PyModule/stations.dat | 500 +++++ .../example-PyModule/stationsmodule.c | 69 + .../perfect_hash/example-PyModule/test.py | 28 + .../perfect_hash/example-Python/Graph.py | 40 + .../perfect_hash/example-Python/Makefile | 15 + .../perfect_hash/example-Python/PerfHash.py | 40 + .../example-Python/generate_hash.py | 38 + .../utils/perfect_hash/example1-C/Makefile | 31 + .../utils/perfect_hash/example1-C/main.c | 33 + .../perfect_hash/example1-C/mk_header.py | 10 + .../perfect_hash/example1-C/states-code.h | 6 + .../perfect_hash/example1-C/states-tmpl.c | 42 + .../utils/perfect_hash/example1-C/states.dat | 52 + .../utils/perfect_hash/example2-C/Makefile | 22 + .../utils/perfect_hash/example2-C/keys.tmpl.h | 13 + .../utils/perfect_hash/example2-C/main.c | 51 + .../perfect_hash/example2-C/mk_rnd_keys.py | 17 + .../rtgui/utils/perfect_hash/graph/Makefile | 23 + .../utils/perfect_hash/graph/example-pipeline | 4 + .../rtgui/utils/perfect_hash/graph/py2dot | 216 ++ .../rtgui/utils/perfect_hash/perfect_hash.py | 870 ++++++++ components/rtgui/utils/perfect_hash/run | 32 + components/rtgui/utils/stract_cjk.py | 163 ++ components/rtgui/widgets/box.c | 12 +- components/rtgui/widgets/button.c | 14 +- components/rtgui/widgets/combobox.c | 8 +- components/rtgui/widgets/digfont.c | 309 +++ components/rtgui/widgets/digtube.c | 174 ++ components/rtgui/widgets/filelist_view.c | 2 +- components/rtgui/widgets/menu.c | 14 +- components/rtgui/widgets/notebook.c | 3 +- components/rtgui/widgets/radiobox.c | 8 +- components/rtgui/widgets/slider.c | 8 +- components/rtgui/widgets/staticline.c | 8 +- components/rtgui/widgets/textbox.c | 46 +- components/rtgui/widgets/widget.c | 26 +- components/rtgui/widgets/window.c | 50 +- examples/gui/SConscript | 1 + examples/gui/demo_application.c | 3 +- examples/gui/demo_plot.c | 13 +- examples/gui/demo_view_benchmark.c | 4 +- examples/gui/demo_view_box.c | 2 +- examples/gui/demo_view_button.c | 40 +- examples/gui/demo_view_checkbox.c | 40 +- examples/gui/demo_view_combobox.c | 14 +- examples/gui/demo_view_digtube.c | 56 + examples/gui/demo_view_edit.c | 34 +- examples/gui/demo_view_label.c | 64 +- examples/gui/demo_view_listbox.c | 20 +- examples/gui/demo_view_menu.c | 16 +- examples/gui/demo_view_mywidget.c | 20 +- examples/gui/demo_view_notebook.c | 12 +- examples/gui/demo_view_radiobox.c | 32 +- 109 files changed, 6724 insertions(+), 1164 deletions(-) create mode 100644 components/rtgui/.gitignore create mode 100644 components/rtgui/Doxyfile create mode 100644 components/rtgui/doc/ANNOUNCE.0.6.md rename components/rtgui/doc/{ => historical}/road_map.txt (100%) create mode 100644 components/rtgui/doc/mv-model.dox create mode 100644 components/rtgui/include/rtgui/widgets/digfont.h create mode 100644 components/rtgui/include/rtgui/widgets/digtube.h create mode 100644 components/rtgui/utils/perfect_hash/README create mode 100644 components/rtgui/utils/perfect_hash/__init__.py create mode 100644 components/rtgui/utils/perfect_hash/animals.txt create mode 100644 components/rtgui/utils/perfect_hash/doc/Makefile create mode 100644 components/rtgui/utils/perfect_hash/doc/czech92optimal.pdf create mode 100644 components/rtgui/utils/perfect_hash/doc/doc.html create mode 100644 components/rtgui/utils/perfect_hash/doc/doc.in create mode 100644 components/rtgui/utils/perfect_hash/doc/doc.txt create mode 100644 components/rtgui/utils/perfect_hash/doc/mktable.py create mode 100644 components/rtgui/utils/perfect_hash/doc/parameters.txt create mode 100644 components/rtgui/utils/perfect_hash/example-C++/Makefile create mode 100644 components/rtgui/utils/perfect_hash/example-C++/main.cc create mode 100644 components/rtgui/utils/perfect_hash/example-C++/mk_header.py create mode 100644 components/rtgui/utils/perfect_hash/example-C++/states-code.hh create mode 100644 components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc create mode 100644 components/rtgui/utils/perfect_hash/example-C++/states.dat create mode 100644 components/rtgui/utils/perfect_hash/example-PyModule/Makefile create mode 100644 components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h create mode 100644 components/rtgui/utils/perfect_hash/example-PyModule/stations.dat create mode 100644 components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c create mode 100644 components/rtgui/utils/perfect_hash/example-PyModule/test.py create mode 100644 components/rtgui/utils/perfect_hash/example-Python/Graph.py create mode 100644 components/rtgui/utils/perfect_hash/example-Python/Makefile create mode 100644 components/rtgui/utils/perfect_hash/example-Python/PerfHash.py create mode 100644 components/rtgui/utils/perfect_hash/example-Python/generate_hash.py create mode 100644 components/rtgui/utils/perfect_hash/example1-C/Makefile create mode 100644 components/rtgui/utils/perfect_hash/example1-C/main.c create mode 100644 components/rtgui/utils/perfect_hash/example1-C/mk_header.py create mode 100644 components/rtgui/utils/perfect_hash/example1-C/states-code.h create mode 100644 components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c create mode 100644 components/rtgui/utils/perfect_hash/example1-C/states.dat create mode 100644 components/rtgui/utils/perfect_hash/example2-C/Makefile create mode 100644 components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h create mode 100644 components/rtgui/utils/perfect_hash/example2-C/main.c create mode 100644 components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py create mode 100644 components/rtgui/utils/perfect_hash/graph/Makefile create mode 100644 components/rtgui/utils/perfect_hash/graph/example-pipeline create mode 100644 components/rtgui/utils/perfect_hash/graph/py2dot create mode 100644 components/rtgui/utils/perfect_hash/perfect_hash.py create mode 100644 components/rtgui/utils/perfect_hash/run create mode 100644 components/rtgui/utils/stract_cjk.py create mode 100644 components/rtgui/widgets/digfont.c create mode 100644 components/rtgui/widgets/digtube.c create mode 100644 examples/gui/demo_view_digtube.c diff --git a/components/external/lzo/README.LZO b/components/external/lzo/README.LZO index e725437827..058eace70a 100644 --- a/components/external/lzo/README.LZO +++ b/components/external/lzo/README.LZO @@ -1,124 +1,124 @@ - - ============================================================================ - miniLZO -- mini subset of the LZO real-time data compression library - ============================================================================ - - Author : Markus Franz Xaver Johannes Oberhumer - - http://www.oberhumer.com/opensource/lzo/ - Version : 2.06 - Date : 12 Aug 2011 - - I've created miniLZO for projects where it is inconvenient to - include (or require) the full LZO source code just because you - want to add a little bit of data compression to your application. - - miniLZO implements the LZO1X-1 compressor and both the standard and - safe LZO1X decompressor. Apart from fast compression it also useful - for situations where you want to use pre-compressed data files (which - must have been compressed with LZO1X-999). - - miniLZO consists of one C source file and three header files: - minilzo.c - minilzo.h, lzoconf.h, lzodefs.h - - To use miniLZO just copy these files into your source directory, add - minilzo.c to your Makefile and #include minilzo.h from your program. - Note: you also must distribute this file ('README.LZO') with your project. - - minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and - the sources are about 30 KiB when packed with zip - so there's no more - excuse that your application doesn't support data compression :-) - - For more information, documentation, example programs and other support - files (like Makefiles and build scripts) please download the full LZO - package from - http://www.oberhumer.com/opensource/lzo/ - - Have fun, - Markus - - - P.S. minilzo.c is generated automatically from the LZO sources and - therefore functionality is completely identical - - - Appendix A: building miniLZO - ---------------------------- - miniLZO is written such a way that it should compile and run - out-of-the-box on most machines. - - If you are running on a very unusual architecture and lzo_init() fails then - you should first recompile with '-DLZO_DEBUG' to see what causes the failure. - The most probable case is something like 'sizeof(void *) != sizeof(size_t)'. - After identifying the problem you can compile by adding some defines - like '-DSIZEOF_VOID_P=8' to your Makefile. - - The best solution is (of course) using Autoconf - if your project uses - Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler - flags when compiling minilzo.c. See the LZO distribution for an example - how to set up configure.ac. - - - Appendix B: list of public functions available in miniLZO - --------------------------------------------------------- - Library initialization - lzo_init() - - Compression - lzo1x_1_compress() - - Decompression - lzo1x_decompress() - lzo1x_decompress_safe() - - Checksum functions - lzo_adler32() - - Version functions - lzo_version() - lzo_version_string() - lzo_version_date() - - Portable (but slow) string functions - lzo_memcmp() - lzo_memcpy() - lzo_memmove() - lzo_memset() - - - Appendix C: suggested macros for 'configure.ac' when using Autoconf - ------------------------------------------------------------------- - Checks for typedefs and structures - AC_CHECK_TYPE(ptrdiff_t,long) - AC_TYPE_SIZE_T - AC_CHECK_SIZEOF(short) - AC_CHECK_SIZEOF(int) - AC_CHECK_SIZEOF(long) - AC_CHECK_SIZEOF(long long) - AC_CHECK_SIZEOF(__int64) - AC_CHECK_SIZEOF(void *) - AC_CHECK_SIZEOF(size_t) - AC_CHECK_SIZEOF(ptrdiff_t) - - Checks for compiler characteristics - AC_C_CONST - - Checks for library functions - AC_CHECK_FUNCS(memcmp memcpy memmove memset) - - - Appendix D: Copyright - --------------------- - LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Markus Franz Xaver Oberhumer . - - LZO and miniLZO are distributed under the terms of the GNU General - Public License (GPL). See the file COPYING. - - Special licenses for commercial and other applications which - are not willing to accept the GNU General Public License - are available by contacting the author. - - + + ============================================================================ + miniLZO -- mini subset of the LZO real-time data compression library + ============================================================================ + + Author : Markus Franz Xaver Johannes Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + Version : 2.06 + Date : 12 Aug 2011 + + I've created miniLZO for projects where it is inconvenient to + include (or require) the full LZO source code just because you + want to add a little bit of data compression to your application. + + miniLZO implements the LZO1X-1 compressor and both the standard and + safe LZO1X decompressor. Apart from fast compression it also useful + for situations where you want to use pre-compressed data files (which + must have been compressed with LZO1X-999). + + miniLZO consists of one C source file and three header files: + minilzo.c + minilzo.h, lzoconf.h, lzodefs.h + + To use miniLZO just copy these files into your source directory, add + minilzo.c to your Makefile and #include minilzo.h from your program. + Note: you also must distribute this file ('README.LZO') with your project. + + minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and + the sources are about 30 KiB when packed with zip - so there's no more + excuse that your application doesn't support data compression :-) + + For more information, documentation, example programs and other support + files (like Makefiles and build scripts) please download the full LZO + package from + http://www.oberhumer.com/opensource/lzo/ + + Have fun, + Markus + + + P.S. minilzo.c is generated automatically from the LZO sources and + therefore functionality is completely identical + + + Appendix A: building miniLZO + ---------------------------- + miniLZO is written such a way that it should compile and run + out-of-the-box on most machines. + + If you are running on a very unusual architecture and lzo_init() fails then + you should first recompile with '-DLZO_DEBUG' to see what causes the failure. + The most probable case is something like 'sizeof(void *) != sizeof(size_t)'. + After identifying the problem you can compile by adding some defines + like '-DSIZEOF_VOID_P=8' to your Makefile. + + The best solution is (of course) using Autoconf - if your project uses + Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler + flags when compiling minilzo.c. See the LZO distribution for an example + how to set up configure.ac. + + + Appendix B: list of public functions available in miniLZO + --------------------------------------------------------- + Library initialization + lzo_init() + + Compression + lzo1x_1_compress() + + Decompression + lzo1x_decompress() + lzo1x_decompress_safe() + + Checksum functions + lzo_adler32() + + Version functions + lzo_version() + lzo_version_string() + lzo_version_date() + + Portable (but slow) string functions + lzo_memcmp() + lzo_memcpy() + lzo_memmove() + lzo_memset() + + + Appendix C: suggested macros for 'configure.ac' when using Autoconf + ------------------------------------------------------------------- + Checks for typedefs and structures + AC_CHECK_TYPE(ptrdiff_t,long) + AC_TYPE_SIZE_T + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(long long) + AC_CHECK_SIZEOF(__int64) + AC_CHECK_SIZEOF(void *) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(ptrdiff_t) + + Checks for compiler characteristics + AC_C_CONST + + Checks for library functions + AC_CHECK_FUNCS(memcmp memcpy memmove memset) + + + Appendix D: Copyright + --------------------- + LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Markus Franz Xaver Oberhumer . + + LZO and miniLZO are distributed under the terms of the GNU General + Public License (GPL). See the file COPYING. + + Special licenses for commercial and other applications which + are not willing to accept the GNU General Public License + are available by contacting the author. + + diff --git a/components/external/lzo/lzo.c b/components/external/lzo/lzo.c index 357cf8c82a..e9c421b256 100644 --- a/components/external/lzo/lzo.c +++ b/components/external/lzo/lzo.c @@ -19,13 +19,8 @@ #ifdef _WIN32 #pragma warning(disable: 4996) -#include -#include -#include -#include -#else -#include #endif +#include /* the worst of allocation */ #define LZO1X_WORST(x) ( (x) + ((x)/16) + 64 + 3 ) diff --git a/components/external/tjpgd1a/SConscript b/components/external/tjpgd1a/SConscript index 8f8200e134..d5db35385f 100644 --- a/components/external/tjpgd1a/SConscript +++ b/components/external/tjpgd1a/SConscript @@ -1,11 +1,13 @@ +Import('RTT_ROOT') +Import('rtconfig') from building import * -cwd = GetCurrentDir() -CPPPATH = [cwd] -src = Split(''' +src = Split(''' tjpgd.c ''') +CPPPATH = [RTT_ROOT + '/components/external/tjpgd1a'] + group = DefineGroup('tjpgd', src, depend = ['RTGUI_IMAGE_TJPGD'], CPPPATH = CPPPATH) Return('group') diff --git a/components/rtgui/.gitignore b/components/rtgui/.gitignore new file mode 100644 index 0000000000..b38864776e --- /dev/null +++ b/components/rtgui/.gitignore @@ -0,0 +1,2 @@ +common/font_cmp_hz*.c +doc/doxygened/ diff --git a/components/rtgui/Doxyfile b/components/rtgui/Doxyfile new file mode 100644 index 0000000000..5c7700759e --- /dev/null +++ b/components/rtgui/Doxyfile @@ -0,0 +1,1826 @@ +# Doxyfile 1.8.1.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "RT-GUI" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc/doxygened + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = Chinese + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = utils/perfect_hash + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/components/rtgui/SConscript b/components/rtgui/SConscript index e59a14a664..c68721663c 100644 --- a/components/rtgui/SConscript +++ b/components/rtgui/SConscript @@ -72,6 +72,8 @@ widgets/edit.c widgets/mv_view.c widgets/plot.c widgets/plot_curve.c +widgets/digtube.c +widgets/digfont.c """) if GetDepend('RTGUI_USING_FONT_COMPACT'): diff --git a/components/rtgui/common/asc12font.c b/components/rtgui/common/asc12font.c index 10788e7b96..4aaf82949e 100644 --- a/components/rtgui/common/asc12font.c +++ b/components/rtgui/common/asc12font.c @@ -15,198 +15,101 @@ const rt_uint8_t asc12_font[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, - 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, - 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, - 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, - 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3c, - 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, - 0xc3, 0xff, 0xff, 0xff, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, - 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, - 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, - 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, - 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x06, 0x0e, 0x1e, 0x3e, - 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, - 0x18, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, - 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0xc6, 0x60, 0x38, 0x6c, - 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, - 0xfe, 0xfe, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, - 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x50, 0x50, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x40, 0x40, 0x38, 0x48, 0x70, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20, 0x50, 0x20, - 0x0c, 0x70, 0x08, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x20, 0x54, 0x48, - 0x34, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x20, 0x20, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x10, 0x7c, 0x10, 0x28, 0x28, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfc, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x00, 0x00, - 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x20, 0x44, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x18, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x14, 0x14, 0x24, 0x44, 0x7c, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, - 0x38, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x78, 0x44, 0x44, 0x44, - 0x38, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, - 0x44, 0x3c, 0x04, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x30, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x10, 0x60, 0x80, 0x60, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x18, 0x04, 0x18, 0x20, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x38, 0x44, 0x44, 0x4c, 0x54, 0x54, 0x4c, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x30, 0x10, 0x28, - 0x28, 0x28, 0x7c, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x44, 0x44, 0x78, 0x44, 0x44, 0x44, - 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x48, 0x44, 0x44, 0x44, 0x44, 0x48, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x44, 0x50, - 0x70, 0x50, 0x40, 0x44, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x20, 0x28, 0x38, 0x28, 0x20, 0x20, - 0x70, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x4c, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0xec, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x08, 0x08, 0x48, 0x48, 0x48, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x48, 0x50, 0x70, 0x48, 0x44, 0xe4, 0x00, 0x00, 0x00, - 0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x6c, - 0x54, 0x54, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0xec, 0x64, 0x64, 0x54, 0x54, 0x54, 0x4c, - 0xec, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x24, 0x24, 0x24, 0x38, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x38, 0x1c, 0x00, 0x00, 0x00, 0xf8, 0x44, 0x44, 0x44, 0x78, 0x48, 0x44, - 0xe0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x4c, 0x40, 0x38, 0x04, 0x04, 0x64, 0x58, 0x00, 0x00, 0x00, - 0x00, 0xfc, 0x90, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, - 0x10, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, 0x00, - 0x00, 0xc4, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x28, - 0x28, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x08, 0x10, 0x10, 0x20, 0x44, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, - 0x00, 0x40, 0x20, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x38, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x10, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, - 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, - 0x44, 0x3c, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, - 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, - 0x44, 0x7c, 0x40, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x38, 0x00, - 0x00, 0xc0, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, - 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x78, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x70, 0x00, 0x00, 0xc0, 0x40, 0x5c, 0x48, 0x70, 0x50, 0x48, 0xdc, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, - 0x54, 0x54, 0x54, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x64, 0x44, 0x44, 0x44, - 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x64, 0x44, 0x44, 0x44, 0x78, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x34, - 0x4c, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x30, 0x20, 0x20, 0x20, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x38, 0x04, 0x44, 0x78, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, - 0x44, 0x44, 0x44, 0x4c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x28, 0x28, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xcc, 0x48, 0x30, 0x30, 0x48, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, - 0x44, 0x24, 0x28, 0x18, 0x10, 0x10, 0x78, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x48, 0x10, 0x20, 0x44, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x08, 0x00, - 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, - 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x58, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/ + 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00,/*"!",1*/ + 0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/ + 0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00,/*"#",3*/ + 0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00,/*"$",4*/ + 0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00,/*"%",5*/ + 0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00,/*"&",6*/ + 0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/ + 0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00,/*"(",8*/ + 0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00,/*")",9*/ + 0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00,/*"*",10*/ + 0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00,/*"+",11*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80,/*",",12*/ + 0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,/*".",14*/ + 0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00,/*"/",15*/ + 0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,/*"0",16*/ + 0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"1",17*/ + 0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00,/*"2",18*/ + 0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00,/*"3",19*/ + 0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00,/*"4",20*/ + 0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00,/*"5",21*/ + 0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00,/*"6",22*/ + 0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00,/*"7",23*/ + 0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00,/*"8",24*/ + 0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00,/*"9",25*/ + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00,/*":",26*/ + 0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00,/*";",27*/ + 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00,/*"<",28*/ + 0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,/*"=",29*/ + 0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00,/*">",30*/ + 0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00,/*"?",31*/ + 0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00,/*"@",32*/ + 0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00,/*"A",33*/ + 0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00,/*"B",34*/ + 0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00,/*"C",35*/ + 0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00,/*"D",36*/ + 0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00,/*"E",37*/ + 0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00,/*"F",38*/ + 0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00,/*"G",39*/ + 0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00,/*"H",40*/ + 0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"I",41*/ + 0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00,/*"J",42*/ + 0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00,/*"K",43*/ + 0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00,/*"L",44*/ + 0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00,/*"M",45*/ + 0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00,/*"N",46*/ + 0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,/*"O",47*/ + 0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00,/*"P",48*/ + 0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00,/*"Q",49*/ + 0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00,/*"R",50*/ + 0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00,/*"S",51*/ + 0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"T",52*/ + 0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00,/*"U",53*/ + 0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00,/*"V",54*/ + 0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00,/*"W",55*/ + 0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00,/*"X",56*/ + 0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"Y",57*/ + 0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00,/*"Z",58*/ + 0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00,/*"[",59*/ + 0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00,/*"\",60*/ + 0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00,/*"]",61*/ + 0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,/*"_",63*/ + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/ + 0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00,/*"a",65*/ + 0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00,/*"b",66*/ + 0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00,/*"c",67*/ + 0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00,/*"d",68*/ + 0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00,/*"e",69*/ + 0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00,/*"f",70*/ + 0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38,/*"g",71*/ + 0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00,/*"h",72*/ + 0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00,/*"i",73*/ + 0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0,/*"j",74*/ + 0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00,/*"k",75*/ + 0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"l",76*/ + 0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00,/*"m",77*/ + 0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00,/*"n",78*/ + 0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,/*"o",79*/ + 0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0,/*"p",80*/ + 0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C,/*"q",81*/ + 0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00,/*"r",82*/ + 0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00,/*"s",83*/ + 0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,/*"t",84*/ + 0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00,/*"u",85*/ + 0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00,/*"v",86*/ + 0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00,/*"w",87*/ + 0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00,/*"x",88*/ + 0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0,/*"y",89*/ + 0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00,/*"z",90*/ + 0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00,/*"{",91*/ + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,/*"|",92*/ + 0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00,/*"}",93*/ + 0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/ }; const struct rtgui_font_bitmap asc12 = @@ -216,8 +119,8 @@ const struct rtgui_font_bitmap asc12 = RT_NULL, /* offset for each character */ 6, /* width */ 12, /* height */ - 0, /* first char */ - 255 /* last char */ + 32, /* first char */ + 127 /* last char */ }; struct rtgui_font rtgui_font_asc12 = diff --git a/components/rtgui/common/asc16font.c b/components/rtgui/common/asc16font.c index 4db17e1655..b2de5ab354 100644 --- a/components/rtgui/common/asc16font.c +++ b/components/rtgui/common/asc16font.c @@ -16,262 +16,101 @@ #ifdef RTGUI_USING_FONT16 const unsigned char asc16_font[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, - 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, - 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, - 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, - 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, - 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, - 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, - 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00, - 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, - 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, - 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/ + 0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00,/*"!",1*/ + 0x00,0x12,0x36,0x24,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/ + 0x00,0x00,0x00,0x24,0x24,0x24,0xFE,0x48,0x48,0x48,0xFE,0x48,0x48,0x48,0x00,0x00,/*"#",3*/ + 0x00,0x00,0x10,0x38,0x54,0x54,0x50,0x30,0x18,0x14,0x14,0x54,0x54,0x38,0x10,0x10,/*"$",4*/ + 0x00,0x00,0x00,0x44,0xA4,0xA8,0xA8,0xA8,0x54,0x1A,0x2A,0x2A,0x2A,0x44,0x00,0x00,/*"%",5*/ + 0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x50,0x6E,0xA4,0x94,0x88,0x89,0x76,0x00,0x00,/*"&",6*/ + 0x00,0x60,0x60,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/ + 0x00,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00,/*"(",8*/ + 0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40,0x00,/*")",9*/ + 0x00,0x00,0x00,0x00,0x10,0x10,0xD6,0x38,0x38,0xD6,0x10,0x10,0x00,0x00,0x00,0x00,/*"*",10*/ + 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0xFE,0x10,0x10,0x10,0x10,0x00,0x00,0x00,/*"+",11*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x20,0xC0,/*",",12*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,/*".",14*/ + 0x00,0x00,0x01,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,/*"/",15*/ + 0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"0",16*/ + 0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"1",17*/ + 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,/*"2",18*/ + 0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00,/*"3",19*/ + 0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00,/*"4",20*/ + 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00,/*"5",21*/ + 0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"6",22*/ + 0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,/*"7",23*/ + 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,/*"8",24*/ + 0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00,/*"9",25*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,/*":",26*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x20,/*";",27*/ + 0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,/*"<",28*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,/*"=",29*/ + 0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,/*">",30*/ + 0x00,0x00,0x00,0x3C,0x42,0x42,0x62,0x02,0x04,0x08,0x08,0x00,0x18,0x18,0x00,0x00,/*"?",31*/ + 0x00,0x00,0x00,0x38,0x44,0x5A,0xAA,0xAA,0xAA,0xAA,0xB4,0x42,0x44,0x38,0x00,0x00,/*"@",32*/ + 0x00,0x00,0x00,0x10,0x10,0x18,0x28,0x28,0x24,0x3C,0x44,0x42,0x42,0xE7,0x00,0x00,/*"A",33*/ + 0x00,0x00,0x00,0xF8,0x44,0x44,0x44,0x78,0x44,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"B",34*/ + 0x00,0x00,0x00,0x3E,0x42,0x42,0x80,0x80,0x80,0x80,0x80,0x42,0x44,0x38,0x00,0x00,/*"C",35*/ + 0x00,0x00,0x00,0xF8,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"D",36*/ + 0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x42,0x42,0xFC,0x00,0x00,/*"E",37*/ + 0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x40,0x40,0xE0,0x00,0x00,/*"F",38*/ + 0x00,0x00,0x00,0x3C,0x44,0x44,0x80,0x80,0x80,0x8E,0x84,0x44,0x44,0x38,0x00,0x00,/*"G",39*/ + 0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"H",40*/ + 0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"I",41*/ + 0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0xF0,/*"J",42*/ + 0x00,0x00,0x00,0xEE,0x44,0x48,0x50,0x70,0x50,0x48,0x48,0x44,0x44,0xEE,0x00,0x00,/*"K",43*/ + 0x00,0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0xFE,0x00,0x00,/*"L",44*/ + 0x00,0x00,0x00,0xEE,0x6C,0x6C,0x6C,0x6C,0x54,0x54,0x54,0x54,0x54,0xD6,0x00,0x00,/*"M",45*/ + 0x00,0x00,0x00,0xC7,0x62,0x62,0x52,0x52,0x4A,0x4A,0x4A,0x46,0x46,0xE2,0x00,0x00,/*"N",46*/ + 0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00,/*"O",47*/ + 0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,/*"P",48*/ + 0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0xB2,0xCA,0x4C,0x38,0x06,0x00,/*"Q",49*/ + 0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x7C,0x48,0x48,0x44,0x44,0x42,0xE3,0x00,0x00,/*"R",50*/ + 0x00,0x00,0x00,0x3E,0x42,0x42,0x40,0x20,0x18,0x04,0x02,0x42,0x42,0x7C,0x00,0x00,/*"S",51*/ + 0x00,0x00,0x00,0xFE,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"T",52*/ + 0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"U",53*/ + 0x00,0x00,0x00,0xE7,0x42,0x42,0x44,0x24,0x24,0x28,0x28,0x18,0x10,0x10,0x00,0x00,/*"V",54*/ + 0x00,0x00,0x00,0xD6,0x92,0x92,0x92,0x92,0xAA,0xAA,0x6C,0x44,0x44,0x44,0x00,0x00,/*"W",55*/ + 0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x18,0x24,0x24,0x42,0xE7,0x00,0x00,/*"X",56*/ + 0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"Y",57*/ + 0x00,0x00,0x00,0x7E,0x84,0x04,0x08,0x08,0x10,0x20,0x20,0x42,0x42,0xFC,0x00,0x00,/*"Z",58*/ + 0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1E,0x00,/*"[",59*/ + 0x00,0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02,/*"\",60*/ + 0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00,/*"]",61*/ + 0x00,0x1C,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,/*"_",63*/ + 0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x1E,0x22,0x42,0x42,0x3F,0x00,0x00,/*"a",65*/ + 0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x64,0x58,0x00,0x00,/*"b",66*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00,/*"c",67*/ + 0x00,0x00,0x00,0x06,0x02,0x02,0x02,0x1E,0x22,0x42,0x42,0x42,0x26,0x1B,0x00,0x00,/*"d",68*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00,/*"e",69*/ + 0x00,0x00,0x00,0x0F,0x11,0x10,0x10,0x7E,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"f",70*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C,/*"g",71*/ + 0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"h",72*/ + 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"i",73*/ + 0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x1C,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,/*"j",74*/ + 0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x4E,0x48,0x50,0x68,0x48,0x44,0xEE,0x00,0x00,/*"k",75*/ + 0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"l",76*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x49,0x49,0x49,0x49,0x49,0xED,0x00,0x00,/*"m",77*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"n",78*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"o",79*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x64,0x42,0x42,0x42,0x44,0x78,0x40,0xE0,/*"p",80*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x22,0x42,0x42,0x42,0x22,0x1E,0x02,0x07,/*"q",81*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x32,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"r",82*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x40,0x3C,0x02,0x42,0x7C,0x00,0x00,/*"s",83*/ + 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x0C,0x00,0x00,/*"t",84*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00,/*"u",85*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x10,0x10,0x00,0x00,/*"v",86*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD7,0x92,0x92,0xAA,0xAA,0x44,0x44,0x00,0x00,/*"w",87*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x24,0x18,0x18,0x18,0x24,0x76,0x00,0x00,/*"x",88*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x18,0x10,0x10,0xE0,/*"y",89*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x44,0x08,0x10,0x10,0x22,0x7E,0x00,0x00,/*"z",90*/ + 0x00,0x03,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x03,0x00,/*"{",91*/ + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,/*"|",92*/ + 0x00,0x60,0x10,0x10,0x10,0x10,0x10,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x60,0x00,/*"}",93*/ + 0x30,0x4C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/ }; struct rtgui_font_bitmap asc16 = @@ -281,8 +120,8 @@ struct rtgui_font_bitmap asc16 = RT_NULL, /* offset for each character */ 8, /* width */ 16, /* height */ - 0, /* first char */ - 255 /* last char */ + 32, /* first char */ + 127 /* last char */ }; struct rtgui_font rtgui_font_asc16 = @@ -294,5 +133,4 @@ struct rtgui_font rtgui_font_asc16 = &asc16, /* font private data */ }; -/* size = 4096 bytes */ #endif diff --git a/components/rtgui/common/dc_hw.c b/components/rtgui/common/dc_hw.c index 02413a7a0f..c9dc711a47 100644 --- a/components/rtgui/common/dc_hw.c +++ b/components/rtgui/common/dc_hw.c @@ -37,13 +37,6 @@ static rt_bool_t rtgui_dc_hw_fini(struct rtgui_dc *dc); static rt_bool_t rtgui_dc_hw_get_visible(struct rtgui_dc *dc); static void rtgui_dc_hw_get_rect(struct rtgui_dc *dc, rtgui_rect_t *rect); -struct rtgui_dc_hw -{ - struct rtgui_dc parent; - rtgui_widget_t *owner; - const struct rtgui_graphic_driver *hw_driver; -}; - const struct rtgui_dc_engine dc_hw_engine = { rtgui_dc_hw_draw_point, diff --git a/components/rtgui/common/font_bmp.c b/components/rtgui/common/font_bmp.c index 264a822401..e4c0ab1646 100644 --- a/components/rtgui/common/font_bmp.c +++ b/components/rtgui/common/font_bmp.c @@ -59,11 +59,12 @@ void rtgui_bitmap_font_draw_char(struct rtgui_font_bitmap *font, struct rtgui_dc for (i = 0; i < h; i++) { - rt_uint8_t chr; + rt_uint8_t chr = 0; const rt_uint8_t *ptr = font_ptr + i * word_bytes; for (j = 0; j < w; j++) { - if (j % 8 == 0)chr = *ptr++; + if (j % 8 == 0) + chr = *ptr++; if (chr & 0x80) rtgui_dc_draw_point(dc, j + x, i + y); else if (style & RTGUI_TEXTSTYLE_DRAW_BACKGROUND) diff --git a/components/rtgui/common/image_jpg.c b/components/rtgui/common/image_jpg.c index 67164c7372..c5fe5da384 100644 --- a/components/rtgui/common/image_jpg.c +++ b/components/rtgui/common/image_jpg.c @@ -351,6 +351,7 @@ static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image *image, struct rtgui_f { /* no memory */ jpeg_finish_decompress(&jpeg->cinfo); + jpeg_destroy_decompress(&jpeg->cinfo); rt_free(jpeg); return RT_FALSE; @@ -381,6 +382,7 @@ static void rtgui_image_jpeg_unload(struct rtgui_image *image) rtgui_filerw_close(jpeg->filerw); jpeg_finish_decompress(&jpeg->cinfo); } + jpeg_destroy_decompress(&jpeg->cinfo); rt_free(jpeg); } } diff --git a/components/rtgui/common/region.c b/components/rtgui/common/region.c index a4bf2f2ed1..47a4b862f2 100644 --- a/components/rtgui/common/region.c +++ b/components/rtgui/common/region.c @@ -2274,3 +2274,13 @@ rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect) return RT_FALSE; } +rtgui_rect_t *rtgui_rect_set(rtgui_rect_t *rect, int x, int y, int w, int h) +{ + RT_ASSERT(rect != RT_NULL); + + rect->x1 = x; rect->y1 = y; + rect->x2 = x + w; rect->y2 = y + h; + + return rect; +} + diff --git a/components/rtgui/common/rtgui_app.c b/components/rtgui/common/rtgui_app.c index 186a1cca4c..7f76d76288 100644 --- a/components/rtgui/common/rtgui_app.c +++ b/components/rtgui/common/rtgui_app.c @@ -30,7 +30,6 @@ static void _rtgui_app_constructor(struct rtgui_app *app) app->ref_count = 0; app->exit_code = 0; app->tid = RT_NULL; - app->server = RT_NULL; app->mq = RT_NULL; app->modal_object = RT_NULL; app->main_object = RT_NULL; @@ -51,13 +50,13 @@ DEFINE_CLASS_TYPE(application, "application", _rtgui_app_destructor, sizeof(struct rtgui_app)); -struct rtgui_app *rtgui_app_create( - rt_thread_t tid, - const char *title) +struct rtgui_app *rtgui_app_create(const char *title) { - rt_thread_t srv_tid; + rt_thread_t tid = rt_thread_self(); struct rtgui_app *app; + struct rtgui_app *srv_app; struct rtgui_event_application event; + char mq_name[RT_NAME_MAX]; RT_ASSERT(tid != RT_NULL); RT_ASSERT(title != RT_NULL); @@ -70,10 +69,9 @@ struct rtgui_app *rtgui_app_create( /* one thread only can create one rtgui application */ RT_ASSERT(tid->user_data == 0); app->tid = tid; - /* set user thread */ - tid->user_data = (rt_uint32_t)app; - app->mq = rt_mq_create("rtgui", sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO); + rt_snprintf(mq_name, RT_NAME_MAX, "g%s", title); + app->mq = rt_mq_create(mq_name, sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO); if (app->mq == RT_NULL) { rt_kprintf("create msgq failed.\n"); @@ -85,31 +83,30 @@ struct rtgui_app *rtgui_app_create( if (app->name == RT_NULL) goto __err; - /* send a message to notify rtgui server */ - srv_tid = rtgui_get_server(); - if (srv_tid == RT_NULL) + /* the first app should be the server */ + srv_app = rtgui_get_server(); + if (srv_app == RT_NULL) { - rt_kprintf("gui server is not running.\n"); - goto __err; - } - - /* create the rtgui server application */ - if (srv_tid == rt_thread_self()) + /* set user thread */ + tid->user_data = (rt_uint32_t)app; + rt_kprintf("RTGUI: creating the server app %p.\n", app); return app; + } RTGUI_EVENT_APP_CREATE_INIT(&event); event.app = app; /* notify rtgui server to one application has been created */ - if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) == RT_EOK) + if (rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event)) == RT_EOK) { + /* set user thread */ + tid->user_data = (rt_uint32_t)app; return app; } __err: __mq_err: rtgui_object_destroy(RTGUI_OBJECT(app)); - tid->user_data = 0; return RT_NULL; } RTM_EXPORT(rtgui_app_create); @@ -124,7 +121,7 @@ RTM_EXPORT(rtgui_app_create); void rtgui_app_destroy(struct rtgui_app *app) { - rt_thread_t srv_tid; + struct rtgui_app *srv_app; _rtgui_application_check(app); if (!(app->state_flag & RTGUI_APP_FLAG_EXITED)) @@ -135,14 +132,14 @@ void rtgui_app_destroy(struct rtgui_app *app) } /* send a message to notify rtgui server */ - srv_tid = rtgui_get_server(); - if (srv_tid != rt_thread_self()) /* must not the server thread */ + srv_app = rtgui_get_server(); + if (srv_app != rtgui_app_self()) { struct rtgui_event_application event; RTGUI_EVENT_APP_DESTROY_INIT(&event); event.app = app; - if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) != RT_EOK) + if (rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event)) != RT_EOK) { rt_kprintf("destroy an application in server failed\n"); return ; @@ -168,25 +165,18 @@ struct rtgui_app *rtgui_app_self(void) } RTM_EXPORT(rtgui_app_self); -void rtgui_app_set_onidle(rtgui_idle_func_t onidle) +void rtgui_app_set_onidle(struct rtgui_app *app, rtgui_idle_func_t onidle) { - struct rtgui_app *app; - - app = rtgui_app_self(); - if (app != RT_NULL) - app->on_idle = onidle; + _rtgui_application_check(app); + app->on_idle = onidle; } RTM_EXPORT(rtgui_app_set_onidle); -rtgui_idle_func_t rtgui_app_get_onidle(void) +rtgui_idle_func_t rtgui_app_get_onidle(struct rtgui_app *app) { - struct rtgui_app *app; - app = rtgui_app_self(); - if (app != RT_NULL) - return app->on_idle; - else - return RT_NULL; + _rtgui_application_check(app); + return app->on_idle; } RTM_EXPORT(rtgui_app_get_onidle); @@ -369,7 +359,7 @@ void rtgui_app_activate(struct rtgui_app *app) RTGUI_EVENT_APP_ACTIVATE_INIT(&event); event.app = app; - rtgui_send(app->tid, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application)); + rtgui_send(app, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application)); } RTM_EXPORT(rtgui_app_activate); @@ -380,28 +370,28 @@ void rtgui_app_close(struct rtgui_app *app) RTGUI_EVENT_APP_DESTROY_INIT(&event); event.app = app; - rtgui_send(app->tid, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application)); + rtgui_send(app, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application)); } RTM_EXPORT(rtgui_app_close); /** * set this application as window manager */ -rt_err_t rtgui_app_set_as_wm(void) +rt_err_t rtgui_app_set_as_wm(struct rtgui_app *app) { - rt_thread_t srv_tid; + struct rtgui_app *srv_app; struct rtgui_event_set_wm event; - struct rtgui_app *app; - srv_tid = rtgui_get_server(); - app = rtgui_app_self(); - if (app != RT_NULL && srv_tid != RT_NULL) + _rtgui_application_check(app); + + srv_app = rtgui_get_server(); + if (srv_app != RT_NULL) { /* notify rtgui server, this is a window manager */ RTGUI_EVENT_SET_WM_INIT(&event); event.app = app; - rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)); + rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event)); return RT_EOK; } @@ -409,15 +399,11 @@ rt_err_t rtgui_app_set_as_wm(void) } RTM_EXPORT(rtgui_app_set_as_wm); -void rtgui_app_set_main_win(struct rtgui_win *win) +void rtgui_app_set_main_win(struct rtgui_app *app, struct rtgui_win *win) { - struct rtgui_app *app; - app = rtgui_app_self(); - if (app != RT_NULL) - { - app->main_object = RTGUI_OBJECT(win); - } + _rtgui_application_check(app); + app->main_object = RTGUI_OBJECT(win); } RTM_EXPORT(rtgui_app_set_main_win); diff --git a/components/rtgui/common/rtgui_mv_model.c b/components/rtgui/common/rtgui_mv_model.c index c32fce3001..e10976b14c 100644 --- a/components/rtgui/common/rtgui_mv_model.c +++ b/components/rtgui/common/rtgui_mv_model.c @@ -422,7 +422,7 @@ static rt_bool_t _rtgui_mv_model_notify_view(struct rtgui_mv_model *model, struct rtgui_mv_view *view, struct rtgui_event_mv_model *emodel) { - rt_thread_t target = RTGUI_WIDGET(view)->toplevel->app->tid; + struct rtgui_app *target = RTGUI_WIDGET(view)->toplevel->app; emodel->model = model; emodel->view = view; return rtgui_send(target, (struct rtgui_event *)emodel, sizeof(*emodel)); diff --git a/components/rtgui/common/rtgui_system.c b/components/rtgui/common/rtgui_system.c index 576655dadf..781b25adc5 100644 --- a/components/rtgui/common/rtgui_system.c +++ b/components/rtgui/common/rtgui_system.c @@ -70,7 +70,7 @@ static void rtgui_time_out(void *parameter) event.timer = timer; - rtgui_send(timer->tid, &(event.parent), sizeof(rtgui_event_timer_t)); + rtgui_send(timer->app, &(event.parent), sizeof(rtgui_event_timer_t)); } rtgui_timer_t *rtgui_timer_create(rt_int32_t time, rt_int32_t flag, rtgui_timeout_func timeout, void *parameter) @@ -78,7 +78,7 @@ rtgui_timer_t *rtgui_timer_create(rt_int32_t time, rt_int32_t flag, rtgui_timeou rtgui_timer_t *timer; timer = (rtgui_timer_t *) rtgui_malloc(sizeof(rtgui_timer_t)); - timer->tid = rt_thread_self(); + timer->app = rtgui_app_self(); timer->timeout = timeout; timer->user_data = parameter; @@ -371,7 +371,7 @@ const char *event_string[] = #define DBG_MSG(x) rt_kprintf x -static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event) +static void rtgui_event_dump(struct rtgui_app* app, rtgui_event_t *event) { char *sender = "(unknown)"; @@ -389,12 +389,12 @@ static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event) if (event->type >= RTGUI_EVENT_COMMAND) { - rt_kprintf("%s -- USER EVENT --> %s \n", sender, tid->name); + rt_kprintf("%s -- USER EVENT --> %s \n", sender, app->name); return ; } else { - rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], tid->name); + rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], app->name); } switch (event->type) @@ -545,88 +545,68 @@ static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event) } #else #define DBG_MSG(x) -#define rtgui_event_dump(tid, event) +#define rtgui_event_dump(app, event) #endif /************************************************************************/ /* RTGUI IPC APIs */ /************************************************************************/ -rt_err_t rtgui_send(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size) +rt_err_t rtgui_send(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size) { rt_err_t result; - struct rtgui_app *app; - RT_ASSERT(tid != RT_NULL); + RT_ASSERT(app != RT_NULL); RT_ASSERT(event != RT_NULL); RT_ASSERT(event_size != 0); - rtgui_event_dump(tid, event); - - /* find struct rtgui_application */ - app = (struct rtgui_app *)(tid->user_data); - if (app == RT_NULL) - return -RT_ERROR; + rtgui_event_dump(app, event); result = rt_mq_send(app->mq, event, event_size); if (result != RT_EOK) { if (event->type != RTGUI_EVENT_TIMER) - rt_kprintf("send event to %s failed\n", app->tid->name); + rt_kprintf("send event to %s failed\n", app->name); } return result; } RTM_EXPORT(rtgui_send); -rt_err_t rtgui_send_urgent(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size) +rt_err_t rtgui_send_urgent(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size) { rt_err_t result; - struct rtgui_app *app; - RT_ASSERT(tid != RT_NULL); + RT_ASSERT(app != RT_NULL); RT_ASSERT(event != RT_NULL); RT_ASSERT(event_size != 0); - rtgui_event_dump(tid, event); - - /* find rtgui_application */ - app = (struct rtgui_app *)(tid->user_data); - if (app == RT_NULL) - return -RT_ERROR; + rtgui_event_dump(app, event); result = rt_mq_urgent(app->mq, event, event_size); if (result != RT_EOK) - rt_kprintf("send ergent event failed\n"); + rt_kprintf("send ergent event to %s failed\n", app->name); return result; } RTM_EXPORT(rtgui_send_urgent); -rt_err_t rtgui_send_sync(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size) +rt_err_t rtgui_send_sync(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size) { rt_err_t r; - struct rtgui_app *app; rt_int32_t ack_buffer, ack_status; struct rt_mailbox ack_mb; - RT_ASSERT(tid != RT_NULL); + RT_ASSERT(app != RT_NULL); RT_ASSERT(event != RT_NULL); RT_ASSERT(event_size != 0); - rtgui_event_dump(tid, event); + rtgui_event_dump(app, event); /* init ack mailbox */ r = rt_mb_init(&ack_mb, "ack", &ack_buffer, 1, 0); if (r != RT_EOK) goto __return; - app = (struct rtgui_app *)(tid->user_data); - if (app == RT_NULL) - { - r = -RT_ERROR; - goto __return; - } - event->ack = &ack_mb; r = rt_mq_send(app->mq, event, event_size); if (r != RT_EOK) @@ -728,12 +708,6 @@ rt_err_t rtgui_recv_filter(rt_uint32_t type, rtgui_event_t *event, rt_size_t eve } RTM_EXPORT(rtgui_recv_filter); -rt_thread_t rtgui_get_server(void) -{ - return rt_thread_find("rtgui"); -} -RTM_EXPORT(rtgui_get_server); - void rtgui_set_mainwin_rect(struct rtgui_rect *rect) { _mainwin_rect = *rect; diff --git a/components/rtgui/common/rtgui_theme.c b/components/rtgui/common/rtgui_theme.c index a1e8b119b5..e7576c4558 100644 --- a/components/rtgui/common/rtgui_theme.c +++ b/components/rtgui/common/rtgui_theme.c @@ -96,31 +96,34 @@ void rtgui_theme_draw_win(struct rtgui_topwin *win) if (!(win->flag & WINTITLE_NO)) { rt_uint32_t index; - float r, g, b, delta; + rt_uint16_t r, g, b, delta; +#define RGB_FACTOR 4 if (win->flag & WINTITLE_ACTIVATE) { - r = 10; - g = 36; - b = 106; - delta = 150 / (float)(rect.x2 - rect.x1); + r = 10 << RGB_FACTOR; + g = 36 << RGB_FACTOR; + b = 106 << RGB_FACTOR; + delta = (150 << RGB_FACTOR) / (rect.x2 - rect.x1); } else { - r = 128; - g = 128; - b = 128; - delta = 64 / (float)(rect.x2 - rect.x1); + r = 128 << RGB_FACTOR; + g = 128 << RGB_FACTOR; + b = 128 << RGB_FACTOR; + delta = (64 << RGB_FACTOR) / (rect.x2 - rect.x1); } - RTGUI_WIDGET_FOREGROUND(win->title) = RTGUI_RGB(r, g, b); for (index = rect.x1; index < rect.x2 + 1; index ++) { + RTGUI_WIDGET_FOREGROUND(win->title) = RTGUI_RGB((r>>RGB_FACTOR), \ + (g>>RGB_FACTOR), (b>>RGB_FACTOR)); rtgui_dc_draw_vline(dc, index, rect.y1, rect.y2); r += delta; g += delta; b += delta; } +#undef RGB_FACTOR if (win->flag & WINTITLE_ACTIVATE) { diff --git a/components/rtgui/doc/ANNOUNCE.0.6.md b/components/rtgui/doc/ANNOUNCE.0.6.md new file mode 100644 index 0000000000..8d65c0a812 --- /dev/null +++ b/components/rtgui/doc/ANNOUNCE.0.6.md @@ -0,0 +1,69 @@ +RTGUI 0.6版发布纪要 + +# 为什么是 0.6? + +RTGUI 是作为 RT-Thread 的一个组件存在的。这次新发布的版本是在原 RTGUI 基础上重 +构而来的。原 RTGUI 没有独立的版本号。暂设其为 0.5。所以本版本号取 0.6,为在原有 +基础上改进之意。以后我们会每个月发布一个新版本。下一个版本号会是 0.6.1。 + +# 运行环境 + +理论上原来可以运行 RTGUI 的设备上都可以运行新的 RTGUI。本版本自带一个 Windows +模拟器,用来方便地评估运行效果。默认的运行环境是 realtouch。RT-Thread 中的模拟 +器也是可以运作的。 + +# 新版本有什么特点? + +0. 新版本的 GUI 摒弃了原有的 workbench/view/window 的工作方式。转换成全面向 + window的工作方式。原有的 workbench/view 可以用 notebook 来实现。 +0. 用 `rtgui_app` 对线程进行了抽象。 +0. 事件驱动更彻底: + 0. 将事件处理机制集成进 `rtgui_object`。 + 0. 添加了`RTGUI_EVENT_SHOW` 和 `RTGUI_EVENT_HIDE` 来通知控件将要被显示/隐藏。 + 0. 底层代码中对事件的应用更加彻底。 +0. 重构了自动布局方式。使得控件的摆放更加方便。 + +# 增强 + +- 添加了 TJPGD 引擎。使得小内存系统解码 jpeg 图片成为可能。(onelife) +- 添加了对单色屏的支持(onelife) +- bmp 图像引擎的重构(onelife) +- bmp 图像的旋转/缩放,以及功能性增强(amsl) +- 增加屏幕快照功能(amsl) +- PNG 引擎增加 Alpha 通道支持(amsl) +- 新增 edit 多行文本编辑控件。(amsl) +- 增加了 Model/View 的编程框架。(Grissiom) +- 添加了缩减字库的特性,开启后可以自动添加用到的汉字,不用的汉字字形不会加入到 + 字库当中。使得 GUI 能够在小 ROM 系统上得以应用。(Grissiom) +- 新增 digtube 七段码显示控件(prife) +- demo/benchmark 新增了 FPS 输出(amsl) +- 新增 box/panel/groupbox,支持自动布局(Bernard) + +# API 变化 + +除了 workbench/view 的消失以外,还有如下的 API 变化: + +- c05a301, 68e3e30: `rtgui_{menu,win}_hiden` 被重命名为 `rtgui_{menu,win}_hide`。 +- 05e4894: 将 `struct rtgui_widget` 中的 `mini_{height,width}` 重命名为 `min_{height,width}`。 +- 等等…… + +今后很长时间内,新版本的 RTGUI 会与此版本的 API 尽量只增不减,保持兼容。 + +# Bug fixes + +- 00a6690: 解决了 `rtgui_notebook_set_current_by_index` 中重绘标签页的 bug。感 + 谢 prife 提交 bug 信息和补丁。 +- 6850ff2: 解决了 `last_mevent_widget` 引起的事件传送失败。感谢 heryon 提交bug + 报告。 +- 9143e11: 解决了 jpeg 引擎中的内存泄漏。感谢 Young 提供 bug 信息。 +- fbd567c: 解决了 `rtgui_textbox_set_line_length` 的 bug。 +- 9b67b66: 修复了窗口标题栏渐变效果的绘制。 +- fc3abbf: 修复了 `rtgui_label_set_text`。感谢 tanghong668 提供 bug 信息。 +- d41586c: 修复了窗口激活时重复刷新的问题。感谢 onelife 提供 bug 信息。 +- ab08de6: 修复了字库缓存的 bug。感谢 rtt\_fans 提供 bug 信息。 +- 等等…… + +除了上面提到的,luoyuncong2012, lgnq, shaolin 也有贡献。上面的列表也必然是不完 +整的。感谢编写了第一版 RTGUI 的 Bernard 和其他大侠们,没有他们的辛勤劳动,也不 +会有今天的版本。感谢各位使用和支持RTGUI的开发人员,是你们 RTGUI 体现了 RTGUI 的 +价值。 diff --git a/components/rtgui/doc/road_map.txt b/components/rtgui/doc/historical/road_map.txt similarity index 100% rename from components/rtgui/doc/road_map.txt rename to components/rtgui/doc/historical/road_map.txt diff --git a/components/rtgui/doc/mv-model.dox b/components/rtgui/doc/mv-model.dox new file mode 100644 index 0000000000..15975c4625 --- /dev/null +++ b/components/rtgui/doc/mv-model.dox @@ -0,0 +1,81 @@ +/** @~english + @page pg-mv-model Model-View framework + + @brief A overview of the Model-View framework + + @section Glossary + + @li view: widget dedicated to show the data. It could be a graph, list etc. + @li model: abstraction and combination of data. + @li data: things that needed to be delivered or shown. It could be a array of + votage values which is sampled from a AD in an interval. Or it could be the + attributes of all the files in a folder. + + @section Design considerations and implementations + + @li one model can respond to more than one views. one view can connect to + more than one models. + @li It is guaranteed that the change events of a model will be sent to all + the registered views. + @li Because there are so many formats of data, Model-View neither specify the + format data is stored nor try to abstract them. The only thing stored in + model is a pointer to the underlaying data. It is the responsibility of + inherited classed to implement the boxing/un-boxing operations. + @li Data can be multi-dimensional. The "dimension" does not only means + dimension geometry. It can also means attributes. For example, a folder could + have two attributes which are name and icon. So it's two-dimensional. If take + the size into consideration, it will be three-dimensional. The size of + dimension is saved in model. Each dimension is correspond to a pointer to some + sort of data. Model can save many of them. As above, model does not make + assumptions on the underlaying data structure. It only provide mechanism, not + policy and leave that to the inherited classes. + + @section Events + + @li model has a record of registered views. When data changes, model notify + views the change by sending events. The event contains the id of the model, + the id of target view, the scope of changed data. + @li views can handle the event by retrieve data from model, and update + themselves according to the scope that data has changed. The connected model + views should have the same presentation of data structure. Views should also + restore all the models it interested. In the case of repainting, it should + re-retrieve data from those models. + @li model send events by rtgui_send. So it's suitable for the synchronization + between threads and even could be used in ISR. +*/ + +/** @~chinese + @page pg-mv-model Model-View 框架 + + @brief 对于 Model-View 框架的简介 + + @section 名词解释 + + @li view:用于显示数据的控件。可以是诸如图表控件、列表控件的控件。 + @li model:对于数据的组合和抽象。 + @li 数据:需要显示或传递的数据。它可以是每隔一段时间就从AD读取的电压值,也可 + 以是一个目录下所有文件的属性列表。 + + @section 设计原则和实现 + + @li 一个 model 可以对应多个view。一个view可以对应多个 model。 + @li 保证 model 的更新事件会同时发送到所有注册的 view 上。 + @li 因为数据的形式与内容千差万别,所以 Model-View 不规定数据的存储形式,也不对其进 + 行抽象。只在 model 中保留指向第一个数据的指针。打包/解包由从m odel/view 派生出 + 的子类实现。 + @li 数据源可以是多维的。这里的维度指的不只是几何的维度,而且可以是属性。比如 + 一个目录,它可以有名称、图标两个属性,那么它就是两维的。如果加入大小这个属性 + ,就是三维的。 model 内部存储数据的维度大小。一个维度对应一个数据首地址的指针 + 。model 中可以存储多个数据首地址。model 对底层数据结构不作假设。只提供机制,不 + 提供策略。只保证能够多维,但把具体的实现方式留给子类实现。 + + @subsection 事件 + + @li model 内部记录对自己感兴趣的 view。在数据变化时,用事件通知所有相关 view。事 + 件内容包含:自己的 id;目标 view 的 id;所变化数据的 index 范围。 + @li view 收到事件之后通过 model id 拿到数据并根据事件中的变化范围更新自己。对于 + 指针的数据类型转换需要自己实现并保证和 model 一致。view 内部保存与自己相关的 + model id,在需要重绘的时候要从所有相关 model 提取数据。 + @li model 通过 rtgui_send 给 view 发送事件。使得这个模型适用于线程间同步,也 + 可以在中断上下文里通知事件的发生。 +*/ diff --git a/components/rtgui/include/rtgui/dc.h b/components/rtgui/include/rtgui/dc.h index 7ee7f6dd93..4a36465e89 100644 --- a/components/rtgui/include/rtgui/dc.h +++ b/components/rtgui/include/rtgui/dc.h @@ -60,6 +60,14 @@ struct rtgui_dc const struct rtgui_dc_engine *engine; }; +/* hardware device context */ +struct rtgui_dc_hw +{ + struct rtgui_dc parent; + rtgui_widget_t *owner; + const struct rtgui_graphic_driver *hw_driver; +}; + #define RTGUI_DC_FC(dc) (rtgui_dc_get_gc(dc)->foreground) #define RTGUI_DC_BC(dc) (rtgui_dc_get_gc(dc)->background) #define RTGUI_DC_FONT(dc) (rtgui_dc_get_gc(dc)->font) diff --git a/components/rtgui/include/rtgui/driver.h b/components/rtgui/include/rtgui/driver.h index 6b77aa804f..2259853448 100644 --- a/components/rtgui/include/rtgui/driver.h +++ b/components/rtgui/include/rtgui/driver.h @@ -17,6 +17,7 @@ #include #include +/* graphic driver operations */ struct rtgui_graphic_driver_ops { /* set and get pixel in (x, y) */ @@ -30,6 +31,22 @@ struct rtgui_graphic_driver_ops void (*draw_raw_hline)(rt_uint8_t *pixels, int x1, int x2, int y); }; +/* graphic extension operations */ +struct rtgui_graphic_ext_ops +{ + /* some 2D operations */ + void (*draw_line)(rtgui_color_t *c, int x1, int y1, int x2, int y2); + + void (*draw_rect)(rtgui_color_t *c, int x1, int y1, int x2, int y2); + void (*fill_rect)(rtgui_color_t *c, int x1, int y1, int x2, int y2); + + void (*draw_circle)(rtgui_color_t *c, int x, int y, int r); + void (*fill_circle)(rtgui_color_t *c, int x, int y, int r); + + void (*draw_ellipse)(rtgui_color_t *c, int x, int y, int rx, int ry); + void (*fill_ellipse)(rtgui_color_t *c, int x, int y, int rx, int ry); +}; + struct rtgui_graphic_driver { /* pixel format and byte per pixel */ @@ -43,11 +60,11 @@ struct rtgui_graphic_driver /* framebuffer address and ops */ volatile rt_uint8_t *framebuffer; - rt_device_t device; - const struct rtgui_graphic_driver_ops *ops; -}; + struct rt_device* device; -void rtgui_graphic_driver_add(const struct rtgui_graphic_driver *driver); + const struct rtgui_graphic_driver_ops *ops; + const struct rtgui_graphic_ext_ops *ext_ops; +}; struct rtgui_graphic_driver *rtgui_graphic_driver_get_default(void); @@ -64,5 +81,19 @@ rt_inline struct rtgui_graphic_driver *rtgui_graphic_get_device() return &_driver; } +#ifdef RTGUI_USING_HW_CURSOR +/* + * hardware cursor + */ +enum rtgui_cursor_type +{ + RTGUI_CURSOR_ARROW, + RTGUI_CURSOR_HAND, +}; + +void rtgui_cursor_set_device(const char* device_name); +void rtgui_cursor_set_position(rt_uint16_t x, rt_uint16_t y); +void rtgui_cursor_set_image(enum rtgui_cursor_type type); #endif +#endif diff --git a/components/rtgui/include/rtgui/event.h b/components/rtgui/include/rtgui/event.h index c0f4e5b7bf..cb83fdb85b 100644 --- a/components/rtgui/include/rtgui/event.h +++ b/components/rtgui/include/rtgui/event.h @@ -90,7 +90,7 @@ struct rtgui_event rt_uint16_t user; /* the event sender */ - rt_thread_t sender; + struct rtgui_app *sender; /* mailbox to acknowledge request */ rt_mailbox_t ack; @@ -98,11 +98,13 @@ struct rtgui_event typedef struct rtgui_event rtgui_event_t; #define RTGUI_EVENT(e) ((struct rtgui_event*)(e)) +extern struct rtgui_app* rtgui_app_self(void); + #define RTGUI_EVENT_INIT(e, t) do \ { \ (e)->type = (t); \ (e)->user = 0; \ - (e)->sender = rt_thread_self(); \ + (e)->sender = rtgui_app_self(); \ (e)->ack = RT_NULL; \ } while (0) diff --git a/components/rtgui/include/rtgui/region.h b/components/rtgui/include/rtgui/region.h index 42a78b8da4..ab36acccfb 100644 --- a/components/rtgui/include/rtgui/region.h +++ b/components/rtgui/include/rtgui/region.h @@ -20,81 +20,82 @@ extern "C" { #endif - typedef struct rtgui_region_data rtgui_region_data_t; +typedef struct rtgui_region_data rtgui_region_data_t; - struct rtgui_region_data - { - rt_uint32_t size; - rt_uint32_t numRects; - /* XXX: And why, exactly, do we have this bogus struct definition? */ - /* rtgui_rect_t rects[size]; in memory but not explicitly declared */ - }; +struct rtgui_region_data +{ + rt_uint32_t size; + rt_uint32_t numRects; + /* XXX: And why, exactly, do we have this bogus struct definition? */ + /* rtgui_rect_t rects[size]; in memory but not explicitly declared */ +}; - typedef struct rtgui_region - { - rtgui_rect_t extents; - rtgui_region_data_t *data; - } rtgui_region_t; +typedef struct rtgui_region +{ + rtgui_rect_t extents; + rtgui_region_data_t *data; +} rtgui_region_t; - typedef enum - { - RTGUI_REGION_STATUS_FAILURE, - RTGUI_REGION_STATUS_SUCCESS - } rtgui_region_status_t; +typedef enum +{ + RTGUI_REGION_STATUS_FAILURE, + RTGUI_REGION_STATUS_SUCCESS +} rtgui_region_status_t; - /* creation/destruction */ +/* creation/destruction */ - void rtgui_region_init(rtgui_region_t *region); - void rtgui_region_init_rect(rtgui_region_t *region, - int x, int y, unsigned int width, unsigned int height); - void rtgui_region_init_with_extents(rtgui_region_t *region, const rtgui_rect_t *extents); - void rtgui_region_fini(rtgui_region_t *region); +void rtgui_region_init(rtgui_region_t *region); +void rtgui_region_init_rect(rtgui_region_t *region, + int x, int y, unsigned int width, unsigned int height); +void rtgui_region_init_with_extents(rtgui_region_t *region, const rtgui_rect_t *extents); +void rtgui_region_fini(rtgui_region_t *region); - void rtgui_region_translate(rtgui_region_t *region, int x, int y); +void rtgui_region_translate(rtgui_region_t *region, int x, int y); - rtgui_region_status_t rtgui_region_copy(rtgui_region_t *dest, rtgui_region_t *source); +rtgui_region_status_t rtgui_region_copy(rtgui_region_t *dest, rtgui_region_t *source); - rtgui_region_status_t rtgui_region_intersect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2); - rtgui_region_status_t rtgui_region_intersect_rect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *rect); - rtgui_region_status_t rtgui_region_union(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2); - rtgui_region_status_t rtgui_region_union_rect(rtgui_region_t *dest, rtgui_region_t *source, rtgui_rect_t *rect); - rtgui_region_status_t rtgui_region_subtract(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_region_t *regS); - rtgui_region_status_t rtgui_region_subtract_rect(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_rect_t *rect); - rtgui_region_status_t rtgui_region_inverse(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *invRect); +rtgui_region_status_t rtgui_region_intersect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2); +rtgui_region_status_t rtgui_region_intersect_rect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *rect); +rtgui_region_status_t rtgui_region_union(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2); +rtgui_region_status_t rtgui_region_union_rect(rtgui_region_t *dest, rtgui_region_t *source, rtgui_rect_t *rect); +rtgui_region_status_t rtgui_region_subtract(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_region_t *regS); +rtgui_region_status_t rtgui_region_subtract_rect(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_rect_t *rect); +rtgui_region_status_t rtgui_region_inverse(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *invRect); - int rtgui_region_num_rects(rtgui_region_t *region); +int rtgui_region_num_rects(rtgui_region_t *region); - rtgui_rect_t *rtgui_region_rects(rtgui_region_t *region); +rtgui_rect_t *rtgui_region_rects(rtgui_region_t *region); #define RTGUI_REGION_OUT 0 #define RTGUI_REGION_IN 1 #define RTGUI_REGION_PART 2 - int rtgui_region_contains_point(rtgui_region_t *region, int x, int y, rtgui_rect_t *box); - int rtgui_region_contains_rectangle(rtgui_region_t *rtgui_region_t, rtgui_rect_t *prect); +int rtgui_region_contains_point(rtgui_region_t *region, int x, int y, rtgui_rect_t *box); +int rtgui_region_contains_rectangle(rtgui_region_t *rtgui_region_t, rtgui_rect_t *prect); - int rtgui_region_not_empty(rtgui_region_t *region); - rtgui_rect_t *rtgui_region_extents(rtgui_region_t *region); +int rtgui_region_not_empty(rtgui_region_t *region); +rtgui_rect_t *rtgui_region_extents(rtgui_region_t *region); - rtgui_region_status_t rtgui_region_append(rtgui_region_t *dest, rtgui_region_t *region); - rtgui_region_status_t rtgui_region_validate(rtgui_region_t *badreg, int *pOverlap); +rtgui_region_status_t rtgui_region_append(rtgui_region_t *dest, rtgui_region_t *region); +rtgui_region_status_t rtgui_region_validate(rtgui_region_t *badreg, int *pOverlap); - void rtgui_region_reset(rtgui_region_t *region, rtgui_rect_t *rect); - void rtgui_region_empty(rtgui_region_t *region); - void rtgui_region_dump(rtgui_region_t *region); - int rtgui_region_is_flat(rtgui_region_t *region); +void rtgui_region_reset(rtgui_region_t *region, rtgui_rect_t *rect); +void rtgui_region_empty(rtgui_region_t *region); +void rtgui_region_dump(rtgui_region_t *region); +int rtgui_region_is_flat(rtgui_region_t *region); - /* rect functions */ - extern rtgui_rect_t rtgui_empty_rect; +/* rect functions */ +extern rtgui_rect_t rtgui_empty_rect; - void rtgui_rect_moveto(rtgui_rect_t *rect, int x, int y); - void rtgui_rect_moveto_align(rtgui_rect_t *rect, rtgui_rect_t *to, int align); - void rtgui_rect_inflate(rtgui_rect_t *rect, int d); - void rtgui_rect_intersect(rtgui_rect_t *src, rtgui_rect_t *dest); - int rtgui_rect_contains_point(const rtgui_rect_t *rect, int x, int y); - int rtgui_rect_is_intersect(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2); - int rtgui_rect_is_equal(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2); - rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect); +void rtgui_rect_moveto(rtgui_rect_t *rect, int x, int y); +void rtgui_rect_moveto_align(rtgui_rect_t *rect, rtgui_rect_t *to, int align); +void rtgui_rect_inflate(rtgui_rect_t *rect, int d); +void rtgui_rect_intersect(rtgui_rect_t *src, rtgui_rect_t *dest); +int rtgui_rect_contains_point(const rtgui_rect_t *rect, int x, int y); +int rtgui_rect_is_intersect(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2); +int rtgui_rect_is_equal(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2); +rtgui_rect_t *rtgui_rect_set(rtgui_rect_t *rect, int x, int y, int w, int h); +rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect); #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/components/rtgui/include/rtgui/rtgui.h b/components/rtgui/include/rtgui/rtgui.h index 066262d34c..fc00d4559f 100644 --- a/components/rtgui/include/rtgui/rtgui.h +++ b/components/rtgui/include/rtgui/rtgui.h @@ -17,6 +17,11 @@ #include #include +#define RTGUI_VERSION 0L /**< major version number */ +#define RTGUI_SUBVERSION 6L /**< minor version number */ +#define RTGUI_REVISION 0L /**< revise version number */ +#define RTGUI_CODENAME "Newton" /**< code name */ + #define RT_INT16_MAX 32767 #define RT_INT16_MIN (-RT_INT16_MAX-1) #define RTGUI_NOT_FOUND (-1) diff --git a/components/rtgui/include/rtgui/rtgui_app.h b/components/rtgui/include/rtgui/rtgui_app.h index 50087e07a2..67f5e0ae4c 100644 --- a/components/rtgui/include/rtgui/rtgui_app.h +++ b/components/rtgui/include/rtgui/rtgui_app.h @@ -52,9 +52,6 @@ struct rtgui_app /* the thread id */ rt_thread_t tid; - /* the RTGUI server id */ - rt_thread_t server; - /* the message queue of thread */ rt_mq_t mq; /* event buffer */ @@ -70,9 +67,13 @@ struct rtgui_app }; /** - * create an application named @myname on thread @param tid + * create an application named @myname on current thread. + * + * @param name the name of the application + * + * @return a pointer to struct rtgui_app on success. RT_NULL on failure. */ -struct rtgui_app *rtgui_app_create(rt_thread_t tid, const char *title); +struct rtgui_app *rtgui_app_create(const char *name); void rtgui_app_destroy(struct rtgui_app *app); rt_bool_t rtgui_app_event_handler(struct rtgui_object *obj, rtgui_event_t *event); @@ -81,11 +82,15 @@ void rtgui_app_exit(struct rtgui_app *app, rt_uint16_t code); void rtgui_app_activate(struct rtgui_app *app); void rtgui_app_close(struct rtgui_app *app); -void rtgui_app_set_onidle(rtgui_idle_func_t onidle); -rtgui_idle_func_t rtgui_app_get_onidle(void); +void rtgui_app_set_onidle(struct rtgui_app *app, rtgui_idle_func_t onidle); +rtgui_idle_func_t rtgui_app_get_onidle(struct rtgui_app *app); + +/** + * return the rtgui_app struct on current thread + */ struct rtgui_app *rtgui_app_self(void); -rt_err_t rtgui_app_set_as_wm(void); -void rtgui_app_set_main_win(struct rtgui_win *win); +rt_err_t rtgui_app_set_as_wm(struct rtgui_app *app); +void rtgui_app_set_main_win(struct rtgui_app *app, struct rtgui_win *win); #endif /* end of include guard: __RTGUI_APP_H__ */ diff --git a/components/rtgui/include/rtgui/rtgui_server.h b/components/rtgui/include/rtgui/rtgui_server.h index 9914a5b8ef..de459bf29e 100644 --- a/components/rtgui/include/rtgui/rtgui_server.h +++ b/components/rtgui/include/rtgui/rtgui_server.h @@ -56,8 +56,8 @@ struct rtgui_topwin /* the window id */ struct rtgui_win *wid; - /* the thread id */ - rt_thread_t tid; + /* which app I belong */ + struct rtgui_app *app; /* the extent information */ rtgui_rect_t extent; diff --git a/components/rtgui/include/rtgui/rtgui_system.h b/components/rtgui/include/rtgui/rtgui_system.h index 975b1e0be5..8f8edaaacc 100644 --- a/components/rtgui/include/rtgui/rtgui_system.h +++ b/components/rtgui/include/rtgui/rtgui_system.h @@ -26,8 +26,8 @@ typedef void (*rtgui_timeout_func)(struct rtgui_timer *timer, void *parameter); struct rtgui_timer { - /* context thread id */ - rt_thread_t tid; + /* the rtgui application it runs on */ + struct rtgui_app* app; /* rt timer */ struct rt_timer timer; @@ -58,7 +58,7 @@ void *rtgui_realloc(void *ptr, rt_size_t size); #define rtgui_exit_critical rt_exit_critical #endif -rt_thread_t rtgui_get_server(void); +struct rtgui_app* rtgui_get_server(void); void rtgui_set_mainwin_rect(struct rtgui_rect *rect); void rtgui_get_mainwin_rect(struct rtgui_rect *rect); void rtgui_get_screen_rect(struct rtgui_rect *rect); @@ -67,9 +67,9 @@ void rtgui_screen_lock(rt_int32_t timeout); void rtgui_screen_unlock(void); struct rtgui_event; -rt_err_t rtgui_send(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size); -rt_err_t rtgui_send_urgent(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size); -rt_err_t rtgui_send_sync(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size); +rt_err_t rtgui_send(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size); +rt_err_t rtgui_send_urgent(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size); +rt_err_t rtgui_send_sync(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size); rt_err_t rtgui_ack(struct rtgui_event *event, rt_int32_t status); rt_err_t rtgui_recv(struct rtgui_event *event, rt_size_t event_size); rt_err_t rtgui_recv_nosuspend(struct rtgui_event *event, rt_size_t event_size); diff --git a/components/rtgui/include/rtgui/widgets/digfont.h b/components/rtgui/include/rtgui/widgets/digfont.h new file mode 100644 index 0000000000..6765ed06c3 --- /dev/null +++ b/components/rtgui/include/rtgui/widgets/digfont.h @@ -0,0 +1,36 @@ +#ifndef DIG_FONT_H +#define DIG_FONT_H + +struct rtgui_digitfont_data +{ + rt_uint16_t x; + rt_uint16_t y; + rt_uint16_t len; + rt_uint16_t type; //ˮƽʹֱ +}; + +struct rtgui_digitfont +{ + int seg1_len; + int seg1_hspace; + int seg1_vspace; + int seg1_nr; //9 + + int seg2_len; + + int seg3_len; + struct rtgui_digitfont_data *data; +}; + + +typedef struct rtgui_digitfont rtgui_digitfont_t; + +extern struct rtgui_digitfont digitfont_40; +extern const char digtube_code_table[]; + +int rtgui_digitfont_create(struct rtgui_digitfont *font); +int rtgui_dc_draw_digitfont(struct rtgui_dc *dc, struct rtgui_digitfont *font, rtgui_rect_t *rect); +int rtgui_get_digfont_metrics(struct rtgui_digitfont * font, rtgui_rect_t * rect); +int rtgui_dc_draw_digitfont_code(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect, char code); + +#endif \ No newline at end of file diff --git a/components/rtgui/include/rtgui/widgets/digtube.h b/components/rtgui/include/rtgui/widgets/digtube.h new file mode 100644 index 0000000000..c29a907f48 --- /dev/null +++ b/components/rtgui/include/rtgui/widgets/digtube.h @@ -0,0 +1,68 @@ +/* + * File : digfont.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-12-21 pife first version + */ +#ifndef __RTGUI_DIGTUBE_H__ +#define __RTGUI_DIGTUBE_H__ + +#include +#include +#include +#include + +DECLARE_CLASS_TYPE(digtube); + +/** Gets the type of a digit tubes */ +#define RTGUI_DIGTUBE_TYPE (RTGUI_TYPE(digtube)) +/** Casts the object to an rtgui_digtube */ +#define RTGUI_DIGTUBE(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_DIGTUBE_TYPE, rtgui_digtube_t)) +/** Checks if the object is an rtgui_digtube */ +#define RTGUI_IS_DIGTUBE(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_DIGTUBE_TYPE)) + +/* + * the digit tube widget + */ +struct rtgui_digtube +{ + struct rtgui_widget parent; + + struct rtgui_digitfont digitfont; + + /* number of tubes */ + rt_uint8_t tube_count; + rt_uint8_t tube_style; + rt_uint8_t digit_hight; + rt_uint8_t digit_width; + rt_uint8_t digit_space; + rtgui_color_t digit_bc; + void * value; +}; +typedef struct rtgui_digtube rtgui_digtube_t; + +rtgui_digtube_t *rtgui_digtube_create( struct rtgui_digitfont * digitfont, int count, void * value, int style); +void rtgui_digtube_destroy(rtgui_digtube_t *digtube); + +rt_bool_t rtgui_digtube_event_handler(struct rtgui_object *object, struct rtgui_event *event); + +#define RTGUI_DIGTUBE_DEFAULT_BC RTGUI_RGB(0, 0, 0) +#define RTGUI_DIGTUBE_DEFAULT_FC RTGUI_RGB(0xFF, 0, 0) +#define RTGUI_DIGTUBE_DEFAULT_DIGIT_BC RTGUI_RGB(100, 100, 100) + +#define RTGUI_DIGTUBE_DEFAULT_SPACE 10 + +#define RTGUI_DIGTUBE_STYLE_NOBACKFONT 0x01 +#define RTGUI_DIGTUBE_STYLE_DISHEXNUM 0x02 +#define RTGUI_DIGTUBE_STYLE_DISCODES 0x04 + +//void rtgui_digtube_set_text(rtgui_digtube_t *digtube, const char *text); +//char *rtgui_digtube_get_text(rtgui_digtube_t *digtube); +#endif \ No newline at end of file diff --git a/components/rtgui/include/rtgui/widgets/menu.h b/components/rtgui/include/rtgui/widgets/menu.h index 0a40890b0f..1a6e85b387 100644 --- a/components/rtgui/include/rtgui/widgets/menu.h +++ b/components/rtgui/include/rtgui/widgets/menu.h @@ -72,7 +72,7 @@ void rtgui_menu_set_onmenupop(struct rtgui_menu *menu, rtgui_event_handler_ptr h void rtgui_menu_set_onmenuhide(struct rtgui_menu *menu, rtgui_event_handler_ptr handler); void rtgui_menu_pop(struct rtgui_menu *menu, int x, int y); -void rtgui_menu_hiden(struct rtgui_menu *menu); +void rtgui_menu_hide(struct rtgui_menu *menu); #endif diff --git a/components/rtgui/include/rtgui/widgets/textbox.h b/components/rtgui/include/rtgui/widgets/textbox.h index e6c1d008ab..989c170efb 100644 --- a/components/rtgui/include/rtgui/widgets/textbox.h +++ b/components/rtgui/include/rtgui/widgets/textbox.h @@ -34,6 +34,8 @@ DECLARE_CLASS_TYPE(textbox); #define RTGUI_TEXTBOX_DEFAULT_WIDTH 80 #define RTGUI_TEXTBOX_DEFAULT_HEIGHT 20 +#define RTGUI_TEXTBOX_BORDER_WIDTH 1 + #define RTGUI_TEXTBOX_SINGLE 0x00 #define RTGUI_TEXTBOX_MULTI 0x01 /* multiline */ #define RTGUI_TEXTBOX_MASK 0x02 /* ciphertext */ @@ -52,10 +54,13 @@ struct rtgui_textbox rt_uint32_t flag; /* current line and position */ - rt_uint16_t line, line_begin, position, line_length; + rt_uint16_t line, line_begin, position; + /** maximum chars a line could hold excluding the NULL byte */ + rt_uint16_t line_length; rt_uint16_t dis_length; /*may be display length.*/ rt_uint16_t first_pos; char mask_char; + /** a NULL terminated string that the textbox is holding */ char *text; rt_size_t font_width; @@ -77,7 +82,20 @@ void rtgui_textbox_set_value(struct rtgui_textbox *box, const char *text); const char *rtgui_textbox_get_value(struct rtgui_textbox *box); void rtgui_textbox_set_mask_char(rtgui_textbox_t *box, const char ch); char rtgui_textbox_get_mask_char(rtgui_textbox_t *box); -void rtgui_textbox_set_line_length(struct rtgui_textbox *box, rt_size_t length); +/** set the maximum chars a line could hold excluding the NULL byte + * + * It will truncate the current line if the length is smaller than the chars + * the box is currently holding. But the box->text is guaranteed to be NULL + * terminated anyway. + * + * @param box the text box it operate on + * @param length the new line length. It should be greater than 0. + * + * @return -RT_ERROR on invalid length; -RT_ENOMEM if there is no enough memory + * to allocate the new buffer. On returning -RT_ENOMEM, the original text would + * remain unchanged. + */ +rt_err_t rtgui_textbox_set_line_length(struct rtgui_textbox *box, rt_size_t length); void rtgui_textbox_get_edit_rect(struct rtgui_textbox *box, rtgui_rect_t *rect); diff --git a/components/rtgui/include/rtgui/widgets/widget.h b/components/rtgui/include/rtgui/widgets/widget.h index 7dd65898c4..60d388cc1a 100644 --- a/components/rtgui/include/rtgui/widgets/widget.h +++ b/components/rtgui/include/rtgui/widgets/widget.h @@ -62,139 +62,138 @@ extern "C" { #define RTGUI_WIDGET_DC_SET_UNVISIBLE(w) RTGUI_WIDGET_FLAG(w) &= ~RTGUI_WIDGET_FLAG_DC_VISIBLE #define RTGUI_WIDGET_DC(w) ((struct rtgui_dc*)&((w)->dc_type)) - DECLARE_CLASS_TYPE(widget); +DECLARE_CLASS_TYPE(widget); - /** Gets the type of a widget */ +/** Gets the type of a widget */ #define RTGUI_WIDGET_TYPE (RTGUI_TYPE(widget)) - /** Casts the object to a rtgui_widget */ +/** Casts the object to a rtgui_widget */ #define RTGUI_WIDGET(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_WIDGET_TYPE, rtgui_widget_t)) - /** Check if the object is a rtgui_widget */ +/** Check if the object is a rtgui_widget */ #define RTGUI_IS_WIDGET(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_WIDGET_TYPE)) - /* - * the base widget object - */ - struct rtgui_widget - { - /* inherit from rtgui_object */ - struct rtgui_object object; +/* + * the base widget object + */ +struct rtgui_widget +{ + /* inherit from rtgui_object */ + struct rtgui_object object; - /* the widget that contains this widget */ - struct rtgui_widget *parent; - /* the window that contains this widget */ - struct rtgui_win *toplevel; - /* the widget children and sibling */ - rtgui_list_t sibling; + /* the widget that contains this widget */ + struct rtgui_widget *parent; + /* the window that contains this widget */ + struct rtgui_win *toplevel; + /* the widget children and sibling */ + rtgui_list_t sibling; - /* widget flag */ - rt_int32_t flag; + /* widget flag */ + rt_int32_t flag; - /* hardware device context */ - rt_uint32_t dc_type; - const struct rtgui_dc_engine *dc_engine; + /* hardware device context */ + rt_uint32_t dc_type; + const struct rtgui_dc_engine *dc_engine; - /* the graphic context of widget */ - rtgui_gc_t gc; + /* the graphic context of widget */ + rtgui_gc_t gc; - /* the widget extent */ - rtgui_rect_t extent; + /* the widget extent */ + rtgui_rect_t extent; - /* minimal width and height of widget */ - rt_int16_t mini_width, mini_height; - /* widget align */ - rt_int32_t align; - rt_uint16_t border; - rt_uint16_t border_style; - /* the rect clip */ - rtgui_region_t clip; + /* minimal width and height of widget */ + rt_int16_t min_width, min_height; + /* widget align */ + rt_int32_t align; + rt_uint16_t border; + rt_uint16_t border_style; + /* the rect clip */ + rtgui_region_t clip; - /* call back */ - rt_bool_t (*on_focus_in)(struct rtgui_object *widget, struct rtgui_event *event); - rt_bool_t (*on_focus_out)(struct rtgui_object *widget, struct rtgui_event *event); + /* call back */ + rt_bool_t (*on_focus_in)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_focus_out)(struct rtgui_object *widget, struct rtgui_event *event); #ifndef RTGUI_USING_SMALL_SIZE - rt_bool_t (*on_draw)(struct rtgui_object *widget, struct rtgui_event *event); - rt_bool_t (*on_mouseclick)(struct rtgui_object *widget, struct rtgui_event *event); - rt_bool_t (*on_key)(struct rtgui_object *widget, struct rtgui_event *event); - rt_bool_t (*on_size)(struct rtgui_object *widget, struct rtgui_event *event); - rt_bool_t (*on_command)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_draw)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_mouseclick)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_key)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_size)(struct rtgui_object *widget, struct rtgui_event *event); + rt_bool_t (*on_command)(struct rtgui_object *widget, struct rtgui_event *event); #endif - /* user private data */ - rt_uint32_t user_data; - }; - typedef struct rtgui_widget rtgui_widget_t; + /* user private data */ + rt_uint32_t user_data; +}; +typedef struct rtgui_widget rtgui_widget_t; - rtgui_widget_t *rtgui_widget_create(rtgui_type_t *widget_type); - void rtgui_widget_destroy(rtgui_widget_t *widget); +rtgui_widget_t *rtgui_widget_create(rtgui_type_t *widget_type); +void rtgui_widget_destroy(rtgui_widget_t *widget); - rt_bool_t rtgui_widget_event_handler(struct rtgui_object *object, rtgui_event_t *event); +rt_bool_t rtgui_widget_event_handler(struct rtgui_object *object, rtgui_event_t *event); - /* focus and unfocus */ - void rtgui_widget_focus(rtgui_widget_t *widget); - void rtgui_widget_unfocus(rtgui_widget_t *widget); +/* focus and unfocus */ +void rtgui_widget_focus(rtgui_widget_t *widget); +void rtgui_widget_unfocus(rtgui_widget_t *widget); - /* event handler for each command */ - void rtgui_widget_set_onfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); - void rtgui_widget_set_onunfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +/* event handler for each command */ +void rtgui_widget_set_onfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_onunfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); #ifndef RTGUI_USING_SMALL_SIZE - void rtgui_widget_set_ondraw(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); - void rtgui_widget_set_onmouseclick(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); - void rtgui_widget_set_onkey(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); - void rtgui_widget_set_onsize(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); - void rtgui_widget_set_oncommand(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_ondraw(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_onmouseclick(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_onkey(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_onsize(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); +void rtgui_widget_set_oncommand(rtgui_widget_t *widget, rtgui_event_handler_ptr handler); #endif - /* get and set rect of widget */ - void rtgui_widget_get_rect(rtgui_widget_t *widget, rtgui_rect_t *rect); - void rtgui_widget_set_border(rtgui_widget_t *widget, rt_uint32_t style); - void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect); - void rtgui_widget_set_rectangle(rtgui_widget_t *widget, int x, int y, int width, int height); - void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect); +/* get and set rect of widget */ +void rtgui_widget_get_rect(rtgui_widget_t *widget, rtgui_rect_t *rect); +void rtgui_widget_set_border(rtgui_widget_t *widget, rt_uint32_t style); +void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect); +void rtgui_widget_set_rectangle(rtgui_widget_t *widget, int x, int y, int width, int height); +void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect); -#ifndef RTGUI_USING_SMALL_SIZE - void rtgui_widget_set_miniwidth(rtgui_widget_t *widget, int width); - void rtgui_widget_set_miniheight(rtgui_widget_t *widget, int height); -#endif +void rtgui_widget_set_minsize(rtgui_widget_t *widget, int width, int height); +void rtgui_widget_set_minwidth(rtgui_widget_t *widget, int width); +void rtgui_widget_set_minheight(rtgui_widget_t *widget, int height); - void rtgui_widget_set_parent(rtgui_widget_t *widget, rtgui_widget_t *parent); +void rtgui_widget_set_parent(rtgui_widget_t *widget, rtgui_widget_t *parent); - /* get the physical position of a logic point on widget */ - void rtgui_widget_point_to_device(rtgui_widget_t *widget, rtgui_point_t *point); - /* get the physical position of a logic rect on widget */ - void rtgui_widget_rect_to_device(rtgui_widget_t *widget, rtgui_rect_t *rect); +/* get the physical position of a logic point on widget */ +void rtgui_widget_point_to_device(rtgui_widget_t *widget, rtgui_point_t *point); +/* get the physical position of a logic rect on widget */ +void rtgui_widget_rect_to_device(rtgui_widget_t *widget, rtgui_rect_t *rect); - /* get the logic position of a physical point on widget */ - void rtgui_widget_point_to_logic(rtgui_widget_t *widget, rtgui_point_t *point); - /* get the logic position of a physical rect on widget */ - void rtgui_widget_rect_to_logic(rtgui_widget_t *widget, rtgui_rect_t *rect); +/* get the logic position of a physical point on widget */ +void rtgui_widget_point_to_logic(rtgui_widget_t *widget, rtgui_point_t *point); +/* get the logic position of a physical rect on widget */ +void rtgui_widget_rect_to_logic(rtgui_widget_t *widget, rtgui_rect_t *rect); - /* move widget and its children to a logic point */ - void rtgui_widget_move_to_logic(rtgui_widget_t *widget, int dx, int dy); +/* move widget and its children to a logic point */ +void rtgui_widget_move_to_logic(rtgui_widget_t *widget, int dx, int dy); - /* update the clip info of widget */ - void rtgui_widget_update_clip(rtgui_widget_t *widget); +/* update the clip info of widget */ +void rtgui_widget_update_clip(rtgui_widget_t *widget); - /* get the toplevel widget of widget */ - struct rtgui_win *rtgui_widget_get_toplevel(rtgui_widget_t *widget); - rt_bool_t rtgui_widget_onupdate_toplvl(struct rtgui_object *object, struct rtgui_event *event); +/* get the toplevel widget of widget */ +struct rtgui_win *rtgui_widget_get_toplevel(rtgui_widget_t *widget); +rt_bool_t rtgui_widget_onupdate_toplvl(struct rtgui_object *object, struct rtgui_event *event); - void rtgui_widget_show(rtgui_widget_t *widget); - rt_bool_t rtgui_widget_onshow(struct rtgui_object *object, struct rtgui_event *event); - void rtgui_widget_hide(rtgui_widget_t *widget); - rt_bool_t rtgui_widget_onhide(struct rtgui_object *object, struct rtgui_event *event); - void rtgui_widget_update(rtgui_widget_t *widget); +void rtgui_widget_show(rtgui_widget_t *widget); +rt_bool_t rtgui_widget_onshow(struct rtgui_object *object, struct rtgui_event *event); +void rtgui_widget_hide(rtgui_widget_t *widget); +rt_bool_t rtgui_widget_onhide(struct rtgui_object *object, struct rtgui_event *event); +void rtgui_widget_update(rtgui_widget_t *widget); - /* get parent color */ - rtgui_color_t rtgui_widget_get_parent_foreground(rtgui_widget_t *widget); - rtgui_color_t rtgui_widget_get_parent_background(rtgui_widget_t *widget); +/* get parent color */ +rtgui_color_t rtgui_widget_get_parent_foreground(rtgui_widget_t *widget); +rtgui_color_t rtgui_widget_get_parent_background(rtgui_widget_t *widget); - /* get the next sibling of widget */ - rtgui_widget_t *rtgui_widget_get_next_sibling(rtgui_widget_t *widget); - /* get the prev sibling of widget */ - rtgui_widget_t *rtgui_widget_get_prev_sibling(rtgui_widget_t *widget); +/* get the next sibling of widget */ +rtgui_widget_t *rtgui_widget_get_next_sibling(rtgui_widget_t *widget); +/* get the prev sibling of widget */ +rtgui_widget_t *rtgui_widget_get_prev_sibling(rtgui_widget_t *widget); - /* dump widget information */ - void rtgui_widget_dump(rtgui_widget_t *widget); +/* dump widget information */ +void rtgui_widget_dump(rtgui_widget_t *widget); #ifdef __cplusplus } diff --git a/components/rtgui/include/rtgui/widgets/window.h b/components/rtgui/include/rtgui/widgets/window.h index 6c8a37cf7f..f0642004a0 100644 --- a/components/rtgui/include/rtgui/widgets/window.h +++ b/components/rtgui/include/rtgui/widgets/window.h @@ -130,7 +130,7 @@ void rtgui_win_destroy(rtgui_win_t *win); rt_bool_t rtgui_win_close(struct rtgui_win *win); rt_base_t rtgui_win_show(struct rtgui_win *win, rt_bool_t is_modal); -void rtgui_win_hiden(rtgui_win_t *win); +void rtgui_win_hide(rtgui_win_t *win); void rtgui_win_end_modal(rtgui_win_t *win, rtgui_modal_code_t modal_code); rt_err_t rtgui_win_activate(struct rtgui_win *win); rt_bool_t rtgui_win_is_activated(struct rtgui_win *win); diff --git a/components/rtgui/server/driver.c b/components/rtgui/server/driver.c index 2fe19347b5..dd441afb88 100644 --- a/components/rtgui/server/driver.c +++ b/components/rtgui/server/driver.c @@ -41,6 +41,7 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device) { rt_err_t result; struct rt_device_graphic_info info; + struct rtgui_graphic_ext_ops *ext_ops; /* get framebuffer address */ result = rt_device_control(device, RTGRAPHIC_CTRL_GET_INFO, &info); @@ -59,6 +60,13 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device) _driver.pitch = _driver.width * _driver.bits_per_pixel / 8; _driver.framebuffer = info.framebuffer; + /* get graphic extension operations */ + result = rt_device_control(device, RTGRAPHIC_CTRL_GET_EXT, &ext_ops); + if (result == RT_EOK) + { + _driver.ext_ops = ext_ops; + } + if (info.framebuffer != RT_NULL) { /* is a frame buffer device */ @@ -70,6 +78,11 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device) _driver.ops = rtgui_pixel_device_get_ops(_driver.pixel_format); } +#ifdef RTGUI_USING_HW_CURSOR + /* set default cursor image */ + rtgui_cursor_set_image(RTGUI_CURSOR_ARROW); +#endif + return RT_EOK; } RTM_EXPORT(rtgui_graphic_set_device); @@ -100,3 +113,27 @@ rt_uint8_t *rtgui_graphic_driver_get_default_framebuffer(void) } RTM_EXPORT(rtgui_graphic_driver_get_default_framebuffer); +#ifdef RTGUI_USING_HW_CURSOR +void rtgui_cursor_set_position(rt_uint16_t x, rt_uint16_t y) +{ + rt_uint32_t value; + + if (_driver.device != RT_NULL) + { + value = (x << 16 | y); + rt_device_control(_driver.device, RT_DEVICE_CTRL_CURSOR_SET_POSITION, &value); + } +} + +void rtgui_cursor_set_image(enum rtgui_cursor_type type) +{ + rt_uint32_t value; + + if (_driver.device != RT_NULL) + { + value = type; + rt_device_control(_driver.device, RT_DEVICE_CTRL_CURSOR_SET_TYPE, &value); + } +}; +#endif + diff --git a/components/rtgui/server/mouse.c b/components/rtgui/server/mouse.c index 27972af2b2..0fff8f101c 100644 --- a/components/rtgui/server/mouse.c +++ b/components/rtgui/server/mouse.c @@ -255,6 +255,10 @@ void rtgui_mouse_moveto(int x, int y) rtgui_mouse_show_cursor(); #endif } + +#ifdef RTGUI_USING_HW_CURSOR + rtgui_cursor_set_position(_rtgui_cursor->cx, _rtgui_cursor->cy); +#endif } #ifdef RTGUI_USING_MOUSE_CURSOR @@ -262,6 +266,17 @@ void rtgui_mouse_moveto(int x, int y) #endif } +void rtgui_mouse_set_position(int x, int y) +{ + /* move current cursor */ + _rtgui_cursor->cx = x; + _rtgui_cursor->cy = y; + +#ifdef RTGUI_USING_HW_CURSOR + rtgui_cursor_set_position(_rtgui_cursor->cx, _rtgui_cursor->cy); +#endif +} + #ifdef RTGUI_USING_MOUSE_CURSOR void rtgui_mouse_set_cursor_enable(rt_bool_t enable) { diff --git a/components/rtgui/server/mouse.h b/components/rtgui/server/mouse.h index 7b8c4f5990..dd62596efe 100644 --- a/components/rtgui/server/mouse.h +++ b/components/rtgui/server/mouse.h @@ -31,6 +31,8 @@ typedef struct rtgui_mouse_monitor rtgui_mouse_monitor_t; void rtgui_mouse_init(void); void rtgui_mouse_fini(void); void rtgui_mouse_moveto(int x, int y); +/* set cursor position */ +void rtgui_mouse_set_position(int x, int y); void rtgui_mouse_set_cursor_enable(rt_bool_t enable); void rtgui_mouse_set_cursor(rtgui_image_t *cursor); diff --git a/components/rtgui/server/server.c b/components/rtgui/server/server.c index ea0fbc44c8..8728a5ed44 100644 --- a/components/rtgui/server/server.c +++ b/components/rtgui/server/server.c @@ -22,9 +22,7 @@ #include "mouse.h" #include "topwin.h" -static struct rt_thread *rtgui_server_tid; - -static struct rtgui_app *rtgui_server_application = RT_NULL; +static struct rtgui_app *rtgui_server_app = RT_NULL; static struct rtgui_app *rtgui_wm_application = RT_NULL; void rtgui_server_handle_update(struct rtgui_event_update_end *event) @@ -57,6 +55,9 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event) /* re-init to server thread */ RTGUI_EVENT_MOUSE_BUTTON_INIT(event); + /* set cursor position */ + rtgui_mouse_set_position(event->x, event->y); + #ifdef RTGUI_USING_WINMOVE if (rtgui_winrect_is_moved() && event->button & (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP)) @@ -87,7 +88,7 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event) } /* send to client thread */ - rtgui_send(topwin->tid, &(ewin.parent), sizeof(ewin)); + rtgui_send(topwin->app, &(ewin.parent), sizeof(ewin)); return; } @@ -100,9 +101,10 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event) { event->wid = wnd->wid; - if (rtgui_topwin_get_focus() != wnd) + /* only raise window if the button is pressed down */ + if (event->button & RTGUI_MOUSE_BUTTON_DOWN + && rtgui_topwin_get_focus() != wnd) { - /* raise this window */ rtgui_topwin_activate_topwin(wnd); } @@ -114,7 +116,7 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event) else { /* send mouse event to thread */ - rtgui_send(wnd->tid, (struct rtgui_event *)event, sizeof(struct rtgui_event_mouse)); + rtgui_send(wnd->app, (struct rtgui_event *)event, sizeof(struct rtgui_event_mouse)); } return ; } @@ -146,7 +148,7 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse *event) { event->wid = last_monitor_topwin->wid; /* send mouse motion event */ - rtgui_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); + rtgui_send(last_monitor_topwin->app, &(event->parent), sizeof(struct rtgui_event_mouse)); } if (last_monitor_topwin != win) @@ -157,7 +159,7 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse *event) event->wid = last_monitor_topwin->wid; /* send mouse motion event */ - rtgui_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); + rtgui_send(last_monitor_topwin->app, &(event->parent), sizeof(struct rtgui_event_mouse)); } } @@ -183,7 +185,7 @@ void rtgui_server_handle_kbd(struct rtgui_event_kbd *event) event->wid = wnd->wid; /* send keyboard event to thread */ - rtgui_send(wnd->tid, (struct rtgui_event *)event, sizeof(struct rtgui_event_kbd)); + rtgui_send(wnd->app, (struct rtgui_event *)event, sizeof(struct rtgui_event_kbd)); return; } @@ -207,7 +209,7 @@ static rt_bool_t rtgui_server_event_handler(struct rtgui_object *object, if (rtgui_wm_application != RT_NULL) { /* forward event to wm application */ - rtgui_send(rtgui_wm_application->tid, event, sizeof(struct rtgui_event_application)); + rtgui_send(rtgui_wm_application, event, sizeof(struct rtgui_event_application)); } else { @@ -349,12 +351,12 @@ static void rtgui_server_entry(void *parameter) #endif /* create rtgui server application */ - rtgui_server_application = rtgui_app_create(rtgui_server_tid, - "rtgui"); - if (rtgui_server_application == RT_NULL) + rtgui_server_app = rtgui_app_create("rtgui"); + rt_kprintf("RTGUI: create server: %p", rtgui_server_app); + if (rtgui_server_app == RT_NULL) return; - rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_application), + rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_app), rtgui_server_event_handler); /* init mouse and show */ rtgui_mouse_init(); @@ -362,24 +364,24 @@ static void rtgui_server_entry(void *parameter) rtgui_mouse_show_cursor(); #endif - rtgui_app_run(rtgui_server_application); + rtgui_app_run(rtgui_server_app); - rtgui_app_destroy(rtgui_server_application); - rtgui_server_application = RT_NULL; + rtgui_app_destroy(rtgui_server_app); + rtgui_server_app = RT_NULL; } void rtgui_server_post_event(struct rtgui_event *event, rt_size_t size) { - if (rtgui_server_tid != RT_NULL) - rtgui_send(rtgui_server_tid, event, size); + if (rtgui_server_app != RT_NULL) + rtgui_send(rtgui_server_app, event, size); else rt_kprintf("post when server is not running\n"); } rt_err_t rtgui_server_post_event_sync(struct rtgui_event *event, rt_size_t size) { - if (rtgui_server_tid != RT_NULL) - return rtgui_send_sync(rtgui_server_tid, event, size); + if (rtgui_server_app != RT_NULL) + return rtgui_send_sync(rtgui_server_app, event, size); else { rt_kprintf("post when server is not running\n"); @@ -387,18 +389,27 @@ rt_err_t rtgui_server_post_event_sync(struct rtgui_event *event, rt_size_t size) } } +struct rtgui_app* rtgui_get_server(void) +{ + rt_thread_t tid = rt_thread_find("rtgui"); + + if (tid == RT_NULL) + return RT_NULL; + return (struct rtgui_app*)tid->user_data; +} +RTM_EXPORT(rtgui_get_server); + void rtgui_server_init(void) { - if (rtgui_server_tid != RT_NULL) - return; + rt_thread_t tid; - rtgui_server_tid = rt_thread_create("rtgui", - rtgui_server_entry, RT_NULL, - RTGUI_SVR_THREAD_STACK_SIZE, - RTGUI_SVR_THREAD_PRIORITY, - RTGUI_SVR_THREAD_TIMESLICE); + tid = rt_thread_create("rtgui", + rtgui_server_entry, RT_NULL, + RTGUI_SVR_THREAD_STACK_SIZE, + RTGUI_SVR_THREAD_PRIORITY, + RTGUI_SVR_THREAD_TIMESLICE); /* start rtgui server thread */ - if (rtgui_server_tid != RT_NULL) - rt_thread_startup(rtgui_server_tid); + if (tid != RT_NULL) + rt_thread_startup(tid); } diff --git a/components/rtgui/server/topwin.c b/components/rtgui/server/topwin.c index abb69d717d..d052e00071 100644 --- a/components/rtgui/server/topwin.c +++ b/components/rtgui/server/topwin.c @@ -102,7 +102,7 @@ rt_err_t rtgui_topwin_add(struct rtgui_event_win_create *event) #else topwin->extent = event->extent; #endif - topwin->tid = event->parent.sender; + topwin->app = event->parent.sender; if (event->parent_window == RT_NULL) { @@ -337,7 +337,7 @@ static void _rtgui_topwin_only_activate(struct rtgui_topwin *topwin) topwin->flag |= WINTITLE_ACTIVATE; event.wid = topwin->wid; - rtgui_send(topwin->tid, &(event.parent), sizeof(struct rtgui_event_win)); + rtgui_send(topwin->app, &(event.parent), sizeof(struct rtgui_event_win)); /* redraw title */ if (topwin->title != RT_NULL) @@ -366,11 +366,11 @@ static void _rtgui_topwin_deactivate(struct rtgui_topwin *topwin) struct rtgui_event_win event; RT_ASSERT(topwin != RT_NULL); - RT_ASSERT(topwin->tid != RT_NULL); + RT_ASSERT(topwin->app != RT_NULL); RTGUI_EVENT_WIN_DEACTIVATE_INIT(&event); event.wid = topwin->wid; - rtgui_send(topwin->tid, + rtgui_send(topwin->app, &event.parent, sizeof(struct rtgui_event_win)); topwin->flag &= ~WINTITLE_ACTIVATE; @@ -495,7 +495,7 @@ static void _rtgui_topwin_draw_tree(struct rtgui_topwin *topwin, struct rtgui_ev } epaint->wid = topwin->wid; - rtgui_send(topwin->tid, &(epaint->parent), sizeof(struct rtgui_event_paint)); + rtgui_send(topwin->app, &(epaint->parent), sizeof(struct rtgui_event_paint)); rtgui_dlist_foreach(node, &topwin->child_list, prev) { @@ -748,7 +748,7 @@ rt_err_t rtgui_topwin_move(struct rtgui_event_win_move *event) struct rtgui_event_paint epaint; RTGUI_EVENT_PAINT_INIT(&epaint); epaint.wid = topwin->wid; - rtgui_send(topwin->tid, &(epaint.parent), sizeof(epaint)); + rtgui_send(topwin->app, &(epaint.parent), sizeof(epaint)); } return RT_EOK; @@ -945,7 +945,7 @@ static void rtgui_topwin_update_clip(void) /* send clip event to destination window */ eclip.wid = top->wid; - rtgui_send(top->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); + rtgui_send(top->app, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); /* move to next sibling tree */ if (top->parent == RT_NULL) @@ -991,7 +991,7 @@ static void _rtgui_topwin_redraw_tree(struct rtgui_dlist_node *list, if (rtgui_rect_is_intersect(rect, &(topwin->extent)) == RT_EOK) { epaint->wid = topwin->wid; - rtgui_send(topwin->tid, &(epaint->parent), sizeof(*epaint)); + rtgui_send(topwin->app, &(epaint->parent), sizeof(*epaint)); /* draw title */ if (topwin->title != RT_NULL) @@ -1059,7 +1059,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin *win, struct rtgui_event_mou if (rtgui_rect_contains_point(&win->extent, event->x, event->y) == RT_EOK) { /* send mouse event to thread */ - rtgui_send(win->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); + rtgui_send(win->app, &(event->parent), sizeof(struct rtgui_event_mouse)); return; } @@ -1098,7 +1098,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin *win, struct rtgui_event_mou /* send close event to window */ RTGUI_EVENT_WIN_CLOSE_INIT(&event); event.wid = win->wid; - rtgui_send(win->tid, &(event.parent), sizeof(struct rtgui_event_win)); + rtgui_send(win->app, &(event.parent), sizeof(struct rtgui_event_win)); } } } diff --git a/components/rtgui/utils/perfect_hash/README b/components/rtgui/utils/perfect_hash/README new file mode 100644 index 0000000000..fa798c1d3c --- /dev/null +++ b/components/rtgui/utils/perfect_hash/README @@ -0,0 +1,49 @@ + +perfect_hash.py + +Ilan Schnell , 2008 + + +Generate a minimal perfect hash function for the keys in a file, +desired hash values may be specified within this file as well. +A given code template is filled with parameters, such that the +output is code which implements the hash function. +Templates can easily be constructed for any programming language. + +The code is based on an a program A.M. Kuchling wrote: +http://www.amk.ca/python/code/perfect-hash + +The algorithm the program uses is described in the paper +'Optimal algorithms for minimal perfect hashing', +Z. J. Czech, G. Havas and B.S. Majewski. +http://citeseer.ist.psu.edu/122364.html + + +Content: + +perfect_hash.py The actual program, try $ ./perfect_hash.py animals.txt + +doc HTML and plain text documentation + +example1-C An example which shows how to generate a C program + which implements a perfect hash table. + +example2-C Another example in C. + +example-C++ In this C++ example, a class is used to define the + interface to a static lookup table. + +example-PyModule A lookup table in implemented as a C extension module + for Python. + +example-Python Some small Python programs which show how to access + some functions and classes in perfect_hash.py directly, + i.e. using perfect_hash has a Python module, rather + than a standalone program. + +graph A small program `py2dot' which converts the default python + output code from perfect_hash.py into a .dot-file which + can be used by Graphviz (see http://www.graphviz.org/) to + create a picture of the graph. + +run Runs some tests. diff --git a/components/rtgui/utils/perfect_hash/__init__.py b/components/rtgui/utils/perfect_hash/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/rtgui/utils/perfect_hash/animals.txt b/components/rtgui/utils/perfect_hash/animals.txt new file mode 100644 index 0000000000..ac29563736 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/animals.txt @@ -0,0 +1,7 @@ +# 'animals.txt' +Elephant +Horse +Camel +Python +Dog +Cat diff --git a/components/rtgui/utils/perfect_hash/doc/Makefile b/components/rtgui/utils/perfect_hash/doc/Makefile new file mode 100644 index 0000000000..6a456a5b97 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/doc/Makefile @@ -0,0 +1,22 @@ + + +all: doc.html doc.txt + + +doc.html: doc.in parameters.txt mktable.py + ./mktable.py >table.html + markdown doc.in | \ + sed -e "s,
table
,m4_include(\`table.html')," | \ + m4 -P >doc.html + rm table.html + + +doc.txt: doc.in parameters.txt + sed doc.txt + + +clean: + rm doc.html doc.txt + + diff --git a/components/rtgui/utils/perfect_hash/doc/czech92optimal.pdf b/components/rtgui/utils/perfect_hash/doc/czech92optimal.pdf new file mode 100644 index 0000000000000000000000000000000000000000..08825a1315b7beeab0803141574fed3a9486d0ae GIT binary patch literal 191651 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μaS*y`qt+j=>cFJGd^LFMA-h<-; z&ZA>+TTy}_h{3Su*!=7yj%~&=(TA>zrY2@@V38t#myo>k2hI|!)q4En0&`@}1c45f z(U}4^4A;-Ij|%Uf9Xc_{JidCG{&W7o=mn`Mb%g_dUL$z5w@Y2bV-WwxCbl*4`sW`t z)=>hM6sP)?ziOZG8ZoZj7@7eGvf@o`R~O6;^i2V_I39 zRv>j7B8OS8F_DL;MHtwm{hDm>S9wL^<=z22cW%95?2h>jS0}!WS9uA{M6`#lp>Uhm zkvn_}%LcpH>x!&n&H?9WW;7z?ZWX+K{Fd_zM}3>R?XQ5-=)D#*EuyBe!3dGi)fTXy zOhR(zkaa1w@cb^)s;7NlgP!oQ9I(CT4R=g5yz3_kV0Es(B9Cd@*r$VVZd>^p;$_N6sgR;jNZ zhwl7r*5`uhX^72b39g;-ri0HMdO&^oQ=Xucf%CKPQ#KP;z*8014D}`e;*j@G_FnK4 z{QyHXEQt}SRWB@TL(!r)x6oqm&$ee6dIQ3VCV;T5yHLU6$}Cj#>pL%ZP&?$`#u~Dt zQd?#z)Tf3=nrnBqZ9kWqecotOTS6{fMqU!ms%p*{6u;J4-g%9R-LHTbLpLlUU1@F| zqFriR=Sw}@z#BJlNu~3d`p46;16h0^QZVQAjWU4qB{j4!Qk*-ml2Ez4iW~}t;+$a8 zw#P%H$R>~MQZBECKG8846RJ?2{IS#E+(sbko$>z8KZLwY%w>;Z02?1HT}_Y8Z*Fe7 z)`^V1gY-6a(Hj)M`jB>PYsH5N(hkQCa08(@laMg6+=~KfVxd9!p(^TQSc^ZM$sopOD z!6jdF2Cn`YMoApr0KuP}Iy7($!RWF^7NTAsG{#;$IIQT_bAQ@(Am|b&e&W_=OyX^EwSU-8EN|uV81~!|H~`p&Z0^T>Ofd zLZWop)!;VH*xvy~WYZb_cXfc-ixm0L7&ib8G*z(T9FG0>~0i6#jYTO*j z^q%?j=Z+ZUq0!Lsjv9V$ON0A>cu|&=C%1_=+=<|B7Kr}}sHejL`dW=G`eDmZEf)K# zchiT)aV+pQ5yg%~jB|fw{I%C@SUd0_pM*LEHRBx_&aQU4 z((d)|_9xy-eq_+U^Xb2M@jnttw*N{bS^nGnizpN`^FOzWbpQWJmG!?Rod1VZS^ooi z{|8cC*4nhgGINc~NmoG;ycCA92#J-sP9#LmdYWQ;h0<8cbZ^>Fkt$&z#!qJqY@;dc zBWT_*#f#=8r_cWZ278!8Gtz_RL5J??vh!V2Or~gTES7AvhSorjLWi!~0KX|b?V6s# z_{aa+6?mwjBo4H@$Jx6bUo-y*Etawcet}?%#n`WJi(mv_5rz$!o zf7j^nXcqaD4VAC5OU(a}xxGLBEL;SgaHa8G_R^2!sYC$F>Hd8FCPXjWP7?d@N}kXw5$zJN32X$ zhNR`QJHi6z)vJ_aBBJR+&el?vwqx`4pw~J77`szdRt((^_j@7QWs!2*JYbdFQJW+( zy+fNfDJ#NteLa8KDS4?fE#6(|+~&;esdln7=IKhYZhh+Z@ObvNdpg~oTsV?7JyL8H zr*R5hRb-@mEI!@LeQQ^>s#;9dEbdQMUYm2MG_B3usUq3N4pL<-mxMwGTJPxUXmaS^ z&fdf}pS~=94lf_4Jhh&(Fy-{C+U!1Ric@zqiAzYMwWz+>c6IxL9cIdZsWpj<+&~V}AH!ZVbun2t4HL)wNMsQw+=z zM9*hATeD@}m4(c8K7F*KR<&|6)!M~6kGm~rM>BxD3b^!0KY;ILC2M{Hz+*EV$Cz+lf7P5f( z0d?aQt!6W8yvDg`t$Z*lX&3()n-A4DwLFu#jBN3hyN;{pN293IRaBp#m!sby6_8-2 zW{K;a%!S+K1t!z8KqZK*4Dd(_fU?!6Fu+6#7Bn!e6rdFdsEPGcKX2Ry%{m_diac-@ zy|in4Ho#nTwKgyv?Khm&ku%F3n#QCQp5{1BuW0n~kMk=fdr^t%nustlaB0J#>*7?a zB^PMxT{AuEtX0<(9CL^`8K@)Hc90F5C>v>s@6px;xcQNvZM)T=a>f!Ls=(a;!`eGW zS=wyff|cHB+qP}nw(ZPHqcSUP+qP}nwoz$Unw{@Ceee0k`0gEjyGQ@pV?BF~SSw=h z9})AJbB2r@Lo(dY{cY20AcBR87P3^FW5K6`#rCqRzrdvISB&&!<-r<2JQ|y>+G|I^ z_#SxFJ~;N*&j~cxy@qoE-7|_KiHv<>ju{O*lV9xdbJX-95OugOcI+crvvJc$SgJ=y zpsSLPR|T;h2MmrXXJ@Sowvp9eLa7@}G^S8|&ceI>ODHu>Qx4Tj{P*~K;*gybloA_0N^qZ+#z?uSCaUmY}BCAb}vbL4wr zs-#?hH4vPtVp|ex&_6>#KMz3hI=xKw2NZB_rNU6)66?%}K?vg}qMw&HcBSxHN|psu zrnKcFye6_J8UB<#!~kvl+E6{?<pw)Vn9>EGVIkOBsHPI6yT`$i zdm!1$S~kdp_*WyJV$gfl4|h^#6}pswZEu?Gmmg-(>F#N;*T z{Si#3(7tHZBMNorh)x#Gi3zB9NpJ)7Bc5b!0`_=Swc;1aZav3c0qSs}#%UEBT?2PX z{m6wC-8}&LBN3ZL_<=1Cs3YA$WPC4cqfigSY+U^t};;UE@#dsLIn-o3WRB87lYFFqBtl7`T?e-@OR#Pn56Th&8-qCH*?O-lpt=&_I8kd6#VX`tn6YqpMLu}R zLQ^8DU5<*XbZ)T<%7f5qaSF<2pwJgzjW|rb087yr9_B1~8qI$8oZjR%80v%>1~?gq zMsFCz0p3&_lF_Y90zDz0#l%>7H445P(MRxU4BYkL)b6>g-i*23GN^*fNI-%{l1AwQ zqcE00zP5x?k2SW||+JCMSv9pKw0x|ys|@bMPxL& zcwovvMEqH0XM&u|U-6kk%ubHdc5@W@r9p6SIWJSFMRyxfhb_fTAY(9G11=j&)kSZ;nUp5LgutI1vUH`=Kn`Hy)EQEN{AY!ssTqMek%s)lxW$T8f znUnhdFN^Kt@yMb=Hd;epuERI{+iad z!vGCajY{IW+wC4L%qaeNy#T3YWZtEbeaWpfZpu(8o=Ze3nUiu)G9EHDK~-KS^o>Eu z?*Y2DlK^5Y#AIO1o^XH*8juYk)Y%_IA9zx|m2W2wV3c=a1|T$+rvFCumD0^pH&>nt zPseF(T-O2y&qqcWNtF9Z3?DET2$PaCk$!f>s@Lj(0Xh30i50plg-?IDZa4LZu&t)hZ` zg?}6J3<+z_A1a`cdTKeeChuV;yLb)8PhZU^Bs7sIPgwxFbNn`20N%P>gt!>Jr~(1h z+;r!driQi#w%H;-!vHl$Jdl){Wl+5W1@~Ze&v^ut!dq zmA$R`1JK(UwIfo9{U%9_0~oGQDMDeXq9;3yZZizL|V7!InP(54&iGpxz zIWZoDJ((5aIrNWtQ>b~)<@P)R+Cc80%Bp250n5Q`E zXDBkU5-hVlxFbQtYfkc178V7A4a0cq@_TJV?$;afJjrv;AFg) zhrfAC$jqIt11hKMtRv0(kw8|(vc6nmL!p9U<`28GDv}ssgT6cO{cv@K8<8eMsBR;x=;~E?1XExm)RZWw806y!MUmwWirF%J5F|#1Z(Rt0{Vvd?&GNboEtEM(C5o!#x=AbpUyV%0 zy+ncl;-Gsd2Ig&PS!@;KMWwX^fr0lvW2Jt04o&X4Qa(EpvkKmo@KP#9AqJ9$L2i&& zV$ns**+rm2B6l+=<^+W|xB&u`9LjhiB{#wJC?e zp6gN)8>y;CCDW4u!rflc%3XO1mSTkI@`QU#tE_>Egnd;6kWRnUe?s)`Ex`vcy8uSH zSJKrr1~I|W6?8<^0%CR&3A!8aBEQ9`oXL|nmQyYeQ%?IgJa%p>gL}C~tT1;NMwuqT5_p)-O}>mTlDo#+@ph*>{5+#jy`svysDE`^8UXA_&@8BHsWw=u%C{L#P1@MnAboSA?pF)xVQnoep+HgrPK25}A*RQFe?<&42) zV-MW<DkGed1GMF$V}Dy`-53ae=c$8^hs)6 z#qfxS6Tg7kxmT*fm33q$-%X->>83m^SD<;0bpdgeZxiWwQxz(Q_q5Bjj1IE8OQbTM zIO65?c3DH!o@M$nB1O(|KLX>D-;fI(0G_Bj0{f#L+RhC!Y z%n_`_71V+Jb=MjWwOWLzbBpx}GJpRRhj{)OSLMe*eNVb8t4!R-pQ4plx6>a3HN6<*zj26n_zMmD72-GmTL23Yr2xU(hrF-ybC@IPZ9j z;WRr{amw_(VPtH>t-cjPBQFH3N}?$B+W{NZ%KjT|jyO=s>IM?8Vap6+DI8E|nr+rBj%8EyQ zOMnr#Mz{aG$mX=xwb#Cn=^826#zYEgHJ7u?t#n`^`0lwVPFkBTjYxO{hbPs?xPRtpz9ilS=-O)|3!IE=7k4jcn!E5q+>B-9%f;Dk zWK?N#%0*&ujC}D~zPxG1#8YY!^vp!xa!KyVnB93@i(29wENnU1Jcw^s!&VWHa?cK8 zB^hs&5FsC3^$>q2{en!_@Q1rI;r*@R4IWE&rHW^)?+x6=5V^u0c4(H$8?UEtr>Kq} zCl|Xu%AQX?8}mDHuLmWKx0{ZPmhSA%cEDRN1;24Jq;?ib!eTJ&2~V6169L^(!spFC zE>!Az{}KgS{FGA6#*`nWB3#r{6MvfHBVJyn-@|n#A1rfPGmcJg4>gPX9-1C*W=bF6iw09e0`xZvyBGpvac*3FQ}cW!kz@w zW4G#a{0Q_CW&ue3ENcz$CiMbQ#u5UmW5<&mJ!g;PEzOn;I7F+h(<=(!wz1**$pN~t zNbj4mZXAMQA#Jd+MO7PBg0=L~SXzW)VV;#Wo=Z*y)hHmR8L$7NIK-I6@mrDedL{;S zq!oyVeTcFE@bwYvYGsi0X2`h8Rpe3!Z7T z^oHIc_iz58`<+WQ^%U+F)6?aeiI-yu2h71DQ-sxX8dKLPZEoUxNQ>7ouyZ6u)0I^> zkn^n2T6$6F(uND^R_qbN}X53uPhhky-$5QCqjr0Ep$n$?8A!PYKlMr5NPC4O-qr#J^agM7g z#A+nfb6}FbYG_+9@$%-Bh7)Nj2_}{w4)#||1&caLP_)_PVc>+LK;+!hJM6~qUj@K- zJ52^Hjh}D*q#@iOQViOUjTn%`&~uZ2y3fF@S~LxZrc_$>+4_6Fa((c$eePmo#ChR+ znscp(_ihlYK^;(i8Mqi$xdZ3(Bf=5KeKF`k^EqZUTKGfZ%8hrW!FVVA0e62Ls7dDx zi5nQGXb{e5ru}YvSMwYegaApb8C^34qH7lVf+9hO3o90%`3<(TQ)Y0DGoFKn5$VBF&-(6@FmV(T!Z{O z9qN}+2%V4;5p!W`AltjLxDpXD$xK-3C1KV-`R7B;*aRfsX?LOa$o{d3qcCGJ1|Z9l zVUzWuNPgmLS?@dr3dUl$-mUS-){#V{W|8|~7ed*?6iTAPVspR0^Cjm)g8ykIoR6vS zyA_gCVd3v$B$D`8|Fj|bI{VL{|4uTKi05PZE+(XOA4h2Vze`#p3M06|{p#tb5JW&a zNn;X{1T*tS5@9iLNGDO9jg@ElXA$BL^9U*95aWqrU?`El%iR6DO#DB+e3#+*r_BGI zgc(l)4=Wk=EgAJNkx2XQ<$sl=*<7kfdiPtre4%_eCiajKc`a0vC4yG>`356wRnbI%%hTfgkYF+7gd~=xbPq$Lu0sb!Fw>m{wM+f|CPj3vDBq%q;#F0#Q4K|ROvI7u zRn~E3DgR_3|HMs(Wuo#JVK)?j#SE2gAT7><|I)*b4=roeCmV)7A3y61yg|NrCkgW~ zeVo@e*zIIX{*xyesh04bH@Y>E5D(`fR|K@N7u*Ryasol}jMh(-86FKue7n~Lgj=TI z>s;kUzi@ozh})Q9olq+=j$lbKEY;ZWzUAQAlW~POc|WMkmKjLA^wr z)JZUbDWotCFODb*;#AAaJCW$I!qnu;Wi_6QL|TBoK#;xC8-eKuNPkr%*kRdg7O3-S z8PUEW01}d=gS0KBI#J!Id-slY&2Ijstc{8* zS$n;m(kq?QDYs)hnQOi4#r3J0?-nsXQm3ex3zNxR5@@Mjgq=xQ-oMXsOjD;f7BOTkN9C$N2<#tUvvI zuy(Eqwd8t1mB|D2FM7hfMUpoE?)25{ZJ3Rf-h`&d6XBa5?x!;jV-Hs(J<1JD0BhM< zu1zcdX#8uvo)nT=!`Eri*4e13j9MVN?evYV&)Rgo=&J?00^YtXr+vYCs8x1PqS-W} zc?*MTGy8o*7vuCin@m-**1kzFvQ#Vmbvd<;rWrJD^DDXDe(!MNDj{#8zjr+C%OSZo zAUEo%+*k5fb+bal4SE7^f&tqnytrIHi-zP1;N|%P_;j9;JS>+N)XVyx6C-?S1_jzH zRY7i%xmXU$RibB7zmO~yynw5gXQ>*mPveBQ5yaN?JGuLLs2bRohM_Y@6d^`gco8aG z@Thr%l3qalBt{T862p!I0ZboN!)SG7! zw;8yM;Y76RAO`|jv7-fq<8$K*6t*Lcf;PgBjnZD()ROVWg%!rT5cr8=8Y?cv zT$((=JVwfq5U&dGm)=ThylNEJqzuy5UoCB}z6?f)9N?Z@nw*W5bizK?VCZ+T(kDoO z!4WU%69|izhJ}BDYKecbB9^5S%w_G1lL?!~0KMmUx;$L&?>bWh1GLu3iv}00e{rsQ zwLT!4h*s%Z>KjY3trK@iS)chWrI`$cj5xSOjnu}RX?-~7W!{1)E->czLz2m<);0tO zfV@+f+MHyB5_^`|pOe?EsnN;g6N@VC2vIEZ;*dt^LoyF^HY&pXE@1(k zFp>(+^c48=I){xSFlgC6z4?iH5O-8{Qmj#>3$NGxY?OgQ4bx+mLJO7 zL#lUaS4TNYkv;C(u)cIQu=X_#d~w(oRF@Z(_fi#If8SPzmrN@wPR=a z9?!CvxA%xyQ_FSZ%$O9(=P+LJ$@u zbt1*^_a>dCCnjrpgvJC9Z%b2%&K~v@QA7G$<`tFu1%dqUQ6HRNt`y9R?Pq@tzPh1d zXJPKiFN0pPG!sVRt6)CWO{fPB=#0$Zkbw`(=@_){^<4~J_dVx3(AoTK?zZVAYd8qcy>^ zoSAnqR0Z?&cdOG$l|{h5jrI#Z+qImWQ77d|Gl zDnv`(RKuoURbav_0DuP9f8lsx z5e0_Al*39YUJjZR?VimAaXA58>LgbK;_h9OGbVfa4rW4g>6?DSTlN_s+<+X_Vz(Pq zbm~#8&thuN(l+W2r)s1wRB%Eh_pG7XMIy@2WfgnNw*-Bk4`%!GRep1QSKUt&Yp6Rs z|@)5yK+&{N67U_XwwMJ*TC#J!z%(rhQN{ z@243p(+u2t2Z8--5%CmWi8PplYB!rjd?X^A3SFIx2G>${YH8D~g>~UO^~aHq4sNh; ze0@8T!(~J*8)E~p`sUd6FBwkz!JTf}rBPn(L&p(r`*$d=D{$7&pD`4nb zd|@`bMQzj%>up{4Ee`nxpRjPsHkgyY+g#(6{XEv3GWTR z@endvolOkSd2h!_)(<(OTBvvWa3->tDDn9Fx#&fLC6&2SSxaoZ1_P;VsbJ@TS`Ci# z52Z>QeD{{j&fKmUP%}=0dh~da7^? z{=43Ba3Do_Tp<@xwu~!UQ;X~^_QbK5>g^);x?vBLJ_5G#+~d!$91{r~5wxOprweQ8 zW$XZZm`{k46Y-`0ey;wHq>-J4>3^K7SsDI|z(oRzh4bIuIsZ9f|G%UX(JQfVGJg-l z{IBErcfk4`{9EPt9dLXH|7IwC2aMmrznDe;aR6pz`0qj)R)+s0p-j>@{YYoTLmoFI zPqRNx$OtpI>DOW`8E(>u`Sc{G6I>|IC^oBMuYWkLL}@Ll3A3C`pOFch>s&586wD$0 ziMC#3_jw<@=e000sAz*uIQnROIkYh((}h4S?YSiD>)R3EL{gIoPUzbud(Sn~j_q{X zlv1+EJ^$b9yS2QQ;BBeY{59X?88UiYe9yYH+Qa9W5SnwEk3LZOzanNlRS5^?A!b@t z=+QZtp0}Z9S(q01Z9n(-8n_28)vM`jb2gLI(XZsM$1mHm;-)sZiC3^PX7sJA?C4#G zt3TeR`yV%}PPd>l;F~j2uu_U!#MsEWh;jQTnDvDAZ*yR$boiF+?09|YUv$PSwK(O) zjmYuv&S322H!b+Quf`9}DqLLhwmLaoN*sHD+Q>ii-Sy`?BhB0Vvbk^zXf~~@9#M>w zkLIg+5UMg>iL~xpd{ODr|0s13bX6OP>%m+MTWOH8Hk)AMNU1~&r4N=j5m zT;b`m)*wSzt)7;zdeD<4)HPZETU3?@^7bHi#yJH7l&^f}-*r15udBP=g8tcY?p8wX zIH8^Bek-#Zf%{A5+m z;wqK72UhS1tkTaH6lU$f-7sSsm%D2XK|hC&#-omo1|K(R}AJQ(tyOEoAA-YbL!%REbIt4V>edf+;Q+9*2i0lk|lX$p{XLphnGu;#!nED z!yh#KkcJg9!(=h^prDtwvF%klGAQE-ezO^zMG}wK&?bWuHZzFx!w~MpDhWSuJj0H) z^LljxDJSn75oUK+0-7<>+0UO;t_BdvTN5$FL7hUblIbN|jsfGzsn!1&Ld^6Bk{nkF z9W0Ot?n3b+5$+`_iTZO(hLLEO@#-8T4WhP4d8R00v^qsJ8Y$x+0+D72Ff`M^OTk1N zLT)T1V1|mEvW&$Lokop7HvtG*x#Lw-1D!UP%8RQ2NHMwl6Cxp1`{ucvMS^mZ>WE49 z+X1+QbvsPXf#e+G9PxF1ej3DC1lNF)$b-5wtXR80;$2P9X;oE7WJP!=$}BifjYadlK6K2u3ka!D&Q2%!z|VR)Q_Ghttq-Xk{R%q%B0s z3Z+OFp=DLALjnLK9tI_}13><_PrNA?0j)e`5S(GeK4cIjEl^o9N0(=8d_WMGKa3x! zrYTK~x_W@KcB8yFAWSNVpGYaYr1B;j!BjO~PmW(2fV1ab83*^zyn7Mz`_G7O0!wED z9Pe)9VF+&m4;){${SwPDXTqKovW2EiA=i&+qEx{_5$K^=jit;o5-R7{-kw;HIVBU7Y zrz6-&RA650S;%(serU6;AKiQ6fXiR>7L+~8GoGzKPlGwD&;YAx-5sx_M)0(`Y-a5n zZmVwU`#}^Rs*-D&0=fEq=>!W1{L!nH2Ar%0o)PL2721u;>TM^S0*|0{zG$$Dng7D> z9|fs1KCq{F8lZ?uw&cV6CJHZ`vjtS({_|1f=zQ5x%j^l@4yQhtfCmt{j#)nlnoQ~P zGrU3MO4sN^np%o!G2+pVzSDh8s{td1e@z<(Oj;J-MGgpENksIUxK~-9fT&@hpoRth z;gLo}Ar1CK0zmN8U?Tt$oKSqTlBmr#Gm43q9y$O`n?X2quA@=YjF>Z(>xmO^l(a1# zwwTaFiZehWjKDE0O;1vpqB_R#|G5Wgrr*GH*k_W74irvqA=x+@8%`7O;j*s~9vLtK z&6Gol7D<;pKy^;g4tq8Oe?lMM9FuGaT962kV1XMC9MggYG9h-4eOCG{>Va0)cq_+OO_pvE&V&hg738F}-W*RtpZ%x&UvdxoB+`^^+p|WDe zyy7}O7b67$Rrg`l7x1t zfC#Q6NeRZ$UsNJt((q9{u>}|Kr9=}#IMS>5GO}hO9MSdk1le(zL_h8lKY;$E$+5#9 zQoMoeGl&FMKYl-fWFi@?3;gIyG!Z+ol3&A*C1EB~=N|w3Z8PjiAijnk+e^-B&q?t8 z4Z^|M{gES$p)Uhx8e;pp@*{-E191e(&%}>En#mbJ)9|xf4R*c~k#GX-mdwn)U?9eM zV&mWQarT*AsG$7dG#4w03|8K0_S%+o$3&JAs`5|kfOLrh(zcoo6qe82{1GiFR1OW5 z=3^b17o6=_SWoeQjXAuejfHc`2qIduy+<@D`ePtp#_Ecv#NH&>BLo}==TajqNva#5-ayx$>qjuUzT9o*rgTh8hiRAx>ESKd*O%2Gt2PoBt3|6ctX zjxjp8M^$P)JcJrf*Cn>7TKS5kgKAvwSW^7#fI0yIC=^Z-n8yN_HJY){u;aF9idZr_ zl(I)fAw+Z`P$ya4u~ce3UQSUX{W~>vHYp5ljey`bwH_>@3(?OzB=vdUy_F=(urWq< zbT%bV?GX$a#_oB%y4}2`hDcS8BTaP^uNVKKN7UTS3Drx|GT9|94*92EbDNqUxHiB( zNkLureV!7gyo2?g^t3aNHyS8VcStleHj$x8(!oX{kzA{q_abjvF9_XG28TL(p= zL`vu_j|xfntv4T2=R^GSz4Zw`+w{!XW>9)cZAv)`3M6%JDW>sCa1v0hoPiii<^3Uk zo;c=l8#4X9xA-et(8{zrCE-oFe5>$HJ0DJ=c7=tLH8& zDkU)poj|+R)AP@l;dVm>94)o@=C$Z++6v#KO!S;paLzLGia3|;AR%N=(?qh+lyt|y z80(-3a^=ONJNqliuS$1Oi|VhZq)A~bMzD~NHZ(3&{NjWuDimS)>6uY>iMGcZRoxL` zAT~KijJf}==p1wqgNSf2OQn0GXl~1TVyA0HU%_uYrt2xj zP(P`k%o@(JY&UZ1S~`nFJkPqhgHt7V_J5JKZL3(8rx@;GPcdc6xRNgi)DV#wJK0hn z!y9dU-fVsix*0^5Gma!(rvBRPnf~H4nbD=>&rg`}_N3JLWB2qy7=Pb|FCqrOo{}Hp ze%_hOH%7dh9K9Bf+*Exj>4(h{-8H(Qd{F0QbBl8Q8%}q*Jg`CTMz3SvjNUT5m{c`9 z1p!Z9BXicXG4;JyR4-HWwl=Q_OfwlX*98269NJb0jv;O* z?p(Gy4+0?S#O&5?xZkKW61+(K;<4fzr|b0NKlRuNLa!epR|QP!%4UYzdarsKT7z1# zF1rj{>O+O)ZNdyZBXM%WcBntRB zc#t!)8p&8b<}$k$wci6g{RRFoJ$A`S0O&p)%!97mb$QbPC5RFGquW! zMAF|nMC7cmMOFuEm0!}GacvE}lUsTH#HZ*GSw+wJwsC6)5m#%|owhjKmN57|Qhz*? zG8;a3?F~ju`J(@wyriRizoG&k=N* zW6MJqzcfM+H4z+<2I>8q(vKBknV|=kvF^q(Z-c_h6drS1YIrz*MA`Vo+_+-8YVk$a z42?Sy^lWha%PLiy*a`)U{mH)|pI3Rf$>Oryh%02)vi!Fwf=e{tVaFj!BfEEYxPy1b zY4<4atGfZ~RbutLpz4A-_0el(`pInTlAVmbP9Pe!dPovD(6Ug81$)wYO7nB{r{}Mr z^tb6yLk7bO6mLR2^)J|YPANs?U26TcM&GLT;OjNda__0OE(S=4QtH1hOmD?2T9@zB ztb?8L)qQ#y-S{rmefDB^C5!n@UlEfp8DV~P5~m9Rj)aj_U+1gt;qj=t3ce-@A!`b6 zW{FKSPm*tU+l8VXImHGddUGgjl~w=`f2u>0som~ax^$uRHNoY!+2vT&6>+ph`Rw)y z^67m}C(?ZJWc)XWXsyLx<(~FJuX*rVRUuVNGd_2ghn08Sx_#L4P{#P|{Jalq@_hE& z*537jfAAxHac+H~=XSKBl2LNTybxz5ZiBwa4EXq-#@@-Lb40JI@NY9phrAH5Pu~~a zh=Rks#!6t{KnmsMf5AoZM?b?4rB%CHIw=iZy*#Kok2x-p!uLsU+78YOqc%y=K3Qi# zF3C7MX)40Hz9**}tJglZ?H-z1TbutN>?jt=3Wd{$pInRJmvMC#%4+onchO@n@5?CZ ziC340v3pyhCu|f9*oeqN9Irkv)gqIPNqacE`9YtxjcG}*l(h4~mo%3V!agGo5O;O- z88Y_;%=Iu}3BSsp4EvEqfQoOVy<4CpJ!u9o&ta-glYV#~i=Apg$CO4@504i*H06nt z$Y1>>0P4`HklK4l!Y=nG~)ZUXaIHf?dOwzx( zA?}6PZT4vkJzhxFuKUf9E5$irQI@4F84~|ASxte`W~% zgJk{}@RF60@tctJZzbga2E1haAD5r~=gweOrhi++{Xb|Yn{=eVy~t6gD=I6Y%2bg| zNX4MO#W6_gD92NNvCV9kBrqBZb+FJ9#g(y*q9_!B`D~gfdZiS*`U<%bcK$ZdbdkMp zC=Q4%loaFMD$P2)CmIfFkibhB<#sc_CbQavryVeyXf()<9gn$>v#+_2H`5%+Xi1n( zLO$P?I|i;{dr}aZBD2+QlQ}uFWC86z#7iM*3#2R+#X_>i;Af6~)1Rka-+D6jr2v0x zdUu#3+5#Ce`7_*Yo^|+cv0wt_h6@1k;Ui-fmatI;CJR6D4*(d2FEiTLWYao0+5A}u zNa((-HbyzZ_@KJd=M3GTJ@nn&JYMH75!Wy?$D?r#^9Rq=yo!ma9GCm_!R9@K8Tw=y zOEyMweHr)-IhCQ1^{m0o*&VA>d>C=BloW3wq7u?~(jFj_( zQnmJd1d>Qfxp{3283XT(f?Z57M>+QS?KTfC%slf}tQFDCq6k*~#I(&VU&wtMNz2o{ zu${eCJ$n{}v6%X@fXK;YWXRmx*TGy+Ek<}64C=gzeK-VwtzskpV9yk}l2}Mad<6fI z%-g}h6tZ(~Pm}4oo5vbTaK~Wlxx&;?o}lu#JD8dU)u=oQneHvAx}1B&d$x zF0s#Pw+e&kst~{{0p&1u==E|ayex6I%p8G%IcP%c!CF{$ldroL2EQrAd38Mb((W86 ziOqTdTcKs+Yu!kVUxQQ@4!EkQmM@6M##@xK1&H{AH~_+ZEd+WuvyZ=er=y3a1^`O>OSwanL)4PU!Op;#x<>s@ zI~r9`$|~?7B@BJBzX2E7hrs+xh~k7X3g#@h04?}*rbgbo;}?5@1wVtQT*`rM=KkRb zy|VB)HjduFMzmeI`RF$y+wXxbxpl^g2=KyDdC9Wo8ubJ1Sds{8_tR^`4CGJ z>zwdxYaRr?HLPG&A=382S#!g_#)WW!XJfj`y~>3bj^1@YNMhjtfE1(+OyRzZ7hGxc zjAdd7O-#I!V^Izz9=qQ)>v7*|r8G&*J<~;8>PVxx>^YeAhz{{Sn()iL%Ow_GN{H^h z`y;UH$q?IjiN=HcK|Z;AgT$xh?!jj^<>i_{_@ad#aj4* zk8+9L2`!4MiwxXO96(uq0@Vu42^3DhK3aAp;;|e-rV9};n^le0ujd@);W9<08xTMp z1{K(Yy*XW)enT}N(+me*&8{eCZMo%=4y}8o5|YLEjiLsmF#-@cP%TJ@4G-QCqQP*1jHhTt zTNFq(^QIWQtB`;*t?(D=Sj}hSK$^8{r_OUIYM8mVWB>XR~~o;aF_WJ1I7uz>3t zyDdYE!b$2VLLoL(*KLe} z=CJU!lsEVJa(nH~RQiau-&cZ!M-wd2sB`_An_h(BbzTIqJgc;C66bPuZ|7qmPGtMd zld&Vhdc400PR+nES2H;2t-fQoqqd8H}%7p ze{hqQs(8)EVy8ybPF{;TpAKAwHvkF>QgrsDfN_}1{N2Rql3=M@?RfFMBUx zg-Y5ii_4rp>;Y=#=kezwgCaevkv8hP#IH703%Vw9>^;v;G;XOT>M9-|PD8obdMYDS zygbxyQDIHp!H;eOiyEwjFeY+@DbhfCwsi)I{Tj|TP<)td?w-STr zye%VQ9o^QbA|0f96kI%JC@+qH6pvZc-`op2)!z!3kG@?QcaGcTgws@D;BpqjfDG0M2D^4Rr`UbJc1f}a7hH^{-@;P?R(XKe@Ox3xi4Qp8(J zB#hJ<41{({-XtStlnIlb;DWKE?Z4aC9SAWi9C1PYSn!lgIsr1&`*Bv(WnqgY_G`8gpWa+n3v-5B&H?l&;r*(B!l%a!adJYC z#W0%N-vCY?d9>bru|}oDWX_X$*BmCH>W08tR`--LKK6EBCD(4^nc|Y)%*S6h*Y`ca+x_2 z;>fRX3m-%KXch$}=em)gUc`W=Gf6D2Y{dloL(+%V!Q;nC4eYy{{k{KsAV$LkyftP4 zN9yet88J=~YJrIq9Rb&~smZIYG|M;lui_RRU~_=~&a!yNiDV5(N(+oiX%%p8Hu6G0 zF;MiboOG@sF4haI_+=!Gi3qrY;E)PoQx>25xCbI~02TdXo2x<$PgEBk1c=v3JPLxC zVl;ZfQ>0nC5VcY#WTtK6w^_J!X3lEUfvp?#NCJMa)AFLKb9UY*?RuCkecdX zJ_U)1smcg?jZSi!&J`?@VB)^!tT5vJZjO!UoVKuvG2Pe`av79CxymLi{6zKh<(RWR z#mWJU+dDKtcYwj=$u0RxC|a;AtJ4mW^*1W<;qDShfet+o)PMkb5DH*PloetRprYt5 z*R$SdiNHBSAsU3{AMD<;Nd&fHq>so4LP)s>*g2s}j4xf40;0pYM{nKJcTdOW^NpyX zlmF=jJ%Z4@#3)w93F)$3tmjPd0f|}o)7>0C<;0qsy9}kS}K{0C9}W< zyM&6St|`j8WTbRvoY44Xhfu2Yo9)U{O_hH%iISRR0078jL|)~5Nsbmcuq+V z&jUROljSA&P3|UE862zn$sUW=jFP%JYnAmaK4&jiB&TXjDj0$6u>OXix#pj}(JBWe zEd53YCjd(7vkLJ=Cu&ZF;6t z99A`Wt&^bC{D<&@DrN7WvXKjou_+9VSW;F8eSp(Wph$ug3#~%t3M{Cnt*4-M&qGi% zO%*>*qll!F~m6jMe2+3z?7R)0f>m;R_f=o-nvM5oUH5 zK+B#2Yh$JW+@Fe-eMF`}r#u{2hL(D9O=@!uv|Qi-GlCgllk&FUar}8GTJ4{Wk+B75 zFrVG9mhZrYkBF&?6ypY1^9mdzPs@EF%>Ng0ZvqZg8#jzswh1A!R*VR3W??L)#+FpJ zl#~*KP%4T_sU~|=Qc{#GEfVb;r7#E;MWwwM6qPb)85wi_zjN?BGBfo4zwdp%GuLI7 zbDv}G-@Z?M)uag&A$9$wdutl-qv{Sx)$Tkd7n62x^Q%<~m2=vSE^WVK*L2{k*ow}D zb|(@0;?|1XuG@?qS6fq-8wE}iy;^_Ot6GJTVn%4RIDFuTO~|7kky9>)OR4Xg!7yF3 zQuB=IQx%Qwtd6_UC+x`fqq}cLJgk)6*REw)W~}>7bN=DCjTbG?u1d(8G?v2k#4VU0 zp6?cJV;Smluxj;dwcMriKT`AzuglDK(Mbp69mxqZx$filCc#T4XS(BLz10@CZ{J)I zbUJ9c^UK>f$(y0CH@W{(`q)#wajf%{$&)M(;YY7~pK+^_V*Z`A_-nqk)NX$Z>*Leu zH32mlZ^x~(-2Q61VHIN9X#D89BDHZ;=L-9cA=H9Y?%~c#`(67ArXE|t&btT<)%HeL3yNn!pd?ZRzYE zk!s4KTVHFxOPnkB%60~Ks?OSWmC&fC8n$yMeEQgxIwNd>i^;}q*ONqVR8F>5S@}Wp z)6@$o1wK@#7gY~N%U_Itol{+IXoY{7+3r%J>9To^vsA+M==mO#%wBAXICO1!&>QjD zW4V`2;uJq@607ixUo%Je>!s^+UWce%KH+7)%Kg+z(`gH=b$*?kr4excW*ChPqZJs=OLH(DT0A@}sBuVF6 zAAFnD{60Bk>!WweEuKlw9eX*ju&t}-QCmu2!re{N=W{!`JCKsh1IOmX-v4g+v%Fia zY}M=+K|AnT<&SzYV<=zM=?4>+R9a`>UE2CK+BW73bMBP1X_gB#uB~SohAh5KBb51Q z1U4Hs)@DQoySMXB)4DM`|?d8r;ubUF6Wb>)qijyTd2-)GBX&pyqtHr7ulc z_HEU{2UT66E0ozidhC!DQ(W>ycLrVyPpo-my>XJieNK+o;l@k1r!8y^Dr+gco2YeL z;mo1NqU|TWzOB(V>|C=tXz?aRXD!>17IClIbiX{V)8xf1(=83o$gi0!YWv!o_B`41 zUd*S1^4iXy!qskX_;@7l!kG0lFF$_uvBQ0J-pp0{?o~k_<-S#3%{czPAVtG>z8gc= zeKzq~y?G~$MqAi)*nPD`)xGw$@92`y~HGQdJkh3_2=VJ z+7rKQEIjX;WG-}O$&O`b-_ncd=>Us3h`^1@eF{Z_6sb2(HO8E!|5 zHXJc4^ZARK=F5SWvXY-4jQh-5X*4cQ`jkQ%PP?s$ncyaAON*{mv6_9_2}xy^&X}D! zmAt;&0&ypES~lFNtJ7$2)$@JuuE&>sq>x=WRdj{u26=8^cU`s4)$X3t-S$p5?`+8L zdAHs1w(4TXZ)dm?6W@=|@Y$L%vhMRe?OU-0TbP%QcI>Qe|Lipgyd}75)>zwLGbfZrEs9$*=BR4JHtpOGgexS;3UPsY`H;GqY)X2BJk1QxW`uOlck+thvx))vlZke;YwNUnE zbV*FOnCy{BISZcTkF@kvXx7VByETU;npPhph4b+w%-3sQbMCO~)kPM1Q?8YabB-$e zQu-#A@T%d4rd@RP{F$Dn=CsE`mv7LBV-A4>Kq-?gy$)FJm$*tI6m z?vb*e)!zGaOg4`f+9>^d7jsu@LBfgybqw$EW;;{sp1yu!RipWk-1w4sv!TcLBdazpKQ2ca`RE=%XuY(IV1_atM?^r9{4 zWo;+#<&gEh?yr~~Bt^KMZZ^x1?0Y;WH}dPJFSnwb)lQf{nqKodY-d`N`5Us=qgyoO zBh;z4y*G_o`lfr4zSrq9JN<*|M()tqxx%0(_7wisNs&9BeRWjYOf@Eys?@lrYN*7z zuPTdsV`Xz*$6IFXL(>zfKbD?cc5(+;?qP z?q+PMO!py$Z#nWbkrv;4z}02K@-MDG@*y z8NJv+8tu-iB1)8RVw(hb+>{)NUtLB_F4whG2rbAwGd@Dt>7?!h%bRX_??vVq%??aD zw9;is5b6A}1EUUIm97cRlw#iXj8rHdLHYH2Ui3oeP#MX+8!|ep_XhjBuR4}E zs*DG>Ztb0#%QV5Y~p!JS0T=Ck&;;+b;QLJoGk5EJR3Pwur=7hda_ViLE&gZm5Mca6v*r;jd zn1Wnx9A7Yvd|<@IuH0{{CT-&=1qG+nS+lO?nKkoee+Zt{mYClc!3ZevA?AFebAw29hF^9$zw-s|`6X~!q$%X-^C(Hne?4FV1$TH@sWRz@$Q z1Kj7xOHE29zIK+r8Iri@U8u~X6CS6Ij?bIpZ00>m{`ARsYp0s9QvqN)kh}{pc#=?>>6IWbghJj}es@iIF!Wy_Z>Uxiwx=ZS-^}k&Tmcwin$yn0|I^ z!Oq!Iw8m45rA6Dk_M9HIwqVDv#{GW3wlBXkMcBi{;MLPFk%xAalGGE&{jkLSVpZH} z8fP!#sa_rXB3WU~^l=JdDUB0@SFK&<;`nQt%EgA;HTAbH6x_&=KeyuoyL_rk={bD< zUeALJPWnk-E1{B*v1z+y*9Dtisbsz0dA%h@YTCUWk)}5lmzJNsh$CBHek@^Kpc$k- zWBG$HMvGtJCA-}}{ZH9^aw|ymD8)x8ZpaK@8tHq+`_>8Kj2oYr+2S)tiQYEYdhpmr z#hY)xZTI}q(5Ra1^+mo`(pp++%oCxN6&{T?9&)!en~v6MUfNM_gy@uZnaNtn^h^*U zf6N#YGLb@^){@qJrKnZ1drln7lhry`zwy>KtGKuO*X688jlJ|{K*vs3ZAFZ; zwuraAZ{6OiPfX?QhaMg|>%Mj3wQhptmhvg5$0;rfd4J~Dt-Bj8%Ac>!YByc{R;xty zw7N<%{$NVGZSJGk4yTylc#(zzo8`yr9p)!%7mXk-NEW$T``zQ)*WjznuKSA?UP+P- zv{Kl2ZvDpdt8BC%2_F#;meHv!7nZ)}mt)30(KLl>S+XxaLU{X>kRI^`H?(agIJ}m$ zH>vYVZ?mZPEOI{lRL0OUuj5LvQ*OtZ=IvS|NhQxBzobkY`#vhkA^IkhC z3W>jaq9jHqA;S@;`n<8TN9L+e+v<%Ks>K?aYbxSg8@LC39FB+1I~(w9r_py=my7qN zk>5znRv%?8x;^@x{^v1sh3C!^=;1<7RGEFM8nO-mf7`Db(U*S9eJ`r)zHA^K9Nv5# zFWxZPcl*Mr+mwr+KqQKgKlj1-CZ!2t#X7Qkoqyxk{yvtO>9yQ>l*LKU-Cz9gz)$yB z<&3u3Vm1Gs`1#`H3@4*&1>##raWWf61f-mmjotOZXK{2&XzH6IEz@f*iRm9%otmRC zu1QoSr%k)%3u~rz_>Z@DLL{=+Y|NIE+eDDKaqkDaq%%EZ&F^ngKd&%wX zCuq#9upeBfd0CC;j;XGgGn0Dl( z-p0$0LE`gCe(s&;&941gR?@Vnc+BxVcjVW!&ut?`x{6NLf7430VO({IP0rpHk8E8! zjdfr95=RL!o9a{dj_}S*Nl3S0YI+&F%lT)*=E&mpEPJf9H^O|{Fm7LF% z>XUC`uf2YLlP)xQ$$es+$byY=hsAuVKib{-=%3#CdBGfKT>j@AC!NmD`h91QR!dAh zG0U@~bbCy+z6~eY=KNm!69pNUj&Di4n%m0p-Mne>q}SB6+I5?*8gSE{C&erz9-)rY} zP0Keimyftoy)r0my5hwVpW`BeC3x=cOw@UG$fiJ$zk!&yQz->r*x$U1Sx)mKzE%~ag9 zW?Qb$uHAX*3Rkv^mA$Bx+}S11UpxaOQI^JiRdQz`aEFr^4Khi&K7@Evniz zZNq&Ry4J4W3D27frBmnBZT~*wtWU?g_#R60t{E%$nRXsj=>D>?IVYQ(a~64i%;ps} z|I)&!rA5}|v#O^iGMb{r(w*L1FO<6Nw)Kwig&DqGW3IowHpzBN-I1yHrmXMmSc{0? zIeSXtcifU|AKqGJ1eLrzoc(Ib@A|Z450_)JC~~UZI5B*Wvi7PNr)z=CH^-iSS>Nnq z@$q5A;;$(a^A2W>^9lL3@EUW$x|!x_CBHiK8W%tDXmdQw)$%So`a8Sip({)XR!F9< zh?ybzh@>&a>B_#mlgn?udlTtMG2GenGqLO1c-gARnRC6%9vc5Pdbi@ZYgto*$Ia%) zM?0_4uBL6Cm3C^;xaQ((FMPD7-V0g2y=}6Os`k6Ni@fgb+~r0OVLKrcDEB7SJ#8&> z?pf%S-9FC$<(Q`jOe!w8?qb)5zinh{`=q&i>7sn1QG2>S*bDiU)7fh$D$I;{EcJfh zoQj&o+Rp?1xayfpTo*pQ+VZn|CS#;s!ALC+>Am*p?{Dy^pvVZb)vZ zdi0fPTU>G+FSDpZF?YnIiMD2?lp~VIyBD)ws)>srrPJq%DjJuGG0N*DS(Tj0VX+k} zlSWEMve_ONQ;ts_k#4wPp_-jq5_Mr+zM|;F@9A;Z){mdC2$z)7Q<-!_N9gpSZ;A`N zx_)!Ejn9@csu*{xN_DYUa`zWb*UXfeQUR_dmBn+Ho$$ZE;m!J(RqS`>SGKQHey*dz z-eiBqx-p~cdR5o{vv++r?eA#%?oh7NwQIE9>0Xm$wwvdDKI(dXk7Pg(gEK{5>A zGFQEq%5S+In(_7K&8}^mpS>Z)t<1j}z4EB>rVA66O*}Tr-!|v%S820n%i_P@vAn6^ zlB(0J82y}cg0fi3CL}U^+%>tq+tfZ@-cs^xwikZslb%cFF}Cr68T8i~44Jag!J7h4 zQRP{7H-xbiFasYlIwh?Bt|`aFgF0 z3%Bo(A5Yu2kLmI?DDXlI%JhLf(H%;n!}J=jZck@MlM}u3s4O{tH1eIJPo3^yt#JYwHN6MM9yt zinRUWvsURakB6u@XlrgJ?5z%FoLc`bE`R4u6_JvN&>doKA_kL>?~oWvB%8f`=em600pS>>W`?0!X zYqv?RbrZX!bn6q9#<_n`M$^;vgXVfSlOWB@!LliLqIS3&6{=|^g^8a!GPTq+bdue{ zr`1&!_^dOI$L6<`Y`cP6didHxsoXUs9SbNbQ9BCa8uQfsKbJih&$c97&z=!4r&FKX z@L_@)+lAsYV^ogk>$3gAPn9$Er_Wv!B_^a*{$_@>#MlSr54z5@ke59uXl=_-*^&F; z%%=ve6@ga_7G{U0#1Z5OvA4oJ+mk&rT+fd?x_ydKx?sIYY^OP$bm ztJZ>`*&X;bVz#90$%wi4BF)00SV7XXC#6rA3#80Ej)uhq%tmliuB1Pg2{zfiW^3cj zT?-wa)J<4$=-|$tuU3nN4?5(u;wGB8eiZU`zHwdEdePj~-gKRYsX8mhdH&SCZJs1{ z`s)JS`?Hlm&i=GdUu3B0`13Jw{ZF5DNe?ufcJA{Ne8Qax zBTPQEop^4fJ11cCyaVm+%3saYxMS{|UqAb1+^oxT&Gs8dgnxY}_HOIEBIdZs)uDk^ zXP%zb)_JnP@Uh7{MJ-y=R2vWC%OYIk2x(5qGZT5?#4-ze_x&dG=P6a6l3l!8Xl#VN z$^O^t+B2@XPO*LZRQ1q>xVP~*+J#TJZEBN*mM-}C#r>=JdgO(0&fHb9tO@F6You!) zn%t#@6&c6vbGz}q-X=TXfcm;Ii<6BDM&nOEtlCt#+b8eg#g~lI^D{^zz4dfBx%Wl# z{8VK%=Gd?Ka@9Vmej@$A#P(%n`qxEoxGtY`aq5Lq=jhDe6RL`iM2lvZED4czn%B0l z_2p?B{UfoDTUO>xIKkQDQf%2OcJz`XZSC=p7boVvZYa1bw5l`hlWM%QZUBQ!JL|s6 zpXK2DDqN~PLG8e}<%=UNWO6kU#onvq*tQFulP&u<1^0A~y#6s#Zp4d= zMWNevrZMesDKD(WZf8#S&Zxo@B1>!2*WK7N{Zz9-(*BUtcJnnk0WzJ>mr?SQR(PeX zWtGXhZD{aWc{M}$&?6ny$ZZ`8KUL1fJ&I~uY@mJe@nUhc`)iu+)g21oCi_BOrY1VQ z;fs%Mvi4CE=V`1xiHV(yZ)^?lc3e36{b<((p3O^wHOtCnkol&2wjSJcBYIXw$+-lX zF(D+CnQEck&x|^cAJl2c-C3WjAojSX$^C;TL29}9^d1$Dm0}Z4O_rE{o_j~AX2cDV z`H|N}49l-KY`^6Z7~{QR)wNrG<5MqeJG<#*xOCktE1Bnwfg4imom8J#pD(*P`8M%) zcgm7zW~{pGxpDquY(2NkbFG?oXywY<8=}q4zb0n}1!rIW_UZY^W*5bEv|AGoC+ap| zjums!c6OAti;8y2u=Km1`cXDOM}7ld;>#Khqmt2AiCbg!t~gk_|5nn;Y*j8@^xfgJ z5Lb3*s_^ggCNrhSy6R*sd49`mLV=@~btgscU}md?T>WX~3?pro&8x2-Pn};G=`(Tt z(!{6uwvvx+7Z-9~bzKX5v0*bgopqm99l>BA3LeJd~Z(c=(+7LCnn5arYV~<%g67~&V7%sh;Q6dbZfWy;}e0`>Pw$Q zdwo~?ar^9{%+|_@BkH=A7u71-#3@f>Ygx&~bSl?+K2ANgP;>28no5i8>?^|W*S<6h zvI~$~GJb~N!Y7v3^~U+xeSIdmmHB9gWrc5yXd=$zvC@j31u*N|@KK~LVS>}Nuj(GV z>rTCtSy^z|^L3Ou{{8G(&*YnaT+CmqBF!*e4Fn~UcWl9BPwn=yBOdzrj-~r641dI~ zicei~52w2`&DZ1JrN+3e34y<7d{V6*x1hSc`jln;=FHb|t)iLM%ja*6v#O!b#6;c$$Xm>pk3O%8j-M> z0#oSDc!fWh8@+U#I49`fqc(Q7O6cqM^}j6{`Sk>*u)L^v6Q>BXUtrB>dn(nR?g3k&5b|wNce;37GZbf_Y<*} zi#NuHTxs*i~XX&#|Dyt?|`mPP%Ir{dr85y^ecAx8mnJ08sNkm4(NWc5vLgTPDTCKo&R^D%l~kW%Yga?!~XEWfVKvs zziMl^(EG#n&Q7&w6i&*l$Un29(xv$2{Ix!X<;-1Ula_o| ze-OH=LlK^jW^I+qYM{4F=DJ@I898$Dj4-WGt@s58eQT53_vQO9&p+s*?$!1vq_bdG z;jh%hl&RC24(xn?Z2$Y1_XnMR$I;&&OT1(=m*9HDY1`)<9mT3cglz8*@%zTj_IbGY zT1{nI^I7kcM^lb?ebo456Nx@)g?>B_u!v!&xAccxQijdTsg zSHwBHBxWspfAxwROft|DYg$x0qCv@wPWR_HJh||Y+bjw$g0L_^!PK;o);_@QJMDLOx4RKjkWXcI*Uh2Vt&b^6T*59*`a=uc*A1KMnlvH%?CvQMLy>qVM0|wC>C1 ziM1Y-D-9{Q9FKRG&P_8pWf)3r6O&t+{HAA@A|>g~^kwg!n`P&HA2nm1r_@mmD+gy= z!$MD8pUrb0HohKzp+j@py%Wz;119Nv8om6stght(p&=i4)kKU<^V<@AIzJhANwKhe z#$uwkQ|&V^+iO{?;&Trgu|6~+6)VnZ_>1W{tuOH!*?K>*_*=u4TT|;RC7+M=HcesS z&Tb6KX*uO5DVKL|lkIvrX}xqY2Lq`ovv4{&%AX4zf4UsMio5afxpdfkRmB&9U&5n5 zY20y>`g-liHl0;7piPH_;)mwGt)5`-+jd-<= zA*$#%E}LFY&%HCsF-@v@ti+>Y&r^vOuLzO*wyc$Kl8LyVe_Uh(44uUADWv-?uxBX9U1FsVOU~3_3p@d`2c3fPsVZYMG^~d6pgq2Bi zO+20irL8PF8D5a_v6ZuoZeIIxNubLS?c_`TcO@o$qT8xbnfFPycMgB?aVJ1Ba=iPBCeK#&V zHfi=#TRrE-&>e+8)xL-~oH}W5^1@|_t=A31R3yJ==Db~BPCuuOSg1Pd%Lvo2Wlcvy z>my6_-`~=T+r3zbMb0CCv6lF{ae>T{OQv||aEHT2vO@9A-sc1Kk`l)zC4|J^JZMiV zyZhvEUX!-4NX}h%`qfsu!aVC-sds6wr|WfOu2VWP_9R#J>j=-q9Y0!rwA8J75|hNM zZ7}(cY8#S1h4@d%*a!{c_E)m;(Ki3Tb<6-Qwq#qtYJvmJXEnigwbvS&xqmQz1*&We zNMyXBG1*ldPHtMgAqbC67!xNrt`79yyvcKQAZRCtP5z#XR|l;iI9OWY3G>&(UCi-> zC98vj;4&+J^ddb>LyCiXBUr!(aHBvx8VGkpKLR*l8deXzci%q$m%k4-)*Soi|9&4m zJ#;49AK%F6KZB4y2~+KVLP!srkv{Mn>689580qW(1CD=Tq)+!V}l{u8X} zW52pN2y6QKXf5d0>|U`Nuc<@93y^u;5@A@z4>4_@7}7eomkt zLI2WG@5I4@FrttKB*y-Cu|~nlj|ahsg0&I<@r}s;8TV7Ltl;2pgjF#A@r?}rGs>o5 zF3#X@gryk&_(q2RD_9$-J1Cg?m9#Cd@Oq&Jb2@BVF1>#qT_Y$EV zrehq%^)QZf6z`R%@Qg_@c*bN0JolaN{2g2I%eHuVg_BqOJ4y>HluMy7XTSh|1Q1l639{Pk*m98+-_sYrMTzgZc%1yMicA zpb-f)5`ji0(DVp2eFBX_pcxQoh6I`sfo2S+(9>|91Pe&8f&@!Q6u688t4Oen1nWq! zkPHjS=#5|@85WXZAsKE)hIM3EM}~D|Sf>Z;^hj_6J@j9~LOoch2MhIJp&l&MgN1sq zP#+fR!wvOeoj&^AV4Xg!(}#8XhHwLYSf~#RDX@?N3n{RW0t+dykOB)Su#f^bq`*1~ ztTTXh2C&Wm)*0x*4GdtR0W36tg$A(D02Ug+LPJ<+2n!8ip&{JR5Y`#OIzw1z2>XVVyCoGlq4>u+A9P!C(UT0}G8| zp)o8phJ_>|tRxX(DTxScNkmvoBEo7C5pGK&!g3N3){}^E0f~rS(TgAypd<`O7?Ln7 zk?5puh=})GFK#|x zoG{-OAGB%nYJxMmmSBypCYU=|;7J54f`x?@!O{Vok%jmffI|!ab(`032t*f(6U^7q zJpJYelCY~$@jTxWua$LL#0^0zZpTlvN4kVr?u8`?n}F1_3K6cPuBrrrAY7%DCIkdw z&=FC0`CTZT6r#%zR;AD~IFBGDl6ZK_QRGT9m~@0gEJUKi5QOcXhhC1b ziFv{BTnzUMfMp^GN68I6TZph|bOb399$_jzcRuO_^#P>Mu*MvMK5ftsI2f}s7;vDt zz-#OS9Ogd~@rI~z2Pb&o23%ncXNQBD5$G8HK#PfljYd2Rw<|=#aYWe1a7PI&V9z^% zunLP2hJ`fpKuk{(5sO5c2%|)hc#HT|g~)E)h~4}lFhGCyL4aiV@BYy}|N8*4;RPW| zMuR{|rtkwHgn9cwhy{Fy03nE>zX72k5FuX>W*qU8ER3%}+Tx0IFFrQFXx0wscX&0RTg~#9kniG`orrgn%9TrW8h`Ltibj4g+S~0LM8zGP8x$=pAjYF)@90!1aNbeivo#{5qvcM z2f`U)D$F0$16-_rP#gS9zJ0vf3v0fR<|8>_Q2W1k=)Dv?a(&}|>V;S6r(kuUfAx7K z0EliB(gwppS|7B60Q$8a-7$vIu@T5u8WD-E2i9g~41^wwKJXp(nyb0?epVqzFH4b4 z=cutjBv3)Vs$u8qM~%Sqhu;AAiy!>ZE%rb7!f$|U(tkbp>x1E^kB8t?AM;~jDgYb_ zy*D4|fjR}~ftDVIPW1$7ogAb?&J9xl*xvd5VG}+G0V%5^?Y(C^WRM6{EFdffU9hr1 z@&2czBMqQ6>}UIig4I85y8kAdK$-KxiUN=_=!X{i61}NFb%WZaePhT!ghJ z47#454yE8hTlBFJyh3j&P%D6w_&0KjqA!4pvSP#4hEk&(zyhM4N@vl;5)jTfBGM5G zC{r%Vpf|}h>CgqrbUi-q#sFAjQT-ud#VgYX>R^5J_WcjOu;vwc;KcK=5Rup46DYAT ze-F+M$3Xu}4j-!o;d(1`r6rJxRl@Lx;D(?Yejt{Y8$^Ty5QF`| z(vX1Vm5mUB;R9G68WspxjE4ULumXwrio7Hpsn`ibO8*lagWhqhW$ZiFDrrmB{c)m6 z53J`XoEli)JE&}0xCkQ6D3RcVFHI91Krj#~{QyLt`BEpZfd9i8?+e-V-iGfD zctsgRxp=Su?jigVH41pR3HF=RLx>WHBL0miF&M%b7oB5as;Di7MC_1AQR~22&KWCu z6aiw5P;z6^SV)8-!lH|CC0K>M@aLR~LYj6zNBzcPgl*)8go6{wb`PZkK17ww=nRng zP5L&GXSaP8sA^c#ekDe5KJ(i{!^7>&!-Ee9}e`rx>*sB2q(*mZq z27UiOB0IxHAut1bh#T~oazlIrUYRgZSYz3*At5+4J7K@DHstku*lB=F!+ywZ$m@Bz zY2f$AGUY>F&+9PqlZn8MaH~FU?7OL8#g0aChL0{%1O;)@S3Z~A5fzkDsm8TXH7%fr zl`v)2&{-LgT%00O!bETcR-qWec2mPxQ7f12rP7FSqTK1gj3wY6BlVmK;S1pnGoHXU zA#^BzH0$JqZWruiU_x&Y6%9Z_pTpG)Mt*Ea8HSC9V*|?2Y-Eg{?tk$8|9@vOph*1h ztg|9rKT&GQq>(%7Nk|7fYAL_(&?4DjI2RfdkAsPh*T5m764i)|Laa}q!W$G5 zJn;s|nOeij;UFeRo=P+kD>=uWjPXIDnGmEwm{Dr5eNibj76f6b^$d6;NoCW;SV*`S zg1||xB!p&J@QMLRD>@>js>X7MNDqYEq7i8%Jer9#n?4Xj)C5D2k5b{2vYJ80Lja%; z1ier-LPaHf&IA(0uT%QfKMoZh9F1$H#9^R5VC4|rk(_JGWg&sa_88Z)3FFOXD<>4 z^aCX0Cdl`|!q00~|5#o|n50^hW(9%TLAx)O9OcZ>2+e{pJy#tli)-u8Ar>gIy=jSvx(J=^7GWBS zbcS9)Gt6Ac%SeNtsCvQy1V^MZN5OIgqDQ?D=0X%2(oLtgfy*pOEbI~$np}rWuwE{Z z;|x%~5e!+Z+G$A0^3f6yEBqHXy%$3mVzAJ{#5{b?3s_WY4KL>fNv$c;T@;+RxMb;I zn)~NH7T>`U(VSeFauJiRm7!@1V}1oBJTb972tvRte0B(hq`fSKRg{95Mk$Ej4xt+2 zZ+56JP$s3fs5Q;B^Oi<%lg4Xsrq97q+4xXI0%7AhbV&W^_$Ng9C#*n3C6JP01PCM& zo+K-c2py8n0;5-$X!&!WP*}ompOB61-Dh7~R^UFdtnBcZ6quAve_O9;GzP^RSB7W? zPn=%}LsUUJxj+s55aotqVaYse8ukwM&oUFGF_N%k7j_ayic&+*6-OhHTmX*|O$dpp z_EM_YT_+e0!#GC6xwZpKEc*lDU@Q%$7f25pgI>byo?d4aQ(=6xIF@l8UV{ltxTZ(! zCUoeI)rR=8t|XlS;c8Y4BLEb(G{OMbFe4Ez6$O%jgDcS`Ia(lh@R=F&M^vXzyYxx{ zexmuG{l}D;6mK~BKZKN4x>+@~Vp7}=Drao{OBx~pN!bXT z8p{nSmIj-)_h3PcME%-jI)_MuAPSwM%nB&1kkJz?8u&PX1A-%%e>o(W__$MiGJ>cx z(65mC{UL$Q0LEp*I|Bl^>@Q7=D8*#ZOp^5hg`Aj6|0C-kQ>cR|V*tqdigSh#ro8?W z)Wh=dAeOW4Wx>8UC%i%L$|Fj#jP>vyq~L@#C*s9$848TLxH#$qIe}IxR_ZheE_`AM zz%j6&KQ<;%wqQFO-Zl}qvn<9$b9&TR(OvFpP`^n=$ zz^oibbAymNkl2TF>Wp}ux`D1Tmh>A+zF_v&p#KlwX|NUtq8cn;1QHb%a2cMc1i3C+ z8R;$5CZhD?==Bl=?868q-GS416g4!;{8j2qKuBSVkm3C-3nHYY`;Vp@ zNHM;oYj+`nlYw&QdbSy;I0)jRn=a{J1h3Il49kthfC7S#yCk^8M>xffwX&8Pf|F*T zxCi6@50{bHPdMl^U*h2>_<22S)EXGXr2>fu>;w;(RXdu*fN?35t_@#hiEwP=Q* z41%L-1A(~HAk?G|9UuZ#B1YqbC=kU* z4ABFkIQ4#sz8Z&6A1)2i+Csp-TO`8PmFO5VlWUrHpu$}uj1w`6qZrAaYwF9kx?F|a zFIilw$eEFX18c|RClg#+PlW6B0 zix6m18}o*_pc9Q}W2jaq_iOcDCqW<+K^xcKNMMSf+V%{ojQfwf@b2MF4c`7x6ba=p zLI~3nnp^q|pptrUK@sS2k)(3{)bJ7XCVd=IL9vJGFI_qkA&GYbc~l~7fv`Q?C5GTK zeqPeQ7{v;mhN3BG*yNF5{6eJ=o$3$&^hHWBn&9JRVS&=&Lwo`Qr5UF;OV-6dOcp!9 zx>jFjG@e=?rkG_CRg zVxS3bJe(N;4X?a6;2$&^obVG&g?|@Z7o6}r;!Z9=3vrQRTpNJR9ppE9gyD!_iK7uU z^c@?*Yp|jO+&%;nfoumeL~fZQ-cTUFL0d2HRtK0|&;r#@bNsa)v;_0qfFISN9Q$9H z4O*FYV+wK4Rgy!grR)+2CrcLTcTq$UCg%Qm3r$07HUMh)I0)e@NQVss9fQ^DMfSmU zjtmv_2_1o2i~B! z<*~l7I`iSfBm&FKGs0XTx>|D(}XCRk@NTaa?AWkM7=`!+(e?;eM2$pxy zJD-0s$c%?4k z4r3&&q&bw%UPfhIMim95SrB%wV2eaWAJ4%t>1{CON)pZJ7zamz-O{lUnnIg!8iG|V zmhJkJ4x!VY2fH)$@en5L6Iy)`z+3}9&4@7Z06;LTYhWl41Wy)6`BW$xixo?&bxHod zU;Yuw6q!=yR1DRC}23ncfdA}~9l0Y|rO_S6lH2=hc z9(WLaD1$=hESt)mpvY08(d!ujopn&hux~Wd>_Cs#4JIJ?Cn?k+sDzJ>9at8Ob+z^~ ztNq(%mYPbp8?l<3%;U~G_=DqY+Z40>*%0w0LJ=YfdiA(`pXUa3d;m3Cm4wF zH&0xr(38Q|{^@(bMz8WU0hd0ax32RhJ z*f+_jrHxKFz{Rm-CJ;E&cgRrL4rp0wZxw4lta@w7KqEy-61Wo4NeEjHaWSBUYt2Bpmtl^1|Q}9ys>8H&`8Fzk4G<*7mwL!^&EL?oC!q z4AP`^S}zC@l^H^xaOj*Am4Dzl=mi^JEX~OvihSck;~nU%P09&K6OjYmiB#~XrD2Q+6<`#NT0mGk z{Q!W4VXq~yj1|kY5cM5JAb!KxYx@Zg~|d&30PF#U5S*i z5H`8q4H1K&8hBty=tbbVPf|*IAg6v}p5PXu-sby3a^eqV*&A>lir$CzEA)nSY5Dxb zHW>ngVVnze_7i{8&dyGbsq&bs$fj}>yNp7) zip64(pN7IZ?<@rWHcTC1Eu-ocGoWdmb5;xqW3hF&fscEKh;VVldWcpj*h3=;or8~n zhyk>})4}7w(;HDfLl4femu^rwjhcZF{R9^Vyg0OOQxxX0(BMf?ERt(s!cdN)cPOor z7U5bL6bcL&!=Nr+MuF_hURs1vACK-9hbNzI9?Kp};V! zVdw;%e8-ngu7pyhrP<(1q8=xf52~WF0Lv1rVu6V_n5V|OkpYqo8y`5NWWz>`3}Rb8 z^@V7TpkK@M)uRfuaT;jJ8j^{DBLA_7Ed`;T4&5Pa(rP&U8-=rh}dim+ISsAN$Z z5*-b3$)@MwNU0i}d?cF7l@RRJ4xH)BC)m?R%|i$&KFz-{I*o^Nz*p~gi~Bvt-kb9H z@4cSmux_zH&oK*1K)^~4P@yxU#n=G|gGC3)9nD~HrCB9hpeQ0h2wu|=v1nKc;+)Z? zjdWQGq4156Kt7H<#ilXnFi7KJXh2~Jar`JGIgBf!=yZZpy-#GeKWlT$xLjd*YGk^;7G5m zLqckampf$0%JUF0$tW<-#IUdxdyX1x1Uu>r(L8G*OpstemQ`Cwt;=W~(nQ{al)zH7 z;06r3{sXKvXc=G=81%4+9VE_~I42?M5YQM}iTCY!C- zSBZfa0^bMx?!Iv%f)D~@7XQX>HWn1wfZ2YPqd;kQjoTNxlg=tG0TP4eK@J+DMvr1` zTJH;>wNN2lW$X=C#tf{lzJn=@Mj^3-JzcFg)C~*zZ2*WGadB$B=OL%S`X^M>cO7RV zTvC6T{y`^kWT9Y>gc16Jv20mTq z{JJ{-!vMh)G04&Cjfn_H<6gTYK>R^#83zIY5H@pzM}S*!0)0M@@wCjC>J=2n=W^=CS1< z&(F*5;2lHVJg|G8o7`7K&!dqsHyJAEhcV;?yUAIiRG9c;6qQ;C`UV|00`3+Q)DM>m zqt+gYKIZg};0%Y^n}7`h$mdAVISeQ*Ll8g;0hAWJV$zW!NFWWksBKUf@5Yr>gRLR`2WTA-djxhs zVUv4W7;;D{6}ld&{bzynhTt|niUkDr;0=ST54K6~hWnzU7=^*-Jc!1McA+a^7(@#$ z+HIT}fym-JOz9l94_eFw+v9{W%R6w=73YX<$=cwMR}hhePx6Fq?7{9R%e3Tx1cSz{Q z0u#%`4yI0C4G)|BuMi0Ixy(L3#yE-2Hj~jPgz{Yk zVqNi76t-J0MmfeHkD<;2y2sJp94V+}mBbB&Pu{pI4B6(PQ3!$fK!;8z@tfFYdj*>0Ie77-FaURNiQKA@X8*n zUT}Cq7E~{Yf80eG$M(@vL-)XY)FW(-QkcaeQIBwF;Pni#H9iqw2>tQd8f3A1x7L@= z7PvJmpFRB61m?3d!c6Vscf&AXR+#z;gyGIIgMv?-+5rSP=w7Ec3TxVSgBi;lB^dt~ zB@qo_JYl+E{m5s)2F!iuw?jzq^^t9FWr4sQVyV92cPKE`myw=lsH;K^1K9(;!{CjF znb2ADb{C?ECf$p^!*-#+5))tdtM4_p5$%_2x~o;+cxM=zGdcNN{jJUbi|yY|^a(h!nC zU|4Y%jt-+^!1ZoMx~4;7D|Fu;7)|BQ_?!n3Fqb0<{Vv*!tcd9rMW3>~r{5agJE zfe1~2png`Lq)dn@VbF(+UGf|M0o*W{@?nb*9PiTwy{Tw{k^&pVJ-nn8G>3a?IZ!{) z!@#3Mn-2MDIuw>cQilyTsNk3zX7~@n8J`XPKW1g99}lO)4x3hT(8x;o5K;Q!#)zO! zME`@YaKlEp41x$BO9uKKF?j~}z%oK04Nwz^U%w;zOBH|NLkaq&ij1(puF-CK1c>>e zRvLDIcI!V%_uV;`Y~)#wX3tB|4+Tp)tUPDX)?lj4VCuyNLiDM*UU0!1^ugl=VI?psggQQX!l_(J$OTuby2^@icu^uCNSNRl z1?(BThj5WfDnZ(@>etr@$=_+)0|%<-lu6>SPzhIB$Z$!^ZL$|$BMncXSm z*|SxB?%Z#m_q(@@RQLPpYKCnxvo}P#RktMT`+I+%_j#}1L}Ss-AQ@HiV}`RR4@C;- zL(mMzHcFgPB-+hkS{Zlg8RaQ==QAoxx%=K}A7;lM-WpB#f77F08-(CahhXY&-5R>- ztwuy~x(30Cih7-A%I}RZc_xqh5QXb%FV^7+NJ}W0=9_F?k&2v;J`Tyy9zXlaDt$mO zx}&deZ5a1PHS^K*25qPm2`J`!r=$X2#?PfN4iS^dY}Mp=sQEw(W=K%M&r@&a3|YZL z*$na2+dOu@EUrH`(8o$Q9n8FVoTV4~;s~|+fW$&gHqR}Y^Mh0hLR`RMp*f0wd+Rx5 z`LP*hP3w%Sxrk^N@tMq;G#;@pDhUPTB4{!tI!Kh?UC#|8b6;^$hy!L97__mRWuYv; z>pK&}F^X)p=3r*0mO9ecdPZYasDX$8;ZG*=5PSyn;;27XVF1?p$=Fs%&v)*-UoIU* zv>{^i)g&tUSA^b8B6+_7newYCu}2Kj>!{ zL2H-U)lozNa5me5V<4#ICkrj_=vf(isc7UGduP!oThWHG-<^396`kbOt%MZ=&Uvol zL23UU6dDA5yQ>rHO*Hq2NNg-;SMMFV*HvuW3u5{hccGFa6AdjXO!T?w@kqyby}@4a z9*vf6T7F<_w(W=?bv&5}(ki8&@|k2b0>#C53M^2@;ON&&+2jXKRN`xr6*zHtym;MP`Egm0w0eK639^= z{^V%1f+;|dtZ)RN+Q|D0d5@1`_kv@Arj@XA9K$~$iN}Y!>Xy8TV=Zvux6k<26&a5} z1B#MLyh_YG=R7r&Pm~G7=yfKQR+JhK-RBP0u#t?X8X4+Aqs|vjP2J36)2u3%!Tv4N zeFvf8(Jc_+nSrWcdKe@sfEJu=uen%6Wr#RoX6;`q16b_93v`aaH6V2g%#Ug1(vMgU zKi;=Va_$_=!^)L92Rro0m-0)F;_}py;fpu3Odl9#P{Cp>QeZytOpW;&gTv>`0ovV% z*vJZP2t6tNy~Xmx4x}rb6Q%f}7vy3Ec`ll?8{`^L0kG;;TG&~Cm!V`2sOKl1pp;hS zC^#=LPjTKc?KB|nup?1IUE9ki&+Wr51hO4nj97Mc8#7jIyVCZd9JC^!iI&4+DzBs@Zcc^S6va>~%`&~j77JF2R z;_p16fX+Y*;CW?VBm%er2K%|>Snl{}=6Tn?kI;-k&H8|t8|Lvhk1})j zZS2MVVRWp4z2%P$^|NCGn3v>|SBs2NkRTPE7-af!V%Cu}ZGmn~XId~y4!Us`Gg8pa z&sy$0@S~3H?;Evsph$n{fOgfjeOU}=1|53P(iIj)!k{3sq5}_$st#yT6&d7A8w?Rd z8ol^ZhVFU;HJi2;5zrzg8BuZ(h?M+}x2#U-@?LLpacnUDv)=buIoJ{!*^_6GI z`@|JpUZYXm0Jf)VdvAAw>OcXEKBSP?VCTFExM*eI_dTE*H9pMA?>!Cv9~G0eBHkDf zp%or@+TQE(uoY9kNXO6h%RGE;seT#Sc5&v;=XA3*Pkd|3ZEBgmT%jQ`s!hU`e&Gsg^0WS4nEjOq*#&_4 zZb(LPrvUHUO#~uin@9XmM#eUN{+(yk>Bl!5c<|&Z-M6U*@Tx-!!A?0OZu$cctY2Kb zB`|mg$|LO9(d3R*K<})_E{0pRobP933zU&x{GT5Aaio0IE(<_Nn4D@}XH@ z2z3Qt4V49DcqhG(C9APvH^f%C)bIY46jw%MQMO^vasjN8VAEs}`TRi<_s?uZ1n;42 z{=B$YpBMvee**ry_L+xY357_?-IVbbMT|{8G*jIGhy)#6;AWYK|0(v%vb$zauK51l zm28+X-?!A6MNNA2udp!E@KI1e`x8LWyl{|fc#kG)lqO7uA1=IaA0`1M);oIo(%yrw zF_v5C(!^u4zx(^oX!7VdL7r@jD9U$$%Fl1DqLn!0Ib%_44xTt%>llBOB@S2oEymaE z-s5@s(XIB;eEJR@qDT&~+DVpc0Zd5mIyQjr$ET=GrBtg0IR(XBttQNqQlQmZO%r;` z4R(P}<3WP;j>YwIVbcbg|0*RqdSv)tnQi)aD6$`&!2VwA`bnxnL;%A}*@Wo6Ezl$MpDdGSK# zYkR|JzpMU_tZeAQ_)m&r$}KrYoWh1ms0QL1cdouhBH8&yoTr2^}8T#2gm`c_2}V7R92o^4vwFhwrby5(AuzcJNYL7Ez_(aIDYNoW-j%^f(7C6BZK@FJeHk* zwklUyvg-{tQ~S6&JC%%|n^|;Jg_kdb_)iZ@O?HjHgQvNY#%F=NRu>Qw#K z))lucpzdJWT(jcZoLsxBE&HX$Go77^)!wHy@as0-H0 zAfe;m-&CU1k8Nf3-`;!=U~C6hELvp{CGI4;FAcKn9j;%6(d!GNH!o-fy%v?N<-o7I zTe0|>uAs#$&;-*>i(roZy);-s@W;Z@i#lkm!C8T|Zw}uw`%Q8{dSW{T-0;V9r&Az< zJ+p@K$}ZI!UEw!f!(*5OsGho#Z8u;z!x^GNs8swA99UTc72+){9I6QY$)ml{6|mfR zJO-|vsTpjeL_h|fouf&!R@U=n{KPXJ=KC<&%98#~8+vNPnLbyiW=6%`HQ`i@dEIJS z!>Na6Fk=?y|E7%G1bFXR4gb4aL1PRpdaJjQC0y=CJ)-$^FH`D&Sfpo4P{bA`a`e{o ztTK;JSw1c=IudPo6Tt7729cq|8ph(6z^(qqi$~dtoaYm$jY%(g1?2AO2yf%cHJ=Vs z2(BHk(2Bk>=iAb8p-0KNn&k?D8}kKbkHCs0BY-oQk*#ily?MGv)PRkHy&VTCvtrF= z9;LM+#1xH^f^95&|AFw;_#gnP#N1rOtP_z}iN!R*SolJ6A_q9KvhkS^RmbtkAgT=$ z@v5`Tv!Wgx-dHRoa@)DX4$am7PW7~J_ZFW2c4z8=$C~YDA>* zGoP2ce%u8wSWH2^c95#S%(3Ezlt1Tg5!kRnT1w}}zd?zRM(VCWt70VBuK$SEo)noe z?pKM>7Ni04h$%4u*hCUs)IvWC1$+4gv>N?jgfuprNaA$J;Mj9=CMEECz&mQS`USb; zFCO2DI;rhQLZO`->n9tH#8Cbk!aynPL^1J9^2GE~gqvz!c#lV<@}HST-?x!pj>^3f z5#^WIMn`JTT+)1%pKSY@Rep}!S61ama%ffZnS)a*8Y7+tyCRy7^ixwJmSx6YBo3lv zRX_2e?hB_Q7-gobAAmE{T$KwUA;Fh@i6MlbR;@#71%+j!G{b6+qm(JvI~IaCzNa?7 zPWkVdtBi`n>6g-zf?2r{k-UBYGUJg@_@vpN=Ek3@Qkr9k18;Qla%n!%_(y^Pyy_BOoIQO-t=k!s;{A-9jX zyqqgxgGfvj3Zo#RIAjt*Tk>EJBrNS$frLf02NKp%7_FCi%wvOz&2I%Y;GtF2#?wMZ zaPBhgiJZ!&ffqoK5p~iTux222ai$sW4_b(k6O`TH1;Gv8)%|7;fMvSRxwcoBGmzk^ zVvh>Vgs8c`9KRSJ9^hegVh@6_i{nRIv|QV!oyiupi0{BV4bGjifIx)7cE*&M3fQzI z`IHIdH_w4MPnj$S((tp*OO1|;7`g2-8cx61y!hI&&sB_OCd<9ldatXW4ZDi%e0$Mc z5PRFUF}OQu4%70JrFMo1vv(9>QZM( zW&NA#f)%6kI1|St&fNeaq9;gq7@p?TaPV;v6O8kEH#ts?l-CUqHfEvN#{ zu2cyU0e{iB#UJm&T^S}T6DDlL{wR><6i?8R3muw7ij=&{>|v{7r-xm>dl4AQ}JXr%LCrDZ0rr7ZdE$O`PuqSum{uhmU8 ztLA4$w&T05B4CWR)ZnZ-H`4eW-PcR1FV&o`KG*iy|WCEq29+mW%UsjeQ?(WASCZwus^^qqc$EO zH9rlJFEI_3>^F3vfhCCC^1VktK2*)VgP0h9WPSlr#wvO6TR>VUBA^Q z%7L-%XR6Jv2ks@8vDmO{+_cK>s-6Y3&b$XT!WQn@K9ycpt=2M~@Fjj!aw2g^R(}}e z{J{kSot0FAh%;x2zCze_KecoJ)BC!+zD{@aV?mB`D)`xlfy_vkkpGh=quIKM2F@T>Xv5w3(KAc$&>N>O-9DnpbtgCG<_?;YNVY*! z<+Ld)@}YIEIqh*QGqmogIAx)Abm2B?4?hV9aeD0)!*k~A8W=))(=7f2*N2&dEgE72 zwTFL&j+Nz^?!;f>8B*!!5r=<3!NwL<3<7qI_r|r-YL*(;2Fuu@YLMjBzoJ}Kip+xD zf)KTpN7@Kk7jqhBx0T2Hws_t@d0Tnv=P@4*&*P}(-^>H5me((EVL27Hv$&HnVc(fh zXTElaZ`qcYG>D7T}TGQ;09?oyvG7bNtK+z( zVVsxmjVSJj_c$OS?#Mqke5nk9moxkJXjhqUyQ)WBhun>mneh3W&KbQG%oo$B18=r# z$ne~~9K>b+SY)(zQ$WN31=lV_fj%j(YWdm9NT8 zAztl2S5=94+h~{PSKB)7QcLE#v!4Tfo^yItSNVm~3pnkI!P~}D+Qjp*SSj}s!xiSC z#vkY3zeqvKgulg4uu9C6QPT_1ejMt$epOkKg}29OBshn{2!?dvJcQxw$jCw%4X+#s z4i6Z&EV-oPv?dY=SW&Q7!*~s)yc`84=8|XPQ7*t{Mj`X3Jbn^;SrrgcM70bhv=qU* zGM0*0^%lvr@ii=1cCi6_c8 z9E6%Js-fsnfAoN{ML~Cl_MgXOop^#Go=HJS8p13eiL)x1q-l!lD{*Xi>DUm6K|f-H zz&4lzGwNC~AobIujPM&SZ@E6!=o^Ku=8FwF`fB-R=0S$S<+P)4kqyqPs=SjXF*r>p z&C%eLIcW_qje0ZpKYV4BdC_w+j${i2vNFV6H5eJs7QTA`>|M2ecps-XJyb@79~-yw z6ml}4rjbuA0$t%*-@@SvVpBIzHKTB9@675Ay<4$+8%NVS(=8f`@wRC&L-^(;D-2c% zk~A>8St=ESY94uKBZ?CeVBUJFh#4&+m=x8n-#FL?^1`0jz|TMTC8|JJZ*vr+qL@1h&Z0OV)55320}6KPVAdST3C(;dkBbSI zBxi>d5F&GMlzGIsU{AvZD)bpqmJSrMS-Z^P$UK>bFM@{jKqRBNiX$Lvy)>ixY>kJi zhEOt-?I|&qE1911kG9;FYc4qxDakgLW!n!`HO3Ew*L#(kf{^tA~!(tb0Z8P zh)5SjxFwr~B7?e^4vC|1lQ|?SJI@{4HgNbo9w0Eh+zdmd5iZOXt`v+AOJ%WatAhI> zf@;cDlpvKdy9k5#2Pis2pb{u_TIaNXuy7*g?-0(hh`|ttt8n*`uik9g!THucba;in zI&bach1eWNVe;v}Vr~ubO^=-CgF05&CPL7P2?ZIzPfBV9A_+(G0^5R#`yX+iQ=nn)FoHl<6|O&A@_a%PH#9YfQ_we?*UHJP zoTF4yu9i2?T-dVea;egy&g_9DcdNpEG*CO$Ew5|Q5QL^};EN@yV!4(cW65O(#;$nO zbEYMXxDBw`+=Wy1x(#*fKck}b;WEH2eD6fKNS*$imUDUK+Ls&abLS%f=H0^iz)Iuf zz@Wmhw<4}&|Ke@igz$)~ql%CPTpM01QcfV`^s{Sv^eV_3>lVVC)6xkJF9*P_b1XlS z0pRA*B>MLXs@=V;{wQb=q-7F3#aXZjf*R->D|~a!d>h&2&)jz|%lDRuO>nk)wqn*r zl&gSFFo=Lk;qF8kF=9--M$+1x2)p6PN;YSUV?#7#>k^{5vF-RJ*!K7I__=49Eh)bQcZpMnhoN}|Gf;XN(P0IOBR zBs1*Ho&nCMR#taBHgFoj#K&UjGbOz4^vA6CGk^=FscIJp0>)OkZm(9^5+)BOi}(ix zX>*(nIOYXSo_P6@sD{++@&xuY2Y9p8OCJmCzF27m027mF5pGlg0tHvDB90(hHPs_C z#T+hBzEIQ(LTYeh6?9Y3&@dAv*`X4>RZUGAb*g-gNx;rsW2!nXT;m%%aDSP;WHdA7 z(g-ne2GIu450a&c(ZGn;$gt;Q#c=6LYxIAr$i#F3EQTqXG^)WrUOkv?`+3WDsqZ5q zEEKFdEV3Je8MyPqnXgq%Ro|`Ojsi8(! zn2A*io4MtFL#4^EuHt|xZe|p&y1if;sy82Xv+!?H`-Gxy^RQ23@VA#n66)m2l3K8A zmDZ?+5@Cbb$XIa|UvOm-E>lmSHWnN zp*^%55O^VgOynUl95^et&VuAhIgdUlLC7?`(xaryFDUxz9`3Bdwi+7pQu#Yk#o?N5 zYNae6mfp|Z8k_dZ!2yV)7M|_EpEy&5Fr4O~|d8N6v zt^!0jb?BSV!s2t1{ zrLb`N6X^pQ008A>^yz*u!oXq6CyenF^s~{bc6vrv+4D-N2famb8P$`^Sm&71rqia+*)Yy9YGnXL`zA3S=e%y)3b~ zf~B(RQ1Q$Y@+^hNMx+uE<;!aYt4dvF_V6Ng=h7`{k@`e`pLX6Cs4uBM%~I3B7>l5x zIjYqlC!q`Y7aoD3<+m;XLVzXW|41jIHEO#yeM@;JoEk4Pwl&IQy&}>~5l20u*?HI1 z!qUP^6PFirHZbQ{uZ#_B#X{Ebaw*t>k_Q=8+=DYag&Go~l61(ttVU(~Gdrwry++ z=mS;m4LuFLt5_;h(^JAGGthN@$rW?nYNS;;He6`E72i7oIxoz6g#=0)`MZ zVMO+(pP}>wHnFjB3&KBAG#N*N&K02nW0R!%uUid}IY*-mPULTXi{iUr@xpDd4@Kp`b#DJ9Sq5lYA%?uAj$HWZ`5^e=wKn?5$9sLwA3vzfa_OY}2uW(;eWZJZ?X#$@+@U?Y>m z$xWmEnef1uTpOxSoQX}Re)Um>vBdQQd@im{e}HeEdla@9M?JNFn4L@isG~@xT*MeE zFy@e21#=3Y1KiN2<=klkr4M>v07M*}_n@o{?3HJh8cX6OMtwXD%jNv*xA5F?!Tx3a zId6ETk|ldi;K@ww6|Tcj`yz$5gW$DLD+LfKv#&L5Rrsh-(3a6^Ws+?tlN+sYQ5{aE z)My=FjFSl_?2iwAl4~A-dTBV+HCom4?8Q$?UN{%;WJSDf5m%|S{su7xvNlXP!;wr_ zK-*||{f%=jOtbb-uz@{qlF)$RIO~_puA}JzXqaxO${BS~I4@;L zQt93>e&OZpCgr4;tpenz6}^c{6}VC_`2T&+ZR)YFG7sz_Eb0bdc)CTChZRvjG@tW^ z1%xg%_o#(Tkq?ZV^8Exg(K zbp7%CWX$>=$GyG;h5#61ip+^1bR$4vU?=BS*vhTTR+v*TIIpmjf??tmm8)}h34|yW z8jy>B8f84i*cO5vn3ynS#RY$hTsqR7|Do{aCim#xh7fHqViP}({ z8mDohK-)8PwWR6GRfVfKJ)^|umP%6kNl9tTxTg%Ook8ghaR?6w~<{8w)mW0KMi|%Ma>^xduf>4kwRT>horV`1hKypH^n39tV7z^x$;o1yTp0IXaHfc@} z8T{VRi?Qss@pAn#HfVyn4`*PUnt=0kBHNqQDEmW~@kPW0y3AcmXs2?#Rr}oK*7|o2 z^uxQ_Sl>~CIZNF7Y?q)2U;U*Y^F89v1$UqMUdmF9mQ-= zV!R^9p$;f8xDk^=+c<1UbjpONr6JMK(3=avOcb%5ZPYcK+5TM_w33z&&mQ>*KwA_J z4}`yYPHc`+fo| zPQIzP8&k0tBW&e`YRFL-H{fF^VvL7GysL1*1RE1Z>l|B-3s8*MCP2A4?kqs%M(gXh z!I-Pd1}MauJYs@Yxxgm6lcdlEd3g{0787qo%-Rz?D`^0-l(Cwz3v>IYySykAcX` ztuPcwXF>5Y<*wEb?DR_mJ0TG@D*VC10b>IqnG@u}Z_{bCN-%74h6i?>8R2Dtordwz zbZ^XE4T(94>?2@WVd(pI4Qou+3oZn)aB=q^9sj&YRjH}>MqwC46}eR-WJt9O)IZU> zA`swZ84%lTsKpk=aWqscZdgAy$wrrEV!xltQ#K{fi~=&uyeG?w2^oP^Be3AGqySx- zOKKJNnk#ExQeN2Wh_VgJN{S}V>>{+>dr`G~$WYSothn1BRcIkCWr4f6hA(Lp)esgB z=qxNh+Pa`icC5&{3TzxyjTCNQC`2r+DUxtQ|C3q)T%bBz0WyKwa5`LNJk%LeFc|j! zXqA2 ziNl9+!e}9{@Ow9bABucM-5>vfdKDi_Fn{F+S&l!%Bi;o$eo-f5bp67=wX+gabnft; z?cnj4u;aOtg@mQC-VhGHEhY*{Pd)q?Ys}7+7Eu5qPE$eL2}(U+$q8NPex#*@K1*23&T7I6mG%FrU9E4;KdO4DBS zaw}&iD&;1lh=vbBu5eT#-rW%SYNYG295f!BD~wgZ#mZ}?oLkMWl?0?4PB$KDJ<<1{ zXjB*etwo?0bnDa_0Tv0kJbGwZb%sYZ)JA`}yY%~w#N|TMuvpHSFvk@=>ih@NL zIzpHx_}2myNWs6?+tlHe1Iqv} z9MR~LEeNH#kxRjf!+E7RAucd$ad^VWFy9h*C##~|k+VyA6O({^r{bRstwB(&c!acWVo%5t|n7x|`|nZ!CzmZQjl zU!}??gq35N(;8>WruzynQQ(_b*4Os~Q$pZ1h;#u+Hm`mlTdeETpGCJa#d=TwMy8MG zFTT6@ODOxC4ge7=Bg?yt7v_u(mb*!&Zjk?GmS%|tI z)eL4kWAzI%G4}`EC?VR=`VR_2zrxhf#4a|3?FOI>F8EpTL)F>dK5Z(VEzW)t;?l7| zy})|4A1x|5;bxSDg~AKkHa07Yx7=~&s+2;Z#&2Grrk-=72x>!>nr#~grH2=8JqR0z z8AgR%Xk*1p&Bf${jWM+G>tmB;)PxAFJ1L2g2{-(kM!hARy=QrKwsW$KE$_H8{mpD! z3@0>;BF%FMNe*QXp7@29K{=MErd>N1DJvp_?XISXbNL4EnxCvtFge?A1Nk~?sv(D$ zMlYh34i?^cfSp5J4@sR&c*L(IcZAa*P)J8$lOb4=VKXSkrwkYTw#Yq|6j$C=#zGZ| zNp!(HBz1p8bceI}x~;$uZ3ZzxPKeuP1$#_j&E2?Z9BcO}(@WjQs0(5_gm5R$8{kTy z;-*X=_i8blx{7xxM`CPE#dLr27|ZIlJ|+7Nc)qZ0I(BKWY9erb69hht4>DK9$Vy)< zxy~y$Yy~WXqB>1;DtJYVWyQ#NT6iGanWsf+#FzzM*`AUR;7qVf6X^JgbYBMi-FQXt zpUeR*KBS`(50V!f>|LKqb8}C%ex|34P?&1@Ac(*(R2V(gLxV=gGI{V#z&a=&{G8IS ze<~r|U(-0V^vI}j>*nR1AvRg6=(l_%-9J)+bP#fpgVz+X6WvinqO-dk94R+_3TmoVe1J=hmEa4nqRLXc!->Haga7 z<|x=_eCsYQjQEX*_M%S@-UGp=+4YNRR(lrW9YpTpKTvSv0a^o_0d6Zydn6g8M%}6PYn`oy6x2;}f0DP%Ct-F@Q|_3@mk`6@yw}nMV&+X?T~~8BkIC zWWuBf)^Dlp-GQVD@+6x5{Y5#jYhQ7w$xS^T`dBvp*=C#Mj% zc)m6Il~e1B#BN2zjk2Pi8)SwZ4yRyGnpd2EgRaD3#>OUZ4$TV`&lwE{C+7{!+}E36 zNAO6=_5NCJIPggG+`~>ifeY9B#%a9q#Xx`5Eb1Y%%8e?3QuJ)g_Clhw$Rcv!D0HJo zONMgpl~ZR~x(-0?%$phBm9&D+I$gjGKp-MpNFY(5UJ>!t{o7l?g}$fAObARUp+ABR zZ?1TL=S%EMbLTsj`$~8ISp4Qg@L1W~;s6sOUa42FOctF-Ub%&;+{s<8pq_y~9vid*iwV9_X^vEM443_7^ zsyvC|#I9)(NER`wMC_V^UYTpK?GV34v=%~z2eNt4%6|OyWzOFC@J!_u znklw)V(*X3rp`g1U{8qigIIyGK9RE*am#KD&ZQbZ7;UxR2VRyKhDUt8km&53HHU zaC|Zttu+b;;z*%300IdB1hggKcZNp+U8|f4EW}rQ?hMT#spUyg^AJgV6C^flfDK5X zLP?EGHpu%K~bBr}hvmj%?Jg|&rZ_cG}KD~GP(z2~3Tj#t@FXZ+Y zikb@t7lc1iIJg_Vfm$m!Jk$x5122OP5d03D5W0&1BScaaX9?Q?+J^Q9zvA?A&V|OA z{K~}2@SSfsB5a_SDRTGq>TGz>yra!}d9a8uwijju0qZE7CLmV8Q*3f6nu$GLqb!Jl ztR-OTdPnBlwK8DpR+c#S)vN|QJB#)#)3S$9{DoR~e;4zjJKL5rG^yEF8;ya3!<)Ml zio^K;k9HTx^8g|P{~WCM^P}KV@&Z`}7PiKIR?%>JTP)#5SM8DbBs$R|f`Vp`yUOKy zo2UBbo~)qX9&%kn)KpE@tk4}DHeLjbCpO80575Lo(gEOeGH$Bhop5Pb?~yMp;j1tD zk_(UQx%PevX$Hin(;8|6aijmCc3Vt8Qu&=yH)9{EFl1!x6(IqqY7pdGh1+7yIx6!t z_XV%_Bs?~?slo%>4DhDBc-ourY-R;$%DiC!U}s-fi-2XgC04ixgkTv68tY(~sV6Q~k&Cg7pR)|%csQi$Uo;wnf<4Q#+rmJH_2T`2-QbvS5M)jt(XW z6~yNJaE8_*)5DuHJI{{1Idl8#Ay$7=@>^=|&g5T#bup3I6q^160_8Pq5>vu2kBWdO zrmTJ`n|XZ;+GhOX%Q;uy8+!l0&~U&?!7idAL;&xe3>VJ|?;F`b85^m;U#>(%#Iu6p zMF<7hY358==D1v1a1ic1q=n2K3@<)moGGJ>Vk#F4i}sROhf?MlVTVa z_?={eNEq;ycGd>+mHyqSg{;2+4SnEJ^nGpe_L9wN=5(%Qt%fw&U?lI>ry~{26M6JG zq)!4y`^{=u8XYEJFH~*&ZO(@_r?Gyx!7oJE(ap8t@BHGoozGLjyQQu0;qHB|JVhQ*+zh_p|Ay65n(YDPp%VML9W=A~0AjDPozfaw!tz)t`={ z6u(j|MOI8Md6@PF`rI~0ySCIuPmfvyE&7e32Gq~}LJS9E{Uw+aEK=cV9D>zR6G~5d zrdohsX)mdYG2dJLwH>P5Iu$Y5f&$I9r3g4|Ie1q0TbYB$yWcv_h!i+H@vS~Bck>(h zOfJTWjFCAR$kwX{A?%qCN@pV56?R1IEbutWPI!&ma+Qb`pnRxnZodZH+ZM|`g-{5C^PwN!@MOE~#m{Vbka_+LO(R5qm=?XM*_l$0~2 z{*4K($Ud+mSA}GT_NgJeU0`OKQ{(7>$>mD?@H!pl1cr}#h2md)~mVph!pRLy$V_RXrv6G59#>tf}!Qh$E#^?A?X+r{!dZA->oJ zyF?H$2dt|wU@kclX29I>NXR;c-c>)k_@RwUqmLl{)dR)odJ8TIq8Tj*S}>|Kg+8J+ zAOQBgtqo(i$eff@{oG71(kHET3dKB(_5+Zwp7ud{j+vsL!3<@?GoCf_;14&X=T3yE zLo_J9*TUL1n=kNlB5%1upr?6sT#On4)8DC0h?7~89Z5|4b zt?wdDd43IAc|5b_HH0A?YF%w*_P~HVt{8uat*U% z(MN>O$`G*oyP6M+>{~(okDyWsDRr1gNRMHSc>xJwOz?k!oHyw?oE#<@JBQr6#Re-h z=mOxSw6Dw!)4oR`W(IyuP}n)wOoKPKdg&?;D&mhKE(FbkNKyVmD78;R_P(tCB>VkB zCO6Mfrdc@LAd0o@!-dOd8XMgAlSh-Un;`j=C$WH~_uZjnyR_^*z_-8@gtmdwY=?5wJaq;_JMglcXxP zDhFLtc*Dej+r$wsg_(zpmDj@jaHi}^_OV_yu2sOWEV$5(x4&X0r0=Wg-g#+f>ch;l zUNt_H=e?T!VRG*>Q|EG*){VTcN(C}6v@TFGD99+>6EMM%t2H-;)tH6zDd2tE4E&Qf z6AuYE9)kk@TxdqDmZci!tedFo$Mr5;ee^32-M6KZm5+Raa*_D8^O;{1n2g{Ip3;8Q z@vP@pxrLwTjV($lhLVxOE4@&!9?aDm>pj8K3vQ|s_WujPMY0`cL3777)EXYR3usZ& zrDj-$7)>erg-5p4}L>R3ofUYR`;M6PDhkz`Rr$Y;0g{@sKt+YV?^G$yoUYw+p>F=@DcF^T`oOdW45^ z=N^%upb8w5kLeAfY_M>m@#O#eX&!qIP%Xsz!voboW+B&9hS*>AAnfuOKph%t1R*i>Ge#3 z4JcY$a^|h!?4iYNnI~3){s&#?gXNJ&P+F+yEq*Nn{3jAXVAWUC8O#OfJ8HBDkqQu* zPNE!g1-+mBS|ZNMbRXFZ=>tfLWgFvKrXK>AP7eAHaaNF6De!Jcnf0f&{!(Dwj9VHj zFz3E-7RP8&Tjo7A+g{aL@kayqol02+^BrhYGoXMuDC=3&B;wB$C0VhZK-&<6!Hj9< z1P+kjB%=a&V%t@m-EAHf#WD;O*xeEzqk)Y-%mr_jT67?o=I5$KynL)W69&rlkQd+H&*+%dVUP_zz`ckSdxPVko-nSQib%xF2Ig~xkM-eSV}4E3aiX6 z>(_7?)VU@XCJZJNf!gvHq$Rf2oJ;CcHu**7mB57t^+O)hYpD!rO&T}Eoomu$4phbT z2ODaErU5?}O7B|$+-4xIL>*on<|4tl%k{qll_gD2wl{-v?N0V_XN+ZsiVTwE?_3K| z6eqyBp$d^XO-bk{@xDzu@DdSc!7VEhX{npi+#9~Zjy<~EV>u9D%uBGVWo#;;riPXD zk^A?xvTVx+1%XF}4M#wq5TG?B>lp$a)H^bg&L$}T!r=;o(E$?XW}x13EI8&9JUq7H za#8NgE+BO(-aPzez4LAVsSn~>6csD+en1-1(W-DdQVIa(TdmdEE+8>$?g2{#>Vvv8 zpqaDnp9~xBD!-O4tw9b8Ez3}0r10KlslJkON^t4DUFFjsM2by?z!scU_hH3HOa}rg z&Bo>41h>>am-gTva=|UuROU5{#IQ2einCEH$#^x4fB$JuY~;eeDhA|$f2GlJvX(#u zVC9XMuzv6?4pDPyv?7Dlh%m&j&1+^4&Io)n4b(8Orl=VMdWb;nM61CS6Ioi?O>WNIIkLfLN5hxfH_Z6H+CHED^B1@-R zMvW!DPy~gSt2`G|vGl_Fi9PTI*!S8#yf7BdH3PN?ahRneQ|oI9Uri6@T%~gRRm5>8 zVCldhA?LX#jT<@`96=)*+Orjz2Egtb*JuH_xqQHDd|VWhH-h9?L3o zXvZr%+4)nz_1!z@S<`djQLmiuklMkYS?i)C>uycrz zq^2?1E6vY0!QUv9Qvm@};~LPA!LT=nYhgF|0@DMV)HfSwI~H5Zpc@TiagT-;BTFj5 zTjd3;$Gk@37*+ntey=*$9C~zzv2h7V1{AzaACpCcngon^L9h!H3LqdBYicB!ab@0CDG_a5 zoNEHI8a5xlbd}$EVfj*}5+OCfTdnDbyhcqgROKM^R0DCov_@mYS$Q(LNl2u3ZHfY1 zr`(E-ijz(lNKVN438?K@WH_u49KDhZ}#ytwF`5CxB%17A@BuM zSk|1n6WV}+nH-d6@tQ=ec7g)})s^oyh#M~d$eI$!za}2ta?D#c$)v$6ZCLFjkMfvf z$bU6%uhC|{Ru{cZ82D}k%DpbJHx_q!4i4SMlK-yiAAw|>_Wu^!yAPZT%xKYQh`Hv|F}S>43vnO+ zQOO|cPQDHDa=EbMA%_CVjucNl- z4z-A-Dx#}fcWp!gODUPlCp1+Byl_EeW3T-V^JjtcMKTD%5d0F}xQUWsrafa*0P6_^ zJ`eETdKn6Q;y<=+g@g8DpUN`(%A;ut0$v7yVqf`>wFIa)dI1cF=EI%g$U+S*TjQ4H}gEs+zf=Rb8HaXI|PR-u2@P9k7I-EJO zG{W4PUM+VCIW(W?Y7@pU0bnpKNP1G`lq?59H7(iG#Cz0UIi0*k;@ zmd-*?7SelVOKmLkyeCzycMJ`oCM}LucZhYF!4Hz`Duy+ieyJY85KzbBO$B#`H=fp_ zK0bII@Ff(n72(fq;!9Sr$Uwx~7a4x9X%cY<*ph_;nGX+mUZPMUC+;X`GhYkV?7BT~ z3SqFbugv|!lq+Md8ei=4u%~)@LriK32{`D2IL3uzTSJl_ghHm16|&Jni4a={x>ATGs{|Hwe1ZO9#tu2SJ)L5)M-|S9lr0Tke+^EHv@NOu^V7 zb8PF1Ie-i^*VV$=a=_UdJg}`R*Kf|fx@0h00LO&-?Ykj5x{R&3$lPk2gcQ217ip&2 z#M5hqgR>tHzV+NaAdJD@I6!dkX64zyaBgb`4 z9-b0#e$D|aar)o98zyw(1XP(qVpN;^E@KQZWvFu!UbJGd?~HQ*PALy$@yZ)CpT?UMVo0;01Zv~1zj z06+ zn?&=*)rdHo{In2RvyLN=A%`KNQ9SQQLwSG<-~B9dt*0K}Qj4sMOCDSk(z^+(Bryr* z4zgy0A2R7|IG4l9X2aJRLmTHy{w=llon{H-Lcp4-B75nffmICkBYp&b83zoxAv!M@ zb*Yjr`S>Sn&;y{?5V~g|H#$&lRCouJ>`3P{&6Cuz7BReGP=C_xFur(fD{Js(j+U%) zZ9Q8DNL(DJU}$E~Lhxi}CfQk)2gMO521_+e5)Fc*E%ye#-mMZbSOsSU0({g*PASso zGy@f&4OFcUFn07S72oZPF}WGXAp!-*1W84~yx^1OzOYaQ(tW{E1X(rKvN}P4`A0F~B97i9zP}6Z_eb#*tqxnQpo{eW-nry5jpBZF>~L;Ali~pYpt+ z|6$pO{q;XIBNVEcURhPf(!;F&@Xlw8hzt>G#vXh@$^>f3oD1BLl;s{U-nXeB4k&TP zm&yPo=<^!7qWj_{SG=uQ=N42Cld47#V#o`^CtL`_!re;`g6fRv2SQhhthB(76R20- zThesWd1Z>+Ty3E+va`9`B8?(XxZK#+$x~JD|61=q0CC{!K%J%r(oat9chj)0Qh$-R zR6Vp%OQVKFWiCpURmCvwM(|^vCvKk9X|STXLkqq~KQ$Tg-=hBEoJw`)Ddx+Ao4dZz9#|Xq(B%tmP31U@{6_u7IFJ=#8w4 zX;~IV<1-EGL17dSav}yuu}=OH;tVgz$%vB!LOsOHmk}~FqYAzdu+^x;Vig&+y`&<5 z!&fMw%=m*DcPXCYGi_%_M^hSq_}N#OKJ??cT(NYk^o606?L^P%31eR$enyB;kktjPr?dua`BE81HY}^O+JQ*|szIUGSNl z+2vVs3Bu>@nnw@%X4(Qs{*`!q7+5Azic^hq3|*e}pY>q^`cdIPxX^?fSh4fV5t(Q& z0Rd1=8$O=x>WuehBB+^|dZ!BAt=Q#Zm)jqn_P19)UTlKw(oE!0@v{Kw4CBrMIC4=f zIJ6w!I1foJvxi^l1^6%L{RD(ap4AvXBoL4Q5Y*)n+V_NbDc$9vDgYJH8GoXJT|F1A z@`vR{Kd-GV*aJYn6mEQAL?9SY&WbT|2?5j^2@1S#Q%C4sHm?R|vUL4Kb}37&DrnHc|cA{B$(;v3Tc`i)g(;p6mRw8&)G!%YE5$K>!jBl{aI~ovmN);b_0&lVUd!f`VowYXFQVyZ~|0qhj{}FK?w~P!)RaOfSOt> z6T`2eT`>LGdjExIOZJ-*R+(A$k6^bL`K6kEHq$s$yI+s&H`>4bY|GaU_A4{@ynXVs zhjxHWVU<3zXd9a)zmx0K%(I@Kff0p$r=(S#ZoZf+>tOf(%#_~AyRS%HY95=MyIV!| zzQ8UKirUmqCSb=*`w5z#au~I9+D}GM>8~8xHd+tP^HL>I|J_=6(UbA%^iO8?xZ1Jw z!_hC4gn=xG+#A`&j;QgGCx6ZG;Y_<8tlfApin4?iy}$9MN4~jlPge^bV8xLmWVe^It+O^AvgtlDxb zP7wezBIa38re_va`yELirICs^5AVF1nf?F~bD9B-dp#WYiRu>eZ>U_Fx)Xd_Cas~9 zE5s0{kVGCKV#rZSK|sMxB3}O@y1{NZ1O(6~C^tCu0hkmJ>{fJw*Ye_lZJ+Vzgfml< zG&(Vn>efsdOIynls<=bvX!9j_RQdkGUcnemnVe2!RjEwjDroLb5%o1$1BDI?!fdE) zVYfJ;3q7z6lM{2dIQAou6LW9RtVNI?19M-dahAGi^(gEJ#eqNsxpW|=0Vx%zF@6lS zrJp$7&(6{b!Kk5#cpX?P%HsK1q1hoIoLs7i_;}{zQcTmfh;bxhw}C%llS>fJu!_Ko zh~1Jmk7%QSj$`}N8k!{0ia|6ldPg=8ujY!M*Fn)22v2f_=QFx#kj-q|^*FV8!F2&`-6|AKvCUUz*HTRyw{ z&q@^NoJ2-LaWmpruy_1${g92uKZpbp57fy5|KJ(Y_p52--)M)Reo!^Ma?@GBj}rvG z$hNky?`+hc>-pjeEIgC?(>Wg`r~X88V=v7>a>;b%I~w#wBlHEn``7Mb91aEy|( zK_-O`qQ(1fdbH%fTIfCLJ&6ttODd07wWFa4Vt#sbCwu{17%&5uT_%yBJ6IL5tO~ga zW|9^kN`e)X&Q`GRl+KhQqgbqkQ8ULo&s81)sEERYfu#lo4fm~aLo$JTgo4orD8lXR z5e8%t?l=3?^iVbg=Gz+VYn8DkHmR_*R-~e#Sy1>MfcY3gaB=-=LKmDj&j%WqLEc*q$|=Q)(uiO3O`{W>dq+Nf6x?s1bQDsgHk*Os%^U#$0xFm=%rIH492g185Xs zUpJU$uyP=Ga6_BVO0(MZ5-+WBcDbdcHK)U{Pas>fSgB*f_yXe}rvIl`w%xo>6wi0IaHpip}NHbryxl%?H z4InH=K4WT`9#Z8C>tkM63<>`J^KO+beyF3gvx&_t`+LHgBP0UD6ESB~h3L`q7%UHb z;MwM;6L>Y_eFO0lsOvMDLG3F+y3Zvs?og6>nUpPoG$;_0{MsWR%RF`eRfS2dl4i~= zK6hFI$YK=kf3R|Zjfsly$>KD#r(F5a1KSx0&M#*Xl;td54k@7KQOVxGby;7o(03QU z>JKdV`9mF0Nw|d@R%Bd)q_80Ah9C!eo$yiN=2N92u%g$JHQ_9erCh*BG^G3o!|Z(Z z#|lfhJTtUdsK*TNZC z$eX?g&*NE$BEkN?UWD4%_9K;}^(WEKy-x#3V4FtW2C}|w@HhYip`MZ4!r~3U2NAlj zj`x@8jU&F?5`xJf;eo-ON^6MvEB<6lAKn)#7Y;O0AZ$p@%oPBdu^T+J-W3gG~y$JqA7A z4QBLSsCabHg3+BoC~NxgOsO_~+aKi;Ur>E1wyI&LLB>O{S!@wp;ER@>fUeHImMqNK zFxHv<+Ckn2Aitx@qokFC2*=qcF9NEbMwckhh4ap4!d0V!1Q8Oi9iO7knQ7cd7ll#C zCv~Zs1!b8*%t)aqKoK^Aq2{jVQBj!L+#nZKXRo8;(|J@Nu9Mg`u{%=qnSq&=W6&MkTZoFfjnt!1hagclW;)(QP@Fn5b())odkSN zOhyGQZ0^#Vq!4qr|ClV1n8|O;Fs*a%UJoNOUqvT z-xvJ!^L4jKA!W^?x-UV|5Y7mSh0McaRSn4x5BJIEad@Oo`J1a0KWoT5Zi@s6^m4lGhPUG3a8Wy zIL97klzI~>H9@R{8HzgAw(L#GF_F!JN-vRx58w^p1}4^kb~j#7rI#SHY<7lp%=gIy z(64M(Mtm1~>-QVCg7yA0H@%I{>nPTMx5HrO$K&Ad=U28Xs=#W8-42H4E?{cwwH0S_ zEdiEX$Fl2vz55oef+R$u2g6*m@ocFku??Ago4N`rX^pW&pZ9e z0fcDuHy;4uI!WDa!`SbRMzoykC5Z7^7kd6J`4HWb(f_X;ZG)g2z&bOvKtrFc)9`uI z9Uz({z~D{bn#iJ+yN03Pt+4dQ+be(~9(%1)ZvSzkWv&DaV9g69An$8A$IRi0eL-Z= zq+)T*Oh~PqiEqbpr7E;IG}r+ZU(Hf$PBsT;fIrA2^yufI=AQ$GUd>D|Q_;q-m~OLY z+UDl!OrOo%@Gy03z>H>LU6ef%V)m2f#|J_D6yNBas7$9D6EMKe`2a)8-`8sf*>Xz3HT+BVMu;=SSXhSu# zp2=-RL1C0ADUL%?$mTAo620ECxQU1dO~Ti^zN01^;16Pxq~42c#XNY<^dRm5TQSaZ z=ql}L31brlQ|AzXhWSrsqTx9+iVq-|&<%aSqB~F|g*ZN_`cxR0a+g_9FC~(nTrgPj z(~QINM5RFZo4rCDg}w2*Qn{zrc=M7cS<_}{d#%iAc_)@ z21>}~r=SQdC!; z$hlnE#^1NC%RaWpHF`erRal}%`@dFcBD~P$z(Y5Z`=0QuK&a|qOIv~skLqLq#H9$d2=B!uZpaCKA{Dr=$-PPZ*9x&z0hDSL{;k|FG}9ZF zVJJ&)aKq3!oE9u%80sevLDC^RSGykv9eKyJ{?{xuM0;FLJ=M&Kq~;m}L^EGF5==Tg zV^htUBA&y^L~4%khx1T#GR}jSe$*D5Y^h7_LPgYZ56hfFD=-AL+Hr6*DM~NmdmQYL zlteXZc5aAey7t`+vd$yn2+?b=e9g;V94-as4nINXF|MWK_*qhjIJ6#ryEb(e1fSEv zM3LpCA%|(5Yi=g zyh_oLrbOHoaR#m~(fjp{3QFIn!Rx3jL=b%@#4Z!ShpWS9X6nlp@5kf${H6GqSe-Q#kvyV;P-G+v|JXIqGJsqo*nvMc-|3Eo7Co^2!Dd4@ z$66m5`r6m_FQ+fn`)+{}#l?ZD(57?`1^I&i?{cd>JJX|VVu4o^y~_ zO1AfA%Rq`9>HO9=JU9QiQGb83wEePCcgPEaZgl#C3iN{XR;AJO4R#5cbD*_}cGd-# zs(^>;Dq^HdQVM(V?G0Yk)oD4;fg-gS%^XWua3+D$vJIXnw=7|A!i{7h0ZzH)%yl5; zrvz;OC)1~os+mU*o&nGX7|&|#4KoaY;N@l79iq#q$hlX^!WTY%zVFcN zBO(fYkmzwP5|kZ~h6x0EryEWM|1ERf0=u#iQMd|<+~GT{D(eL}Mr$713d(rMT9C?J z1z!=&Sip+Vkc)!7nr@W`W_n6?;bif)<(&$&W2SvzvobS~ymwe`w{tq1g0&ZL>;`=x zxG>j#Hq(V*PB`C~^V-XJE*f60kN$MhUw^!r^PA{3eq#&ZG&LA}dBeX^2rG3N3SOh- zk1F)F94ZU*LCV~8e|0t4{p~|CcKv2iJtRW7_T3JdV4ieK0ZHj9=C=!E8mMC0|8TDP z)Us6|Q^!!UT@;rE`Z$dg21n1rI-&6)uH&UW06;CeJgVgHlb}qW{~PejvqU7L<$M)G zOewO~_UMPmsDnqAcQNw&UlQRq6@;_vD$%_S<0tlj)#j;v-ht1f(l!3<@oEN9)dQvk z_)Ms71zsBv75V}OV)k64(c#~lTbKyrjq`uwJB1m5eS+gci?7#gR~QnXo_o9jHdFgC ze%7^Rag}DM^*?-6EuuSUY;zBQsNFnC{sO{54$Z~;Hoa+zKS$nJx%gYu&XP}$!gq6tlIa3&1u=d$ z^9{gcXKK6TGK~j83g^OZxWS#k%Ja?3O=ZY9Nj#Pl;X6C3aw7c2r~auktB0hF@QXD;h#@3D6f<)fZ;z`OUQ}$u_L{(vx=NUQO?M2NdQNLw$XgjXOm6{ zLc!NbI^pZ^wZDwM^0zP8*Vau3kYAAq!fyNm{!^WO#~bd#kHBf=S3YZo{YPD-aiQyc z(!ci659MJ?K^-^oJ{PVW)Fgs-ra8sA-itU+K??giJ5E7K)VE<`O63s2%p}JE0^$ct zLdAiT7o{|FLuc*=6cbV3Fci!yTZmB$tq7{K>L&qp5K=Q@blk1vJXh+yXql4kWFuEv z9|GUPfrIya19^X#g}2o99v%a0L2tHw01f3ihfX_I(Mq5KD*M$kP;=439te}{DI>;y z)ErP9LwLI8_)7nd?9TK;HeCOMSLGpDQOPI}!nQTPQSH({H}JEfv*= ziWsP95s(#@K3`mr19|*HX0||7*(_SlSt{@>QYy^ zrqe8bp&w*_!=OV`)C8z0&DmtWZUmAkfd|MQOSr=EUh-?Lxb@x+sl?^&~P?~^+pc)IJ! z-8=YaH*VZ};H#*srJ_${Sp$?`SiipIe{Q_*$*x`ded_@yXy3mBzk%Le)Y#G0ySaP! zt|y+xK167p{=@W)es)o#`D@#s+Vx~NN_C;hzxZ_b*S~^}_kdzQw0r;l-B0a$WcSXe zp8#t!e)du87XkKz-}^+@zAtt^y}GftYhU+M`{=*W*wy&>9gFxMdEajQ#wOmx_6yho z$fDB>m~YG#vdz4f?+c9&c0aZ2=_fE0bOAQ+ktu|88nj-)O4+bs|I_=ryS~2YbM-Wb zG?{@lfqVS-`kbe35z3!-?%wgV@A2+kyPq=u$OoS4*-L~+^!CnYdh?Gu_Vzx@$KzXl z?RNX>FMr{Y?RVUD*WK6N3#^AT^!T&BPoMcPySsNiiJN7=cbNAD`_dd1%9$))@UzcxxZ}*PfT~GSD z5A5jfr3ZKWdb{_1omPJDQ@-8%eY^H`J@s_=PT$jeeY>C9@#Hf*=?}pBJ(z#sZT8~% z*YO0uYTMrZPn&z%hyUWXP4}69<qM{C`<{6L_k=?|-;SiBg%1 zOhu+}=X;w(BuRx(Nf|<93ZcQAN=TB5D3zj;p$w6+q$nz-XwamYCPayzwU4`Rx##o$ zKL4KA^ZUH|eb3$Yyw`fK_gZJ~eb#$9ZblOWH4XmF&)(J3SHaII5R$xL6<|etz1{7% zK)X`I4_EgsNE2b*p?jc!3ZQ{rUhWQFUK z+fu1d zfj&KE#V?h9GhDQx=b<>MXG4*a(T{>)n#F#ZY#m4z+nWy}qsxeD1@Q{oTn7#^Kn zaO3J`=c{ouoxSt>f2>`my{)o8++>xMsJ!dJn-2?uzEIqpA{o0=ep)nz=7k&;c<1!! zcy*yFv)(w!%EGX{rnoDa@$I$V2-B0IQSn=DE7obUntiuryQ|0;Zp%zDtr*ChyDBPc zp@C7gD2~n^&gqe_nyR+7iNA|zFPh3&D{N$PDq(KM%|6*-a4YPu;*lJj=9ToW5K5z za(|kOW=Oaz1WnKndSliqo~1Z@q1z6VRq3DCW{xddoiy{lXn)|-rsZzK#tI#pH+Iuc zO}UHq>LypOgjy>l6(8Haw^9GnX4~Q|pI$7T?7=(}ax8a}AY0*C*Zk}}t1qSp+@&o$ z+P4dZJt^NQDPwZ?Tc_{3RsoMZ@y*JwT0{2>rEFIgTH#ufVC59l_Q3hsg}Ij+-Df77 zxz5}y`0TJ^$LrjbWFyKg+fWk;sq1zF$pxI+19BY-EpLU3^fl)HJj0}N7LV?gd#*+C z{&i*QPN!gJ;q}*lNPg`ZcQq>ccmLWSiHA-EygVlOwQs(dN%fWci~3S8>M0){?{;Ft z*#w8cb6#xyJl(+{|D^S7Mb1twKRwG^d!9MHS*PyY6VLHxOrL*H zjXC$=x-q{;RWCiH^Lxbf`iJZNYS|f8d(Y=Y)AEC>%Re1`^s+(Y-c1QgJVjnmyYD6_F<|5s+RAH_ig|9T7zj2q(!ebIC8t{;>87)duRN9x7v=?bZKj_ zt7bY~_o8dsyIaQ&O}I2+;)x)YsxVat;}@wWDXsg2#sqz~PVOnQVni)mwX^z(qvxg< zGLKdDYQrj5Z~fAuC_67JNaA3F(ypU=FjpNAXHJo9k2Yr%=- zBXt9%3$s1EH)}DAp13p$%kHPWtM?wG@H{2_)Ale!+P6t#pXw}@V97c8+WeS!9t9b@BC7PRNnA1FSZ#1QcY{L#5 zi?X6;)vDi4F8J1LYo0F>V`}HD_sc)-6`J+*^q$5pin~fxx^MrsyFzbFO`g?j zI4S-Jj6V8>{qeQS8s+&n)?ZKAR%bT4{4>=>d(UTarMI^iIP@J4b54^m>rHA-mU%eYyG@h75|R?M_qMa zJdmm~l&xCxD#2s8yn#dAyg-514%v zHBlYE=GXMi6Y|H6yMC%p_PxP~j~%}qZ^)lmsI$^!;PP3@?42WW#C`^qjx@SGIrvOK zt~$l8{`)8Sk3x!zGy-PG^{qycEZnzLtZ-tt@!XB2`$LT+?v%!wSaK59rLGI!prIdHCnfw%&Fi~&ua1yM-<$KX zi={A z%((Y%?=sJ-a}@%%Qngd>r7c<{w7zPe%bRby@7ARFEj@EE!J%i0*#63S`?pLVotVQ8 zG!>lAj(Aa-)Zrgb-?n{{lG%?t{xg=E)CndeAEil#8g`pC`kUOpwk_nf*SH@$3rknM z>xpZ+ptCr2oVkUt&#c0%`dte&e&4XU(5St!CG~AcL1@+rHJYLk<-t4F1l>)q?^qmN z|E~4XM7OdDQDuq-tkY+{UCOT7di8~yyw#``cfu`Wb{$r8Kh_|#Ev@Lh_BdI`&5pKr z<-^X!pJ;zv_qA|#QfaYIug@$G(Y>RcetJkg+sUl3^&Rsx$3dbgc$$$67-qyqI0Ay?5Be zQ0EJaH?ErhFzd+fptj{Zoi|+$n4eIsv2uM!-=2_i(>)s!vnuXfdM3VgbmMG`Wm==g z8%D1acpv7aeQ2%MHh~Y#YpI`XwiZPNj0;+?s+GK)EM$1NF^>(N5TKUp;N zEFWz>)3NwSmdk~EOU~O)u5nEB>|;HWiacN!ueBC6Dl14SB)eUxcJl^Xg#q&VHX|g)?%Mk>$SuTt_kju6_2clFprVdmrSwS6CoA3NNDbU%isGSJzcwa zz%^O;%Zyo~iH+6oGV~fF?FB|mX=-nFrfbv-)HHoklhBfAz7=1iF!@?u)2&A%`l@eF zNWB@jSx;ljyK-y4`fqK)oEm-8q#y1|>8CGlGkUen-Nkc!oz}CmQz>VEXsp~_GImAH zwF3Xe>WA+=5_x=WVUNitL8liF43%|_nr|$t>e`XyHz{Vd?(+*r20Dh#w7r}%Ejw-h zfmQL>cDjYz9(wTWoA1tj^wl$No>VZub7|T}>5i%Tan36fla@%%creGtBb0SxU6moKbH^7ehc}0NiA|kZ*wA%k_k~?^lp_;o+%WBKR#_(+Rw6R;OheM>n39#_ z-`b^IE`3!eJkHYY@%2U4X~_$fs(;M)5cjrJ8RKT&`Q>%V&r7l^G^JIqzPX*&p=TyD zuxueG+b;T8u9!mL_5Brs5z{1kUz|7Clvys z@YPF8=KcxQi#hA{7%Ora1AsXDl}{!(y(*fPDJ4QoUP3PuK`^jC;h zk9xPM_V>6&Ul%4bLVx%+rO(n;-Qmo^|avt7nSIPS>Ds*s$Y< zu~$`EE5kZzTOwOTVg9|U7fy-A!MDN$JqB3s6quTm0vYqiDK;1>mToD`udZNci9Rlm zw0ysP+6$#49UB^w;x|~$lS?+=*$`Fo)}cT*>f_UpH%`H;KW_>z-IE==aJ5~)iJ5QC zW!PNEOl5W+sfxPmvNBDfZ11TFiOnObkJH1iE3A4jvb(mUGb;DjLGvadhX=WeA8 zSLFO2g)@5ou}d#6wB0&oWP)``g#B^tJ&QW}?`5=irKXm@%`!`kvovMoEDH%a;MrAv zOK^mR(dy|*ec~R_rQ2#TH)CxHR%;TJ>OR9I;t;`(ybpS)oL`HGv;vB zwgZ9djAyEg+hjg^vfPB-lWz0-*3UMnh~fu93RPvZ$NQCC&h~tL`YzSrbiYw~Ra38G zv60G#zLJBd-{|S(Pqpluewel8^tiSC-cP>Ehg%1E8g#G^SlQ@_2A#{5y>q>DvPH#j z_xc|@T3MFEb*4Lhw~45CV}6rad?@XSkxrn0Kv{)W`f?M+V4BgcF(R6|AFV3hUG(?Z zs&}$p?GZ~XWYidUyZ_dn|dB>FzS)k}Aw zQonwEt$i~!ST8Yf_KcX9=QTwx)UR)pPFp44zG2^FNl}*@*X!Ag;)!kTrU#8ST$<0M zg)KI+ZTGkytWF=OSU$X2x+YA_#C-EfHSr@UH&ae0%b3sJ`7~O3DwK%7t=Gx>J#`?jiR+nVnm9w}zs zd)H-SwdTT$28P-Bgip!GAM8u?@Bh4Dsq)yhQWw28ZayzI)l24-YmVcEU5!>+ar>_|bNu%B*P2l+FXqp=zG1j_>c1BdDTS#)Apo<|pP_ntt zebv&p4kKm1uD@PU*&VQawqt1|b9eP)=1J+LSCc!I$h}`DICa@B2a4pLiW@~uL3=*R z$w^tpmuFtBN&2-TWS6~%qL9eO-ANHMw9YZgl{&jpXRa-DkYe3T->d$5W7i#L{m!Z5 zbK+L}k6dcyk$og)#f7;Un!#^Qj_Gq-^R?9}`ZmjoU4Q;kSMBkzQ*%vqYjTBZdln6- zZ;Dmeyj4i`y~gf2Z|7BObWD*q_!T53$;@17U`(GqD_1-zsLJ(~h5vH)@${XS+Z`O9 zpZ#R`MOtClshg)YluvyA+OQcCJoand~VS@%4uU*ZW|rSV;Jy30;ZXT(3Ao7H{fPFaH3giq8jvPUzci>zzDy!&wZ%Ek*l4jIwbrp)Ct z%y&*&aCLLs+tJF?TV%qL92NUr{PZmo?`vt_@6@zuuyuJ{MQrxozgz#b<`)$6d+^ zo*>d5#WFtW)-cX4=ZTD1S*7?l%ha4bB?otWt~{rrw#9iu^0RLrC?ax8g)__czn$`K zQT7S3i2KX89_(HDc!_xQrJlgH@*^cidB$H}Eqv|0G+k5d<%hbs$&VsRB zLKCFcd1naZUoiSPKFw@>=?;(AN>Q>nh-!Lo%R#YSaMj-AyxTp+e%;hVF^<6r&OIdmsK$YE>MQfs#|oysZ2 zCS!z{dv0nSnELC@xJ{G3T|2NjL+??o(egr(gg*BO#d)dAO?RJ^J#FCP`y#!gWXiXs z@|qpe5+BQj3~!egsu#;}ELiWzxgD2+=k1lAB|8~Vkr}3ccF&lNZ;HbFH{AG*Y`m5IMF`6xBzoaB`!i%W7 zhqLK*BHrs%(>TiBInDNGk0u)|UHIUB*J}$W$44B>g%1<=j}LINRFyd&cRJ*I# z3Y~SS@8~w`(1N8UZ4o23D_*($;PZvIr*3476i**>ka2@i^K@%Yti(*EeOpg7MXNG= zj=8O}&9hWJdh%1N^zabnBQAa+;^na#rrM6}Kjte-Y<;8d{Cf4Km!tMd^hO?e=n=WU zq|((hJ+p`!SHyf37b!FPN6)p$CST=|QIt!fA`Qo6b5!5ZBzK>muW>KT@^(S?-oUS- zoi`Rq>PdBJ38?;jW3x)JK=I7RnX?3A6>6GGN9PwBT%6zgm`EwJJ37aY^mt$T#nvPW)h)^Z4hQ%Rv$>fiUKn$saD9$=A%8 zU8!_#MIjJ#6 zeN4O)(yFv%l>aH~%-R;MW|xy!wwySa5azT(li@tEO!81+t7GK?&2iqZ%l5J~Qo6)@ z-&^M)bS_vYQTQS;fqsPf~e4F%QH)-V%9u0GhmT{U2gxru+tvkljpY~602@f)8@ znbPyh*3qBFa4WHDatt!RxZ~`+-r(Aii*BzP(N!+g-|9TaKJ(jtC(-w(XRV&zYSeJ$ z#UYV%hn@B3>83lpj5zy4v|TMq<78+-mbTv0J9_7qsU#NMXj*Awlcc4#IUT+PHl}ve zUc2+EnInIxU6I_BoPT3$*k+l^!*nIPhN+RiDB-5Nn)7SYW;O4aZ{lM)oxW55F{@8R zOmy;dYW}xdjRpgn@%JrE^UO4JZU%2LFF5g0W9HY>sr<2%M9jk-;<~!CY&g@%u=ix|I1(72{+KyMQ%E<(usoZ6lp669O@Wvy4 z`+Kdq+4p`eStKg|Buuc5GFRjBtiYZ+#oeh^!dsi;X6BzgW0fv3e9Q!ib(y2|_FeO1 zSVcD`nBSuh?7yuYYVG#p?Xd?htlZv>4m#meBIET$#O9V)>W#^i)9Y?l_?)fk3@OfX zdGB&G;^Dk2aed!&d-`VSKA-<(%&yM0=jyy>vxa{z>3!wA=f>C(%5VB|@7_9>pY$bYIb(vU8O}?lbBe_f zTvf*93y+p6k85(wU%$XxUt!Yg!cQvG`(liv-#H!Y+9tElsJQgfiPTULPnC&x19Rpd zomu=bP+F)ASd%JS3JlN$@_+?M2_cei1 znbD`Rk3QVT+Evu5wq~2{YS-|c_bWu=YF1RGDO+BqmEU%=tlN?Br8Fgzv#DkEM1>b# z%Pl{SbBNjUbbH$g?f%BL(GMTYnJpY7VV}08fWsWtZql1lV4C}o@ojgkm$$SQbNgM- z+D8V7t%^T(+1}i9;E5;uLq)WxV`kja`ni`oqqL_os}_VmIMnyvV)nG9i^}(zi$7y@ zt)1I=t2_P5NwbIRIexmQbQ!z9R5oj^FydSL79uDH|v2N46jkhO15Ex~?iF3ECymN$aV##oNzkpJfy5F*R ziQnh99T5%c4{$zayJbpnY2o^Q$W zlR0L~=gu>$CVO~S_#OD=arU?En%$E|d8SIgElSkw65nT1yx?X>ob|%Sh3yLx?n``J z`snrRhAgK=qvE3Xyu6lIa5EuocYDUTWVzHYy=6-oD`mS^<)5<1@b_38{Bm@@YV=~3 z!pHM{XQrQs7@N?Q)3H+Zs*2-D8S%8Hl;e!T!{ZOt{t`GDu}Jswy*D2N96p{EXbD{@ z_B)+5`>Nn>U5V7^k+#=Min=}8&u54w2v*>8hmF{Y{2bM;or&dwjNp z-S<%g&ZifB9^RoE8KAyuZSJXUd#;7)`umjSD3>WqG-VvVIakH@^9|`7x2A3CqU%fE z{nDSWa#wL`jHlP7vlTw8?tTdO`~1VIe*5EH{YO4kW{d53vbNOUOg{40@~oFX3Rw>% zGfl(x89k{C3tN$PMg5|%!K%Ybn({h{A6BP5JY;h&;CoHQSam(!ltmd?N7MwC4s### zHO{ce?xy4G>hKqVXWhJRi>xf~O`dVee}jo;x~JlImjbmn2~Wk~a8b#U@E6B?lC(Yv zt2;J3u>{is7{5~$40|PWEO%f${Lo99>GkF!}85s(p@bZFSY zVLu;g{F**v$LHxnR>}po z)dQ_{edd1t53OAy%1i^7g-TAgyT!#seEKnK zi>$S>?WbQ}41Kz>#p`sjrN!cTtvjD+I*T953Nmfo>;3dc+MN1OX%YD`-xju>x-&9N z^2vjS)?KN>=GDIM@88gMK9IKmy3?6;v9kUjY(hH*0`taX)=qfcX*j!l%}p`!cDma2 z;AO+ihLuFfK95xOxI3dEbIODrt4{d&_m*iGy)E%telKQ*ruf0Jl>)u~n_ObzY`%D2 zzr0QH(tu>P#)`IX_d0OgL z!bD?f)9>4)^@0O`JUDwl(>O6NK{U88$#ir;Y2ZOqn;qAt&far)P0xkQESIy>oaRJ6 z>ezGr*}M^2ox2SC=H9AL5O3Tfn40@u#V^3Ial@=t8`MnvC+IUy*ttFa)dqoA^Cs(# z0yq2G5xr%BuHi*;&9f98^jaM6eUq_&%2>X4O`pWw9a;~kEUr4$b<0iJY?t?`()&~E z_9|;XkGbzOcdTv9oYPT0n?7v3Dw4D?xoC})4dudUPGE8LT_-K~8yo5_fAg{173=Bq zZGrCSIZ5?44V~7OZh7Tp1F6@f8M3|Ss*Cpil=pI5Obf2q_+ZxweJ`79ao>Bk(`bv# zc2vhYPc6A=-O&H!rN`7WbB}oJS(eioa{vDPhG7ZwBTS3f zYhS*fXus^2!pKv5&)$s~ebngM>bTI|FV)kokM52V?_MDGRdB(6gQ#bcUn?57PYCk; zcB@cVDNRAGYTr1=+D*l)#4b-CyB#E>l<&WOm7wx(;Z)sERqr!mhlvfJQFEuxd zrmxQO7~ZHfo6^luDAzFhxq9E&u}Kq?wEJ_6f_iJN-WQPVGjpp>Td=14!;?4H9*w4y zHAJ6vf0`%b=v3kD<=s<%&V9bo)y^s*Y?{B) z*KKo_ouQ_N|6E-rC}ho1unk*UH^Fmp<@4l`ge5Ehf zQS|cGMVUpnoBH*3wib-5n6)ua=hf&c`u&TS4TYvyDRm{8h8jn@Mg5FDZIaOvGit7+ zXYWM4US(s4nw$AiHVOla6&mYmT=(5g_x~kTFB)`jePiKIDMzs+L5bT&HFIdzTQVN` zPa9Zv`o7((lWF(fy}xv_t+rm`p=oyPRO31a53h&4xnCw%@2)P)F_wF)9eT9PajbQ( z(;U^rWg}-x$(L4sRqHx5xub8gfK^lETYFpCSXJ9GW18~DntU5M{u|Te%*Gqcb5;n1Erljt1}^CXzv>K7l)*l_rKp&8qnVmkIx%BJ_XvtHlZ{(j-! zJ4J@??dfrP!)v^~KQEYs_xM|7eo_#C!sZ>r3nI_IijZW~M7Oge5viazq zkMCcUw7okvu+jT0HCH1*ev{EOU0QWf$@8B4aU+JWsS+8y%8GkIs&iU}l4C`sV-=2&J37qMquDv+q zS=do|rT9oE4Reuph;%3jNjfoc`+^)R$nQbX|$M#X4>Evs6U3On?a*Dkl2keSDXZ^e1YIu+x zt*mi%Vw(QUvpdeJ8}=R*z4>gqt6XltojX;#?xzhe+c5qq7`a?vaMD@H$H zb$54Ze9^pD$`Ctdd1Zm?>qX1=MT;t3EY4dd?CePkSm}2;n3ma+dp2e9hfm)dS~FXy z;T!eVsO0$99&9z8DpK-(%<~7%7RoEqLzH*A9j7s@M$%m4_hgoZR>!#4xJcYAX_N{I zTGqCX7Wv`)`5)gOH@|!~@qkU5Px6;x;k75fepYz;`$F{d+}=$oy)qHM7-D^WZIfyv~p6!A_W=Sefy~qbA^r=sJ)t1B(c{24n1V} z`-#67ZvU}+qwmG6$ola!nKM)FCBB+ll_(-mS&%=vqwUxOyw$ z>dNia**={~TQ}tmm+P@*>TbOM{HoqoQRSMG&Pt7xjnj>)h58d+?l0+d86{4=*>=Q3 z*ltf?>z0FB<_-p`3&Y;e)H2>1`)cXub&aWQX0z_B^Qv3BrE+qIOIDvi?`%)A8*VQu z<97%&6uup+C9-zbUayzED!XMuI-i?oZ4cG?@#f2v*W0XxEGOSh9I&-IC3#j~yT-pu zcCF#X*0+8;pSnbBzNQkD?j-CyZ+Nhq&@*;xe7w$Zred}Hx!aaMO0P6}8r%|szE^q5B^G(rBP`h#Of$k(_Tl0_F73WsT z#<3@SKhbXc>yX8!S4rVix9{h)1g?B)Zmo}wmuE0*q{mjg>v3a_^u5$l?4BK7>bBA@ zP1*2kQ_M9_K>yA>VELF3gVCEcP7AGtzWn#|g-Kp#lGuFxPhvT}+ z=-4G)4R<6GGlaF?yWV;k9Q*xBkE_nXmHHRc(= z_03kR=1S`R9_B2Yn{~K1>%HW{VQ=X9I~-inPrD935PNZdm!B>}ZkV7^VoAc5SVv~f zi^H5dUa|8!4AQ5}lpC$mR_B){ltUnv4ufizEQ^$ zME#bAY@F3US5)|A)v=>$93A=olI*(D=U=v$U9S^d=POtLu}Rh1ladgwcYNd-^WD@C zj{_649zNfipmk2KaEyesKzqYBtsGzap{jrlC)c;Ery%Z zExpw_i|gOZ*HdOFC8^pyI5PLg?zU%#{imo{o-&rWc;`!7`%Up#4WAB-^eivB{%X3+ zvyY*DalYc7wVxFYh707;FHI1Mw10c@@-e5V$TMR1HHwPQTsZhxx6p8cg^vD_eo^M{ zF*Cj`DTs7DZTqRi;^^$t2Lio6NM9V&)OwIJzDsqU$Bq7wEL9U1y5nTq_nHNdRemlA z_LYws)wZqHlhIY8ny5J@;>6y~l0h??G+Q%%?p0X3{!2@p^S#}Y6|1v3_J?n@h@X!z zQd{nH!s1l=g~yHq9x zHlLc$E~FcD{9Dmrv-41B*I5WA;gGtk4ikYpQ)8eZP8D>R$KaqmFXN7MsOCO}#e# zVM~r~g>F^yb_1igADoP4Uw<7a{V*|d#;vKLt8VN4D)7AWc(&EWOTK!?ZKKQU?ujKC z`>kH?X0}0n3T)7&U)~ZvWqdha<-~6tY`0&gM?~|3%3z@b-)x8E1NpEH@E6b%lR^>GB zT(EnIbYx2(W0_dt!(Ypd=InP0|Ky>l7XJG5ok=~%4u3f1sy9RXY@@D_VK;?s+ueC8 z@N+}>)HCkv9H~=9ug1(@_gnt?;|6^z0ap?4Jrn$+x7kf=m6@Xd?78Ofj#SLO#4}o`3ndzwt4HGjZ1ZYmQP9_Q~t(%)3MzFW7^X` z_`Y~ILvQi+(CZt=ZH-!&S}3?f_?y9=bhF0iU)1bu?)V*9y;SCWl!&)*vOvL7+XfK< z-}5P5>DvocJ{Po5f-a?CM-#?i# zt{-x|xN-C7N#R*XO+J?^ZYk>Mwk#fhW$QxUtE$r93_E9C2vuKT)9t$Iq3s3j*&TDP z_Do){PG2myZF2Cjb)|1Q=Es!RNuOvw+16{5bS6g8F=O?dY5JNiONZ@VI-J%xI!#t= zM6FWLy11r{l?e;um#{QFpRQR~v@SMZ_ac4$)J?%Vo?Fh{_}gFbnC7S9w*o&JEPLYg zz+P?fmg7^jy}Gi;x(KH1d*mq}T9nW@uvd_#dG!9O#D*%x*d^!f6vxgDQ=0ms|9VHl zLd_qtZnGBmb$|1^tn&Pmex*_Ddr1?Egr5^Xn0V=bt*U+G^H49(X55?L=OZsq+56VN zFT4obPFwy*AyObc$Jvb$b>c(-Jx zck-9$-}5U4V%${#>;JIZeUvGELaw1(>~(# zE#tlu3oX4rmEEeXj=MI0?lj|~?=q`JWIG*>@7}PfSYeUgQE}bq1ucF4*V-5@V&5}o zY;{gnn3_I0g8Ht>LeNfT?)c9lec9ff0h04JYk&D|x?<_~O@*$Ew0MylkFHI)ch_>8 zaG6+e^iRrZ*UT?lW7&+4(oNIvdX~R0J8B*FJ4&S_k%Ewpg4V$c{uhu|VF6B%#Ew74kFGDgl&xiM$bSEp~1pYPNO zF6+pMdB00;AN!WW68VYin|E5twflTc{?(?daZT)5O_7@xtI_3lfl0aXCyxo5@4EMi zXFY5xeI8>5zU}i#-ny;L%a0^ps@}3%K)mnBor8fI6xE7x>P3_0UCPoJk#0#p9v&a3 zmb}BUF4nFgX8n!%iR~p-%@1wz=RMm}xoNobjr81gPb!z|Zwi@Eb5P<#sN{vLFb!tI zk6Np%fy(j0TdRZTjnydG6y1Av%BDr%i_UD(x7m4RTFtJ!QWx*vm8K^R{VMKy2(Jpi z{;74?^qa|!G70k9D;@;DnSZTfbGBmKo~ozL(r!niWw$*Vf6r)bf6uPjyS4WOF8I*x z-m+`>ibAVswqrZvlz+hC;otQ1bSf8!Tu%MbHNbh#$h44suOKcIseK}KZP;c*`OoKP zpZooUDl9WXH|Jy0IV}yfaUH|n+>)wNS|$5_*^Xm9Zg=DkPSxN{&JgSi?wwsKnbLo* z@ztXrxB8ggUyN6ryZpw|_DapZf&?Gk%!dmuzKS>9y|b}3<@tAkaif|<)*U~-TS>uU zL+fdkFFTVc>p#Ajnyffd(*E+=Df&yw$Ngwq+mNs&%{MhgAIQ#3D zg{^42=CX5TW7!Q^`=pxkUS-9GwQwfo2lmLfE_Jw@veK(cNw+D^U7}g=HhquJTScGz z$Th;_sz<+^6Wp+U_drDHc#F{9I92_(Gc=}kC;e1?_V%DunUlH`L($Xe$$7Vs_-k)D z5?81OQ?Jwh<3df|$Gj*sD%^;`JuAfc`)i@Rb5q*HNvS2;7MmUX&{-<<2bwnTI0QNa zZB86bTJGcJ=sRbQwmpR^#30V5nQPm#;1OM10FMlK9L#O61CQtoG^A4Dt0mk=?uU~g zkpdTZGAQ(=1W4rwQ3i|6oA>7g z7aZRr&IEHfaB_=xfWv0+;|j$8hjdpTUq5uvNh+`@qJQ{WkO51!#>7zS}oGtBOVDn;)dXnCzgX3l|wO919wF5O*#hL!#6m4=wv^) zML6R};hwLvXR(CfxEhfKj`vZB&*4EWbRCdRZaWNkCca_>=`^+walbJ z;GsS!$Qt|(0Llx^5NEpKnaUC3sT)!UZj*GX5T07N3<(|WCwc;(_rZ@$7y~zz$>C`n zizrxP`rud2QI}XeO{9Q&5uZ~=$*{8Ap~GQEydLm@N1n3Mgz!o-gy2Z}U?&(t zZ0;iiApmzGsnAcX&1}$dJa8&Q2&+C^-G$eP!h)$r*Xuwx=ztU4O5k!$iVoHZG`&~` zIYLypF`UTGU_y4hVo(&z4uBz*__`mORvG17B+TgF2`m#LZuDp9Y`}aSQ(73sR9TSNHEAY_ktoM z0>m7``V$L^XLe%8AG6w5NG~VyMxwe z@jpN%Xg{_MAezLOVKHH)h;NF(BPcQP*%f$X@T41LesJCSRu2RgbPLe^9~X}?WbM#o z60^b?GGee9|0m;M{0}2WTFeDA5JFYPGI)R!0EeMPLVOn4=c*qKmSZCpp z3kVDbJGNv303 z2WEKid*+ZI%rG4jJ21m^45h&5=mao89%zdAm<>EaOPJI^hcTytK4MCPigCNH1CO}p zRGwJ{{y<0&>MP*Mpa=sA;n`O(`j~VA7vLEeuwXo@0qt=u2m6n)04vEe5U4t?b^!lC zU!A}jBmR-L49MMwc4EKjLO&0_+Fr0)Rf6a|(jaK|+G&fzBEt zvjkrJx6Cg52bo23gsCQy9ZWT0+31*R!m1JXX2KMLq+z0oGIO;X<;Cj&kK9#*RltN3 zB$R@s@{jC*d}38#@z@c}53ep7j~#*JU_uF`1hWzlGaf5Jq71VHeWU^5Ku>(D3`-9X z_wNu2A1fJ32nKl*p@>i?u~cBM35!l>5C`-Jo8lpshfWCVf3KP0Kdc$>2s);G;2zMi zngC~|<5>b%fsR!MTm?Gjdcbz+nByYmh)FoYD?FD#Bk7oiBV8h>4$>u5mb=afqX;hx zr9)eoVj_&>FVeCJ0E*cnkrRA(;l89Cr?8 zliN3-?^qrFaBaaOoe4Rc>0_&j<4;|+jm!1fR<23}NHU#@O}sp0toh&^LhipAsl z;D=yN0xTWVe&F#u+7BKl519cbv9=Sw5$--(LGCkn3_QY)h&)DHP*^(LmrhnV5DECe zB85WzM^t67hA12XComaWxHdXhfK*otX2_XEu!NNyLaqmIoG0S2@bwqAH z+kkG+L;*1xh4PQWN~7=#Del$Fh5DlYY zx(Y!S8m6ld#h_uj1u+>K#!1jT8m6ugF{5F22oWPVn)MJ z119ttQ(7Wg!xdbJq|tb!7V5#Q7C?)JX)OR74U<_E&%n_+z)u>E&H-xDa6}Fa1r0~! zz*N#OO#(|m!!!v@B@F{7NInhoBoI*=CQ5+&G#*oeb}`(8GSe_Y0_#J=)&tls4Rd3} zdoZs7#in6d2Xjip!7QZAJTOLOxf%z}@{9~Ta+L=f#VQ4DVu}F8FhfA(9@Bp?3%n2; zFa!#odI&gh@c=9V1wV5j1cVn2`id1F96IhJKoAx_ut|R+aBx9C1|aAj7j!s0JOCq$ zO)ryYc@ae8LSR_2Wn}{@a+3idu^EPtAkKhdlh~sD;g?`fvAqShgeM4*B|L2~PK?Ni zb8$z+{5w1j0M3OXHUz!6xCPNZp2cNDC0qyuvp8Wt^;B!cvabKA&k%{7KwQl1T-mFVAwDKEZD#+c`g_5M;e|HU@Nr2 zHRgj&FwGPodsNE5hW0tMA*e~1B7$)eg8-=|mI#0ZnkDQ%=qq8W(Q2Uoh_1nG6BY&H z8AxUTLy>)lUmOL%0s=|^HwZN(1Q&vV@K=Hgf$SkUAz%m%0cr%QLKqcTe6R+C%|LGW z8;;r$Vhmmcnt#MWkQkx=07$^%fhK?r1WP&?$Ro@&5dcKr${?_EFrGIA*Qo?J{Wq@b z{{yarTLT)*m1{IO8Ybry9Z&--jOhDOG)&LY*EeX`By#|023Z`$3Xt-0C6WUug1I`x z8EIICK-XzJu8vyZwhcl_!^9mK7_4@n5j0HQK`d!l50K%($5hB+%TLO75HGD^dd zG|+DvX852MV6b5UfCqrO&`@}jc!oMLlR`!da|O@=8rETCoG_~bouXk@g^UwsRmeDD zR)vfcW>ui{G)y#*p~9>R6q$-y6&NilW>sLQsF+oO-czyS0|BREUIjh{6%#AaH!9X! zz)32mR-gn_OsxPZs60{+Wib{4dchTjgYy6ej7mr#%nukaD#l&_J1RE(z&fee@Ph%P zVyGrUJlwej>P5wdAJ`}r8-6fgR1Dl;z^K^pgVCa5!w-gviVZ&)Dk?Vo!0f2l@Ppq+ z#fBe-%d_=hhqxe$A~zV-;gLH&=q|SNzzhC1T0BDqe1zu&f&s&p3Xl#j6xb0SFGX05 zvmlVf#tc*&TQeXOSbqR*cv26Bjf={_2=F|^iveCl480w}yjh3Avv&k18C)&SA72v~ z2_7zx4Lp@#&v<4Im^Dw^!M<>7M#LEF0~j>iBR0>rp(rC)Nr2hmKn;*HY|l`n4XY;b zI&9BSY!CB;zr03ZT|AbJ{7vq`0>~&f5QGX6RtPMV4pa!lZP2KpWh3Ygv1)|aa4i|ihW;a%2%$57 zoCd;V5Pw9DFF^sg?}i4;{Qds{CJ0mdcN(&jfBO~)>HpgT>HUKRqJmCQF} zMY^y}hc6|-53c@E5fWpoP6cg5AAjdo06oC!NJYSm4LcRIkcu&mieMU>b}G_UY}?_z zHT=N%tOGs3NI=zr9$@nh-x`4*c&-5iso20%fxSS(-0lE-frjx9=mECz;N8OyB+7*2 z4~=5WP65gSZQ;K_qu91n09L6Oci`jh@B?ELC^wad$-rBv*p5T|0^9}e^iqJiK=s_J zfx1wzDTkl|{J`*rxIH%P6ksnDY}qM@Vq?=z0obKr+YXiqesC8U&<+p}H%hR7JRaaM zP$Rbo;CVxh_y<&ttv7|Rb+|U*G!$&7!5YF3JOp4k=wru&lZY%Hwl5UmI~1O+2Eqfk zBjaq)4$oSnH~rXLQ-J578=41e1ENF0hKmBmfr2eHKs@}wQ$_fUcs$7Iz_399*q~t8 zpa5(@^|)#n4|dEcfFV#l_bwVFg!SbjluUpNMOSXyfD{yr6ksyp2Ujs*8w&iu6OYU`#slC8@B_~dXgyTI?HlO!;F~AZ9Z=`N zH&5sXXz-wSMErp6V5LRA1cY$86@V{+-dGK;HfSTUqkzyx@FfO=vQPo|5`(T3dWO2N zE`s)fpE6h)#R@Q=2HitG5>YE?8&)>ty>h1*^a-mIXcJZ@P#>&4K(#P42Gzj?7~Fo$ ze?e`q)_|VyLRt{?=Qa!qgY^Y81S<%r1l9;({a6J+1F!-B=f^A&I4I_;Ap2PKLGrQS zgWMCg8>R)M9t%B)IhJx@gILBv#Ib~ffMfYa=A1i$AkSEwK}@lfqPP=x=|PUL7=el5 zSs3K^a2F6T6N@n5B32ZH|J)1+6S>O;I5YSJ>&cZ=SWRvjBv#xau#$sMFd2gn5SaMG z%|X$iJnjI@7>}t_5L?D;2w(#Za_aV426Kj7>dCO#T*^h4=*3sOOOv-2l&wV5xvM5oGLKOf1+lv8Hk$;1IVp<0F658Q*5HTNaI|%9rn*r0wvz)-Xc&-YF1k52`abO(0_g#<) zLkqZF+-kshVB3KLpST?I5V3m=P>+!wZN}sZ4T=+Ts{^{hb912IylrrZieZI7emt)s z(AYomI@t4tpLvEfXB$-Mn`&~@&NgN4Ti9=d^h0n(0z9l7<~z9IR-S`Q0_!3_91jGo&JuyXhd z(Pci@4w^v&1FQ6pt{u$gU#=ah1+_J3Uy0EX3Qb5e(P=_JkVX;q1%^Z*KXh==4@2?= zqB>~y0MfxU09b>LA{&crGgt>OJYa?hhz6?wsKSj367fO;@WF9JgCr22Kws1+08bDsdIAgt8TyzmP_=^!`x^Cto^|NO+R^Is`Y=U@L} z*P3Vwtu^UC-iXj&2s$!I_7Hs=Jk8|K7Dv(bl*3bwWGewO6=$IQbHv zIU)A*6B|1P3iyc$pWvyfaH_$%>Rp^a7`iHhBGC^~2e)PW(=OoTi;Bx=#e~J812GxQ8!G1I_^6*ju zB!~rVp?_@X3-KE?kPT|U2K=J~J~06|SRm&tNaw(BHlPILh4M&c5m-UJKs#8#({LRq zAFd0PL*qbgjQU56 z4aSFJ+vpz}Kl~%wC-R}Z@DGoL3ATce7bHVyUbz1NumKZME8JR%8c+}Z*FTgO|NZZ0 zNCP(USF^bJfB0Xb1BAGvVFG98FN;J6EhPu+9eT&j_xHi_AgX_-BQe3h(KDJxB(m_o zL!yiXpZMR1z=e^S%iz;K@Z}bg`ZFk$KM=zpJdJ-qCtU5HD(Hm!_`mx!h_L2f9`>H3 z{y_P^D?>)%|E52GRr#klvPRs(aHMPfW=AI<1>P5rj5hrF=nzv&M-9$8aZis0`oMQ- zKpr8k1j51nKOi0Gbd9sZU>fZFMgAH3KLyXhG>8qcktg|gnhxv*M(z<`8XFO}ztbQr zMC?8IJ52{RG9w@!ng(`^zdp!-EdG#uI`H-ixbcuQ*gTC~3%)c2S^Q}%my$p3n>kM z8uA2(rU9AbpHt8dL~8l+5l#eO8l5!vaF_vkYJB;a$lK>jWB*4!&VS_N0F3gLg;+GH ze-Qcx_hD!o@Uno^F1+d^*T+Jx2VYtE#u|Sbyxk?u6}&kn^#$Hglj?)+@yivQS3_Z} zq3zO$y-0j%#MW8^w|497<%T1CY*a=J;8=Z+_ zJwy8fU_z1&&~tJd9I{-&xggS7f~b+o0;3?c%V3e)1<@eY$0U5?p?zi&fhE2)V$U#N z+JDFulS7_ACWkzKEaGj((E3=!t8%_HI$7>nEab}Z<>Mf)duSS42f2oPX~Y&1zBFRP z2VWX-&X_NaNp6>oY&XirvlTiFjt+{x@}&`5KKRpsD)Hwd4gv7x1A|1$$0F+`eAkhG z4wyQ`i=rX*K^ltJ@}&`*-}urPq;W8H*vR$f%SXmAAjl*;1BeI|o3AW*iljcniwFMs zW5Syj{yAVmM2&y$A&sO9fCk869@=Mk??~zkypJX4WBx}z4)Xbj)(5agst_~RWl|dq zVs`^yK4PyZUmBBSKbUZEoYWTv2Sr+jmSySy=O(407YTg%i0ycMX~f2R{xn2t`O?@V z+sFi}&#$XY7V%zuXjvAq#fmSD%nz6>CW(VES!|Ns2hAt9%chgdvWcT{L)!()N|Hao zE7DxCIVg-gv@C~svB;N3=3GoLp`FBt7KH=&%d*L1 zgB@?A{=sfQ{C3r1b!J=EqJ5wxKsgL)+l6NnC)fql3cfL-GM#Bk^Y#8i`M`bx=5vzbu=iZ)_bl z$-iVngq~Cu-WQSj0vjgy?JpZ%vGU6X8#c?3(}*p!L&pZL5UCBIqU5q{l09O>&R+hx zho}>Y>#&Oo4;#Ld_&V)Nb5IbbnJaS)h2l3uc53P`fSCbk_9 zt&dII>cW>s=COdpDg(c>R4hj<@5v_1}T{)R7&iC%>BrLjp|8NxpNu__&o4zYcG zNLh{!*%#vIuu(j5Xg+v<#=jmMc(2MYyByem#6LC;yjJC(Qx0r5Bc~BtUWc{|TN?Rg zmjg6{Ul%yAW1Q4y*nv*!AGm7#^T&am|NOWHQ%}+(NF&AEIB<-LUv>dH$zuceh}35Y zgYeA(Y$gNt$UpaRVwu!GIH^v~2Sky-EQAzD;{_LjR3BV+#Mc)cpn4?Ez+phNl)nuo z*rf=N%O+eA>kDV;s>Pl1)V1Kg~cY>GO*?(y9#EDWE&w2OyW%( z;MAl(gVK=N<)FAfpU!ZI`H9_ob;!C6P;{oJj@W&${4T6IF^>N5?ejPXw#5ecg z*puxR2^Q93-u=&y${5T03NQ$q)rcqM-8PZ6c71Gda zRn)|vIfaSg=V8EriCrW^^MOyyFIVs`mZZPHp85SF*!M$vHvwr3(p*6rzYh!ffF$wv z8Qw3D#sOl$FQ>2v80|+NIu6iZKHLS;M2ba18gWE(Xj!g(_7@fdf;{~BU}&T^0Io>=WB$jQGub3O1wrM1=K#t^@*yCN6f1x< zU^V>xgB=*8v4NVTk05^zp7k`&U`S^842LT{|pIJI2o(Q{FiIWO{*9U22 zdk!Z=NOl3vlaTlU97W;h5g-J_@tvV)M_X#BBUfFa`kg}?iZ)`(=Im>g1^ z3(At;d4bvI*9EALguC!!k;MN9NaVMdu=SI~H^5uv_aWfL9fP0mLK>Sa<0vr7KY!qM zlh%ku+#&JzyufB~aK=exAtJ$_20k&LegL$S-V;L_nTNrlTmJYOHxS{Qe;9g8q*=V31-NkdJKhV5b2|KY;r1uQ{SaBs_py zTlizN|4&-_ z9^W#r^-Jm3HjdsmN}tjLSd<=ftVj7$XArBKI3|(@%*{Oq+|)bZH>G_c)bkkxyUsX~ zUQ3zlvgfWvv*W7uGS6f9l+;r)CfRJp6xU6xE%l|s5vf;*$}z)JYarF_+ao3BloilT z*4ntv*qY3Cza0Uu(_cb~Nj!&p0aQA3kD#lhoN?!=LnnM~+BMGQEc_G+2&S~#8^5(1>3_@hlF&c0OXK_xgq@xTP~CsaiSt(P9Chy) z!5&hFXnZK&Lz6^d888fW_DSEeHbF{wt@yl`Y=~q^-`DWJMC0OUQk-$z zP6yDmIm{D|$vs$MzKpf&d!78~Fq?QM^CrbZj0taoVN-9G^v|2xRkRpueavD^oF^DN z03muFNN|o(FiYD6Pt|gvK;z&3^Srs;_3ytA{(;s8T}98E`Eh(7*`RDTZd$e&cu0N= zR9SwINFdi+&qC@cXJ2_Y^ID69`?XbwG3zM|s5Zt69J9hn&2M3zauRNJyXMb(WykSG zs-c1Oc^+*3&$u1N_U&@}yl#i{xeV{OpKB#(mtk4gy>J4{Qij*BkG1gR aveZAW_}(wu-niVPxF9r#Generic Perfect Hash Generator +

Ilan Schnell, 2008 +

+

perfect_hash.py provides a perfect hash generator which is not language + specific. That is, the generator can output a perfect hash function for + a given set of keys in any programming language, this is achieved by + filling a given code template. +

+ +

Acknowledgments:

+

This code is derived from A. M. Kuchling's + Perfect Minimal Hash Generator. +

+ +

Introduction:

+

A perfect hash function of a certain set S of keys is a hash function + which maps all keys in S to different numbers. + That means that for the set S, + the hash function is collision-free, or perfect. + Further, a perfect hash function is called minimal when it maps n keys + to n consecutive integers, usually in the range from 0 to n-1. +

+

After coming across A. M. Kuchling's Perfect Minimal Hash Generator, + I decided to write a general tool for generating perfect hashes. + It is general in the sense that it can produce perfect hash functions + for almost any programming language. + A given code template is filled with parameters, + such that the output is code which implements the hash function. +

+

The algorithm the program uses is described in the paper + "Optimal algorithms for minimal perfect hashing", + Z. J. Czech, G. Havas and B.S. Majewski. +

+

I tried to illustrate the algorithm and explain how it works on + this page. +

+ +

Usage:

+

Given a set of keys which are ordinary character string, + the program returns a minimal perfect hash function. + This hash function is returned in the form of Python code by default. + Suppose we have a file with keys: +

+
# 'animals.txt'
+Elephant
+Horse
+Camel
+Python
+Dog
+Cat
+

The exact way this file is parsed can be specified using command line + options, for example it is possible to only read one column from a file + which contains different items in each row. + The program is invoked like this: +

+
# =======================================================================
+# ================= Python code for perfect hash function ===============
+# =======================================================================
+
+G = [0, 0, 4, 1, 0, 3, 8, 1, 6]
+
+S1 = [5, 0, 0, 6, 1, 0, 4, 7]
+S2 = [7, 3, 6, 7, 8, 5, 7, 6]
+
+def hash_f(key, T):
+    return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9
+
+def perfect_hash(key):
+    return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9
+
+# ============================ Sanity check =============================
+
+K = ["Elephant", "Horse", "Camel", "Python", "Dog", "Cat"]
+H = [0, 1, 2, 3, 4, 5]
+
+assert len(K) == len(H) == 6
+
+for k, h in zip(K, H):
+    assert perfect_hash(k) == h
+

The way the program works is by filling a code template with the calculated + parameters. The program can take such a template in form of a file and + fill in the calculated parameters, this allows the generation of perfect + hash function in any programming language. The hash function is kept quite + simple and does not require machine or language specific byte level operations + which might be hard to implement in the target language. + The following parameters are available in the template, and will expand to: +

+ + + + + + + + + + + +
stringexpands to
$NSthe length of S1 and S2
$S1array of integers S1
$S2array of integers S2
$NGlength of array G
$Garray of integers G
$NKthe number of keys, i.e. length of array K and H
$Karray with the quoted keys
$Harray of integer hash values
$$$ (a literal dollar sign)
+

A literal $ is escaped as $$. Since the syntax for arrays is not the + same in all programming languages, some specifics can be adjusted using + command line options. + The section of the built-in template which creates the actual hash function + is: +

+
G = [$G]
+
+S1 = [$S1]
+S2 = [$S2]
+
+def hash_f(key, T):
+    return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG
+
+def perfect_hash(key):
+    return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
+

Using code templates, makes this program very flexible. The package comes + with several complete examples for C and C++. There are many choices one + faces when implementing a static hash table: do the parameter lists go into + a separate header file, should the API for the table only contain the hash + values, but not the objects being mapped, and so on. + All these various choices are possible because of the template is simply + filled with the parameters, no matter what else is inside the template. +

+

Another possible use the program is as a python module. The functions and + classes in perfect_hash.py are documented and have clean interfaces. + The folder example-Python has examples which shows how the module + can be used directly in this way. +

+ +

Requirement:

+

Python 2.5 +

+ + diff --git a/components/rtgui/utils/perfect_hash/doc/doc.in b/components/rtgui/utils/perfect_hash/doc/doc.in new file mode 100644 index 0000000000..1bcce9a961 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/doc/doc.in @@ -0,0 +1,130 @@ + +Generic Perfect Hash Generator +------------------------------ + +*Ilan Schnell, 2008* + +perfect_hash.py provides a perfect hash generator which is not language +specific. That is, the generator can output a perfect hash function for +a given set of keys in any programming language, this is achieved by +filling a given code template. + +### Acknowledgments: + +This code is derived from A. M. Kuchling's +[Perfect Minimal Hash Generator](http://www.amk.ca/python/code/perfect-hash). + +### Introduction: + +A perfect hash function of a certain set S of keys is a hash function +which maps all keys in S to different numbers. +That means that for the set S, +the hash function is collision-free, or perfect. +Further, a perfect hash function is called minimal when it maps n keys +to n *consecutive* integers, usually in the range from 0 to n-1. + +After coming across A. M. Kuchling's Perfect Minimal Hash Generator, +I decided to write a general tool for generating perfect hashes. +It is general in the sense that it can produce perfect hash functions +for almost any programming language. +A given code template is filled with parameters, +such that the output is code which implements the hash function. + +The algorithm the program uses is described in the paper +["Optimal algorithms for minimal perfect hashing"] +(http://citeseer.ist.psu.edu/122364.html), +Z. J. Czech, G. Havas and B.S. Majewski. + +I tried to illustrate the algorithm and explain how it works on +[this page](http://ilan.schnell-web.net/prog/perfect-hash/algo.html). + +### Usage: + +Given a set of keys which are ordinary character string, +the program returns a minimal perfect hash function. +This hash function is returned in the form of Python code by default. +Suppose we have a file with keys: + + # 'animals.txt' + Elephant + Horse + Camel + Python + Dog + Cat + + +The exact way this file is parsed can be specified using command line +options, for example it is possible to only read one column from a file +which contains different items in each row. +The program is invoked like this: + + # ======================================================================= + # ================= Python code for perfect hash function =============== + # ======================================================================= + + G = [0, 0, 4, 1, 0, 3, 8, 1, 6] + + S1 = [5, 0, 0, 6, 1, 0, 4, 7] + S2 = [7, 3, 6, 7, 8, 5, 7, 6] + + def hash_f(key, T): + return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9 + + def perfect_hash(key): + return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9 + + # ============================ Sanity check ============================= + + K = ["Elephant", "Horse", "Camel", "Python", "Dog", "Cat"] + H = [0, 1, 2, 3, 4, 5] + + assert len(K) == len(H) == 6 + + for k, h in zip(K, H): + assert perfect_hash(k) == h + + +The way the program works is by filling a code template with the calculated +parameters. The program can take such a template in form of a file and +fill in the calculated parameters, this allows the generation of perfect +hash function in any programming language. The hash function is kept quite +simple and does not require machine or language specific byte level operations +which might be hard to implement in the target language. +The following parameters are available in the template, and will expand to: + +###### table + +A literal `$` is escaped as `$$`. Since the syntax for arrays is not the +same in all programming languages, some specifics can be adjusted using +command line options. +The section of the built-in template which creates the actual hash function +is: + + G = [$G] + + S1 = [$S1] + S2 = [$S2] + + def hash_f(key, T): + return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG + + def perfect_hash(key): + return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG + +Using code templates, makes this program very flexible. The package comes +with several complete examples for C and C++. There are many choices one +faces when implementing a static hash table: do the parameter lists go into +a separate header file, should the API for the table only contain the hash +values, but not the objects being mapped, and so on. +All these various choices are possible because of the template is simply +filled with the parameters, no matter what else is inside the template. + +Another possible use the program is as a python module. The functions and +classes in `perfect_hash.py` are documented and have clean interfaces. +The folder `example-Python` has examples which shows how the module +can be used directly in this way. + +### Requirement: + +Python 2.5 diff --git a/components/rtgui/utils/perfect_hash/doc/doc.txt b/components/rtgui/utils/perfect_hash/doc/doc.txt new file mode 100644 index 0000000000..f28dda0ed2 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/doc/doc.txt @@ -0,0 +1,141 @@ + +Generic Perfect Hash Generator +------------------------------ + +*Ilan Schnell, 2008* + +perfect_hash.py provides a perfect hash generator which is not language +specific. That is, the generator can output a perfect hash function for +a given set of keys in any programming language, this is achieved by +filling a given code template. + +### Acknowledgments: + +This code is derived from A. M. Kuchling's +[Perfect Minimal Hash Generator](http://www.amk.ca/python/code/perfect-hash). + +### Introduction: + +A perfect hash function of a certain set S of keys is a hash function +which maps all keys in S to different numbers. +That means that for the set S, +the hash function is collision-free, or perfect. +Further, a perfect hash function is called minimal when it maps n keys +to n *consecutive* integers, usually in the range from 0 to n-1. + +After coming across A. M. Kuchling's Perfect Minimal Hash Generator, +I decided to write a general tool for generating perfect hashes. +It is general in the sense that it can produce perfect hash functions +for almost any programming language. +A given code template is filled with parameters, +such that the output is code which implements the hash function. + +The algorithm the program uses is described in the paper +["Optimal algorithms for minimal perfect hashing"] +(http://citeseer.ist.psu.edu/122364.html), +Z. J. Czech, G. Havas and B.S. Majewski. + +I tried to illustrate the algorithm and explain how it works on +[this page](http://ilan.schnell-web.net/prog/perfect-hash/algo.html). + +### Usage: + +Given a set of keys which are ordinary character string, +the program returns a minimal perfect hash function. +This hash function is returned in the form of Python code by default. +Suppose we have a file with keys: + + # 'animals.txt' + Elephant + Horse + Camel + Python + Dog + Cat + + +The exact way this file is parsed can be specified using command line +options, for example it is possible to only read one column from a file +which contains different items in each row. +The program is invoked like this: + + # ======================================================================= + # ================= Python code for perfect hash function =============== + # ======================================================================= + + G = [0, 0, 4, 1, 0, 3, 8, 1, 6] + + S1 = [5, 0, 0, 6, 1, 0, 4, 7] + S2 = [7, 3, 6, 7, 8, 5, 7, 6] + + def hash_f(key, T): + return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9 + + def perfect_hash(key): + return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9 + + # ============================ Sanity check ============================= + + K = ["Elephant", "Horse", "Camel", "Python", "Dog", "Cat"] + H = [0, 1, 2, 3, 4, 5] + + assert len(K) == len(H) == 6 + + for k, h in zip(K, H): + assert perfect_hash(k) == h + + +The way the program works is by filling a code template with the calculated +parameters. The program can take such a template in form of a file and +fill in the calculated parameters, this allows the generation of perfect +hash function in any programming language. The hash function is kept quite +simple and does not require machine or language specific byte level operations +which might be hard to implement in the target language. +The following parameters are available in the template, and will expand to: + + string | expands to + --------+-------------------------------- + $NS | the length of S1 and S2 + $S1 | array of integers S1 + $S2 | array of integers S2 + $NG | length of array G + $G | array of integers G + $NK | the number of keys, i.e. length of array K and H + $K | array with the quoted keys + $H | array of integer hash values + $$ | $ (a literal dollar sign) + + +A literal '$' is escaped as '$$'. Since the syntax for arrays is not the +same in all programming languages, some specifics can be adjusted using +command line options. +The section of the built-in template which creates the actual hash function +is: + + G = [$G] + + S1 = [$S1] + S2 = [$S2] + + def hash_f(key, T): + return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG + + def perfect_hash(key): + return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG + +Using code templates, makes this program very flexible. The package comes +with several complete examples for C and C++. There are many choices one +faces when implementing a static hash table: do the parameter lists go into +a separate header file, should the API for the table only contain the hash +values, but not the objects being mapped, and so on. +All these various choices are possible because of the template is simply +filled with the parameters, no matter what else is inside the template. + +Another possible use the program is as a python module. The functions and +classes in 'perfect_hash.py' are documented and have clean interfaces. +The folder 'example-Python' has examples which shows how the module +can be used directly in this way. + +### Requirement: + +Python 2.5 diff --git a/components/rtgui/utils/perfect_hash/doc/mktable.py b/components/rtgui/utils/perfect_hash/doc/mktable.py new file mode 100644 index 0000000000..ef304ed673 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/doc/mktable.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import re + +def convert(line, head = False): + pat = re.compile(r'([$]\S*)') + line = pat.sub(r'\1', line) + + row = [x.strip() for x in line.split('|')] + fmt = ' %s%s' + if head: + fmt = fmt.replace('td', 'th') + print fmt % tuple(row) + + +f = file('parameters.txt') + +print '' +convert(f.readline(), head = True) +f.readline() +for line in f: + convert(line) +print '
' diff --git a/components/rtgui/utils/perfect_hash/doc/parameters.txt b/components/rtgui/utils/perfect_hash/doc/parameters.txt new file mode 100644 index 0000000000..b853492659 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/doc/parameters.txt @@ -0,0 +1,11 @@ + string | expands to + --------+-------------------------------- + $NS | the length of S1 and S2 + $S1 | array of integers S1 + $S2 | array of integers S2 + $NG | length of array G + $G | array of integers G + $NK | the number of keys, i.e. length of array K and H + $K | array with the quoted keys + $H | array of integer hash values + $$ | $ (a literal dollar sign) diff --git a/components/rtgui/utils/perfect_hash/example-C++/Makefile b/components/rtgui/utils/perfect_hash/example-C++/Makefile new file mode 100644 index 0000000000..de525f5d5d --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/Makefile @@ -0,0 +1,31 @@ + +CXX = g++ -Wall + + +lookup: main.o states-code.o + $(CXX) -o $@ $^ + + +main.o: main.cc states-code.hh + $(CXX) -c $< + + +states-code.o: states-code.cc states-code.hh states.dat.h + $(CXX) -c $< + + +states-code.cc: states.dat states-tmpl.cc states-code.hh + ../perfect_hash.py --splitby '|' --keycol 2 states.dat states-tmpl.cc + + +states.dat.h: states.dat + ./mk_header.py >$@ + + +clean: + rm lookup *.o states.dat.h states-code.cc + + +test: + ./lookup 'NY' + ./lookup 'QW' diff --git a/components/rtgui/utils/perfect_hash/example-C++/main.cc b/components/rtgui/utils/perfect_hash/example-C++/main.cc new file mode 100644 index 0000000000..9d724a7872 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/main.cc @@ -0,0 +1,24 @@ + +#include +#include +using namespace std; + +#include "states-code.hh" + + +int main (int argc, char *argv[]) +{ + if (argc != 2) { + printf ("Usage: %s \n", argv[0]); + return 2; + } + + string abbr = argv[1]; + + State s(abbr); + + cout << "The state of " << s.name () + << " has a population of " << 1e-6 * s.population () << " million.\n"; + + return 0; +} diff --git a/components/rtgui/utils/perfect_hash/example-C++/mk_header.py b/components/rtgui/utils/perfect_hash/example-C++/mk_header.py new file mode 100644 index 0000000000..646c0787be --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/mk_header.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +for line in file('states.dat'): + line = line.strip() + if line.startswith('#'): + continue + + row = tuple(entry.strip() for entry in line.split('|')) + + print ' { "%s", "%s", %s },' % row diff --git a/components/rtgui/utils/perfect_hash/example-C++/states-code.hh b/components/rtgui/utils/perfect_hash/example-C++/states-code.hh new file mode 100644 index 0000000000..964d8bf8a5 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/states-code.hh @@ -0,0 +1,19 @@ + + +#include +using namespace std; + + +class State +{ +public: + State (const string abbr); + + string name () const { return nam; }; + int population () const { return pop; }; + +private: + string nam; + int pop; +}; + diff --git a/components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc b/components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc new file mode 100644 index 0000000000..ab94be31f6 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc @@ -0,0 +1,55 @@ + +#include + +#include + +#include "states-code.hh" + +static struct { + char *name; + char *abbr; + int pop; +} states[$NK] = { +#include "states.dat.h" +}; + +static int T1[] = { $S1 }; + +static int T2[] = { $S2 }; + +static int G[] = { $G }; + +static int hash_g (const char *key, const int *T) +{ + int i, sum = 0; + + for (i = 0; key[i] != '\0'; i++) { + sum += T[i] * key[i]; + sum %= $NG; + } + return G[sum]; +} + +static int perfect_hash (const char *key) +{ + if (strlen (key) > $NS) + return 0; + + return (hash_g (key, T1) + hash_g (key, T2)) % $NG; +} + +State::State (const string abbr) +{ + int hash_value = perfect_hash (abbr.c_str ()); + + if (hash_value < $NK && + strcmp(abbr.c_str (), states[hash_value].abbr) == 0) + { + nam = states[hash_value].name; + pop = states[hash_value].pop; + } + else + { + cerr << "'" << abbr << "' is not an abbreviation for a state\n"; + } +} diff --git a/components/rtgui/utils/perfect_hash/example-C++/states.dat b/components/rtgui/utils/perfect_hash/example-C++/states.dat new file mode 100644 index 0000000000..5538309450 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-C++/states.dat @@ -0,0 +1,52 @@ +# Name | Abr | Population +#--------------+------+--------- +Alabama | AL | 4335400 +Alaska | AK | 611500 +Arizona | AZ | 4664600 +Arkansas | AR | 2531000 +California | CA | 33198100 +Colorado | CO | 3930700 +Connecticut | CT | 3271100 +Delaware | DE | 736900 +Florida | FL | 15012200 +Georgia | GA | 7562200 +Hawaii | HI | 1188400 +Idaho | ID | 1221500 +Illinois | IL | 11981700 +Indiana | IN | 5882500 +Iowa | IA | 2854700 +Kansas | KS | 2603200 +Kentucky | KY | 3921000 +Louisiana | LA | 4361200 +Maine | ME | 1243700 +Maryland | MD | 5122400 +Massachusetts | MA | 6133500 +Michigan | MI | 9825100 +Minnesota | MN | 4704200 +Mississippi | MS | 2739700 +Missouri | MO | 5421400 +Montana | MT | 886400 +Nebraska | NE | 1661400 +Nevada | NV | 1828700 +New Hampshire | NH | 1179100 +New Jersey | NJ | 8078300 +New Mexico | NM | 1738700 +New York | NY | 18197800 +North Carolina | NC | 7483100 +North Dakota | ND | 640000 +Ohio | OH | 11197900 +Oklahoma | OK | 3328100 +Oregon | OR | 3266800 +Pennsylvania | PA | 12044200 +Rhode Island | RI | 987000 +South Carolina | SC | 3781800 +South Dakota | SD | 738500 +Tennessee | TN | 5398200 +Texas | TX | 19274300 +Utah | UT | 2071500 +Vermont | VT | 590400 +Virginia | VA | 6768400 +Washington | WA | 5674900 +West Virginia | WV | 1813200 +Wisconsin | WI | 5224500 +Wyoming | WY | 479500 diff --git a/components/rtgui/utils/perfect_hash/example-PyModule/Makefile b/components/rtgui/utils/perfect_hash/example-PyModule/Makefile new file mode 100644 index 0000000000..662ff78442 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-PyModule/Makefile @@ -0,0 +1,26 @@ + + +CC = gcc -Wall + + +stations.so: stationsmodule.c stations.dat.h stations-code.h + $(CC) -shared -fPIC -I/usr/local/include/python2.5 \ + -o stations.so stationsmodule.c + + +stations.dat.h: stations.dat + sed <$< >$@ -e 's:\([^,]*\),\([^,]*\): { "\1", "\2" },:' + + +stations-code.h: stations.dat stations-tmpl.h + ../perfect_hash.py --trails 2 $^ + + +clean: + rm stations-code.h stations.dat.h stations.so + + +test: + python -c "import stations; print stations.locator('DL5BAC')" + + diff --git a/components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h b/components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h new file mode 100644 index 0000000000..b77e6320b3 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h @@ -0,0 +1,12 @@ + +#define NK $NK /* number of keys */ +#define NG $NG /* number of vertices */ +#define NS $NS /* elements in T */ + + +int G[] = { $G }; + +int T1[] = { $S1 }; + +int T2[] = { $S2 }; + diff --git a/components/rtgui/utils/perfect_hash/example-PyModule/stations.dat b/components/rtgui/utils/perfect_hash/example-PyModule/stations.dat new file mode 100644 index 0000000000..5358120c34 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-PyModule/stations.dat @@ -0,0 +1,500 @@ +DL0WM,JO40HM +DM4WDK,JO50OI +M0GHZ,IO81VK +ON2CP,JO21IG +PI4UTR,JO22MC +DO2YMH,JO41AT +ON1GZ,JO20FW +DL5QQ,JO32KB +M0HKB,JO02OB +ON4LBT,JO10WK +SM7VTW,JO65QQ +PA3AYD,JO21UU +DO3LTK,JO43XS +DC0NAC,JO43VI +PD0LQQ,JO20VS +DO1YMJ,JO31WS +DL1EJL,JO31FS +DG3TF,JO53IU +ON1AEN,JO10VW +DL1KDA,JO30FQ +SM7LHI,JO65PO +DG1EIP,JO31JL +PD1AKT,JO22TA +DN1GSK,JO62NL +OQ1AEN,JO10VW +DG9YIH/M,JO31TR +G0UYC,JO02MR +F1PGL,JO20IE +DO1KNB,JO30NQ +DL5NEN,JN59OP +DL1RNO,JO62FK +DO8EF,JO31KK +DL6IY,JN49NI +ON4NOK,JO21LO +DO9MH,JO33QO +PA0PTS,JO23TF +G5LK,IO91SK +DJ6XV,JO31LQ +ON4ARF,JO10MV +PE1OJB,JO22IN +DH1BBO,JO42FS +M1DNJ,JO01GJ +PA0BVD,JO23TF +ON1CJQ,JO10OV +DL2NFX,JN59JU +DL4HG,JO53CM +DG3BEO,JO43JF +OZ4EDR,JO75JF +DD1LT/P,JO44TK +G4OXD,IO91UW +DG1KZF,JO31RN +DO2YPB,JO41JR +DO3JJ,JO31QM +DO5YLM,JO42GA +DL2IAN,JN49BC +PA0ME,JO22OB +DC5PN,JN49HV +PA9JP,JO32MS +PD5RD,JO21IT +PE1PQV,JO32JG +OZ3TT,JO66CB +DO9KS,JO43CE +DJ8MS/P,JO63CT +ON4KBE,JO20BI +PE1JVV,JO21GV +DH0EAQ,JO31IK +DG9RCI,JN59PH +DO6UWE/P,JO31OI +DB7LG,JO44TH +DD5JK,JO31RO +DG6LSW,JO44SP +M1MGD,IO91VC +DL6YAU,JO44PJ +PE1OLM,JO23TF +DG0DRF,JO71JJ +DG3YCB,JO41KV +DF7JS,JO31JM +OZ2NAC,JO55RT +DJ5JD,JO33OO +PA3DHR,JO21DU +PE2JMR,JO33HG +OZ1XAT/A,JO55UL +PA3GKH,JO32HK +G4DCJ,JO02IT +DL4NAC,JN59SV +DF0DS,JO31RM +GW7SMV,IO81LN +DO1AYJ,JO50SU +DL0BAC,JO30BS +DL0JRR,JO31CT +OZ7HAM,JO65CL +DK0ALK,JN38TD +DO6DIB,JO43DA +PA3GTC,JO32LR +DD1LI,JO43WO +DG9ACT/P,JO42QH +PE1PMG,JO31BH +SK7OL,JO66NC +DH0JB,JO31CH +OQ1ARQ,JO10VX +DD7ZT,JO40DH +DL1JJ,JO31IA +DL1EEX,JO31MA +ON4CDF,JO21EE +DL0SE,JO31PG +DO3YY,JO31QM +DK0HC,JO40OQ +DC8BQ,JO31KE +DG1LAR,JO43UP +OZ/DL0IZ/P,JO45GD +DG3TD,JO44GQ +DL6OBH,JO42QI +PA0JCS,JO21DN +DG0OJG,JO50MX +DO1KFB,JO30CS +SM60EW,JO67DA +G4MRS/P,JO01MU +DL5DBM,JO32WO +DK3BM,JO42LH +DD9DV,JO31TO +DO1DQ,JO31TL +OZ5AEK,JO55XO +DG1YAR,JO41CR +OO6LY,JO21LH +DL1PR,JO30JS +DL5ZAB,JO40HC +DO1MGN,JO50DO +SM7UPF,JO65TO +DO1NNN,JO50VF +DK5BD,JO42IX +DL3OCA,JO42VH +HB9MPX,JN47RJ +DG4KAS,JO30DU +DF1UF,JN49HK +DC6GF/P,JN47NX +DG7ES,JN68GI +DF0NF,JO44UH +DG8EKI,JO31MI +OZ9CLN,JO56CE +SK7MW,JO65MJ +DL9ECA,JO31CQ +DF9IC,JN48IW +PD9FJ,JO23KE +DL4LBO,JO43XT +DF0WD,JO42FD +DH4PSG,JO31NN +LA0BY,JO59IX +DJ5FK,JO42SH +DO1ASM,JO50LQ +DL9KCM,JO30IS +DG6MBS,JO41AH +OZ2SYV,JO54RS +DL0HMS,JO42MC +DL2PZ,JN49DW +DG5NEP/P,JO50VF +SM6VKC,JO68CG +DF8AA/P,JO71AA +PA1WM,JO21WW +DO3BTL,JO43HB +PA3GGN,JO21LU +DF1VW,JN39HJ +DJ5KX,JO30PQ +ON1LPA,JO20XO +DJ5QW,JO32SF +G4AJC,IO91VJ +OZ7P,JO45SQ +G4MRS,JO02PB +PD0ZX,JO22QF +DB5BR,JO42FS +DO1JRA,JO42GF +DL1DUF,JO62EJ +DO2NHD,JO40MB +DG6DDE,JO31UM +PA3FBP,JO33GB +DC1GUN,JN68GG +DO2BO,JO33RM +OZ6AQ,JO44UX +OZ1QQ,JO47XG +DG1YBT,JO32QD +DL9YEY,JO41GV +DG1YIV,JO42HF +DB2WD,JN39VV +DF0UKW,JN49HN +OZ1BEF/P,JO46SB +PE1ISU,JO21WD +DO1KOH,JO30HR +DK9SS,JN48OM +PE1OPK,JO23UE +DG3GAQ,JN48GE +DO2FX,JO40LH +SK7BT,JO65MO +OZ1FHU,JO55SR +SK6QW,JO68WR +DL4FBN,JO30WC +DG3FCT,JO41RB +OE2SCM,JN67OV +PA0ZM,JO32GK +DL0MQ,JO41EV +DB3WR,JO31DG +ON2BFV,JO11XA +DJ5DM,JO31FF +G6FPQ,IO91XI +DJ0VZ,JO30GL +OO2WIM,JO20OR +DG7RZ/P,JN59WK +DL5QN,JO42HC +DC9XX,JO43QR +SM7SLU,JO65ML +F1PYW,JN38UP +DG2NJ,JN68OL +DJ5KM,JO42GA +DL3TS,JO30PX +DG4YIE/P,JO41PU +DL0RSH,JO43SV +PE1RYU,JO21GU +DJ3QB,JO32MF +DG4KBY/P,JO42CW +PA3GSX,JO32DM +DG1YRT,JO41KW +DG9BEY,JO42AH +PA3EXO,JO32GW +PE1OPH,JO22XF +DO9FB,JN49BP +F0EUE,JN29VM +G4RRA/P,IO70XR +DL0EDD,JO31IF +SM7MRL,JO66KC +DK5JM,JO43QS +DJ3NU,JO31SL +DH6YMC,JO32MF +DL1DAX,JO31RM +DC4KM,JO30XO +F1TUE,JN38DR +DO4ME,JO43KC +ON7CC,JO10XM +DL1PBC,JO30VJ +DL3IAE,JN49DE +DL1SDN,JN48PP +DL4ANT,JN49LF +DH1NHI,JO50VF +DO1BR,JO42AE +G4ODA,IO92WS +DB2DJ,JO31RM +DL8LAH,JO44QQ +DH9NBB,JN49WS +F1LPV,JO10NP +DL3SF,JO32MF +SM7VXT,JO65NU +DL4LCA/P,JO44XF +DL3FDL,JO40KR +SM7XEN,JO65RL +DL6ABO,JO52GH +EI7IW,IO63SS +DC1QU,JO31TW +DG0OCW,JO50CT +SM7XWM,JO86AJ +ON2MRT,JO20MX +DA0GSN,JO31HB +DL8FBC,JO41UF +F1DBN/P,JO00WT +DJ6CB,JO42JW +DL1SUZ,JO53UN +DJ5NU,JO31QH +DL0SOP,JO54WC +DO1MGN/P,JO50AN +OK1BYR,JN79IP +PD0RAA,JO22WK +DJ9DL,JO31NC +DK5WO,JO30AS +OZ8FYN,JO55EJ +DO1FDR,JO41PD +ON2BIV,JO10RX +ON4AEO,JO10OW +DL4MB,JN49FA +GW4HBZ/P,IO83GC +OZ1BEF,JO46OE +PE0NYJ,JO21VT +DO3LBP,JO43MW +DB3BW,JO42AC +DF6YL,JO31WS +DP0RFU,JO32LS +DF4BV,JO43RH +DJ6GV,JO52HG +DG7KAQ,JO30FS +DH1YPH,JO31VL +SM7JUQ,JO65PO +DG7ACF,JO42UI +DG6NBL,JN59LL +OK1MCS,JN69QR +DL1REM,JO32MF +DN1RDT,JN59WK +OZ3FYN/P,JO55BJ +DB0GSN,JO31JC +DC1GUN/P,JN68GI +DJ1DH/P,JO53BG +DO1RSG/P,JN68KX +PD0FFU,JO20UU +DO8DW,JO31SO +DL8II,JN49GP +PA3DRL,JO21PS +DG8LG,JO44VP +PD0EBF,JO21LQ +OZ9BO,JO46HE +DO3NML,JN59SV +DJ3BP,JO42CX +F6IRS,JN38VN +F5SMZ,JN39EJ +GM1TDU,IO87WE +DL5BAC,JO43LG +DO7OCH,JO51AT +DL1HRY,JO61AD +DK7VA,JO32MK +SM7JPI,JO75DW +DL0GC,JO31CQ +M1IFT,IO93NL +DF5AY,JN49DX +DG1IHH,JN49GJ +DO5BRH,JO43CE +DK6AJ,JO52GH +DL0NF,JN59PL +DG1BHM,JO43PC +DK3RV,JO31DG +DD8EI,JO31NC +PD2PL,JO22HD +DL0GL,JO31LN +DC1PJA,JN49DV +PD2GCM,JO21ET +SI7GM,JO65MO +DG6MOG,JO52XN +OQ4CJU,JO20PS +DG1DPN,JO31RL +DK0BA,JO43NF +DL2HQ,JN48FX +PA4PS,JO33GH +DK0EE,JN58TG +DD9PL,JN49CN +PB0AOK,JO32IH +DC2OOO,JN39NI +DL0NS,JO31IE +ON4BAK,JO31PA +G4DCV,IO91OF +DG4FFF,JO40FA +G3BNE,JO01BJ +DO2GN,JO31PM +DD7PA/P,JN49LM +OZ0A/P,JO55UL +DL8BEV,JO43JH +DJ8UV,JO31OF +PE1PMV,JO32JG +DL8AX,JO31ID +PE1RER,JO22SA +PD0RKC,JO33AD +DC4ASK,JO31MI +DG1YCF,JO42KH +SK7PL,JO76DJ +M1MHZ,IO92WV +DF9PX/P,JO30JF +DG0OZ,JO50LU +DB1BMN/P,JO43HA +DH2UD/P,JO44XS +OZ5AGJ,JO56DF +OZ3AEV,JO55WR +PA1JAN,JO32KV +PE7MO,JO32KR +LA7M,JO48KK +PA1TX,JO32JG +OZ7DAL,JO56IE +PE1PED,JO22QE +DL0WH,JN49HN +DL9KI,JO42GE +M0AIJ,IO92PA +DG0CAL/P,JO31BC +DG1YFF,JO42IG +OZ4DR,JO55WL +G8RWG,JO01BN +OZ3RIN,JO55VK +SM7VXS,JO65UV +DL9EBI,JO31IE +PD5FDV,JO21HV +DL5XB,JO43UL +DJ9IQ,JO30OI +PE1NNX,JO22JN +DB2YC,JO32OF +PA5WT,JO22HG +DO2PK,JO41NW +PE1BVW,JO21DO +DL0TS,JO40FC +DB9KR,JO41DQ +DO1ZB,JO64II +DO4YPM,JO32QI +G0VJG,JO01BL +DD2YCS,JO43FE +DO7MH,JO31MT +G3JHM,IO91LC +DL8FAJ,JO51AD +DG4FR,JO31OJ +ON1DNF,JO20NU +DO4FMK,JO40MF +PI4THT,JO32KF +DK4LI,JO44WQ +DD3FU,JO40IE +DF1LON/P,JO31LH +DL2ARD/P,JO60AR +DH9YBC,JO42HE +G3OHC,IO93KS +DK0HF,JO42IF +DF6QB,JO31WW +DO3HN,JO31LK +M3RCV,JO01AL +DL0SAT,JO41XO +DD7PC,JN49AX +DL2LSM,JO61HH +PA3HHT,JO22QC +PD2OPA,JO21BT +DL0VR,JO31MI +EI3GE,IO63XD +DF9CY,JO54AL +DL1AH,JO42TX +DL1PW,JN49DV +DC9CZ,JO42GA +PA3FJY/P,JO32FI +DG5BGB,JO43HB +ON7LAO,JO20CK +DG0SY,JO54VC +DK5KC,JO30DS +DG6YJ,JO32RB +OO4BAX,JO21IH +DO1LNK,JO53EK +DJ3LE,JO44SK +DO1YCI,JO31NO +DJ8TA,JO41BU +DL8BAV,JO43MF +DO1RSG,JN68ET +DO1PIA,JO31PM +DL1AUW/P,JO51CH +DL0VV,JO64AD +DL3JAN/P,JO60KS +ON50ZTM,JO10UV +PA3GHZ,JO21OI +DL2SDU,JN48XT +DG4YFT,JO31OR +G0UIQ,JO02PW +DF9PX,JN49HU +DG8FAY,JO40GD +DL9LBH,JO30MP +DG5YHK,JO31SR +DC2GY/P,JN48DS +PE1PZS,JO21DV +ON4PS,JO20KQ +PE1PWM,JO22FE +DL2VB/P,JO31KP +DG8BX/P,JO43NA +DK4FG,JO40EM +DO8BAF/P,JN59WK +OK1MSM/P,JN69PR +DC2GY,JN48BQ +DK2LR,JN57KO +DH3UN,JO31TL +DF0SB,JN48GE +ON4CBR,JO10OU +DB3VE,JN39KK +DO2YTM,JO42GA +DJ9CN,JO43DA +M3HKK/P,JO01BB +DK8ZB,JN49KW +DC2AM,JO43WL +DF7KF,JO30GU +DC7KG,JO30LW +SK7CY,JO65RJ +DH6OBN/P,JO42UJ +SK7HR,JO77HM +ON4BAR,JO10MV +DH8OH,JO51AT +DL5OAK,JO52AK +DG1DX,JO31SL +DL0HEU,JN47NX +DL1FX,JN49HS +DN1BE,JO42AH +G4ZTR,JO01KW +DG3YY,JO31QM +DK4WH/P,JN49BH +OK1UEM,JO60TH +PE1LWJ,JO22VJ +OZ0XX,JO54RS +DO1ON,JO51HR +DK0DH,JO31QL +DJ9JY,JO31JM +DG1FDX,JN49LP +DG0CCD,JO52TC +DL5NAV,JO33TF +DL4KCA,JO31JX +DG6NDK,JN59GN +DO9BC,JN48QP +DK1HW,JO42TG +DC4MP,JO31MI +ON4CIN,JO11UB +LA2CFA,JO48JL +DH2SAV,JN48QU +PE1ONM,JO32KR +M5AEH,IO93BS diff --git a/components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c b/components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c new file mode 100644 index 0000000000..bf14e1bbee --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c @@ -0,0 +1,69 @@ + +#include + +#include "stations-code.h" + +static struct { + char *callsign; + char *locator; +} station_list[] = { +#include "stations.dat.h" +}; + +static int hash_f (const char *s, const int *T) +{ + register int i, sum = 0; + + for (i = 0; s[i] != '\0'; i++) { + sum += T[i] * s[i]; + sum %= NG; + } + return sum; +} + +static int perf_hash (const char *k) +{ + if (strlen (k) > NS) + return 0; + + return (G[ hash_f(k, T1) ] + G[ hash_f(k, T2)] ) % NG; +} + +static int getlocator (char *locator, const char *callsign) +{ + int hashval = perf_hash (callsign); + + if (hashval < NK && strcmp(callsign, station_list[hashval].callsign) == 0) { + strcpy (locator, station_list[hashval].locator); + return 1; + } + return 0; +} + +static PyObject * +stations_locator(PyObject *self, PyObject *args) +{ + const char *callsign; + char locator[6]; + + if (!PyArg_ParseTuple(args, "s", &callsign)) + return NULL; + + return Py_BuildValue("s", (getlocator (locator, callsign) == 1) ? + locator : NULL); +} + +static PyMethodDef StationsMethods[] = { + + {"locator", stations_locator, METH_VARARGS, + "Get locator from callsign."}, + + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +PyMODINIT_FUNC +initstations(void) +{ + (void) Py_InitModule("stations", StationsMethods); +} diff --git a/components/rtgui/utils/perfect_hash/example-PyModule/test.py b/components/rtgui/utils/perfect_hash/example-PyModule/test.py new file mode 100644 index 0000000000..02c06b6926 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-PyModule/test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +import sys +from timeit import Timer +from stations import locator + +call = sys.argv[1] +print repr(call) +D = {} + +for line in file('stations.dat'): + c, l = [x.strip() for x in line.split(',')] + D[c] = l + +def test1(c): + return D[c] + +print repr(test1(call)) +t = Timer("test1(%r)" % call, "from __main__ import test1") +print t.timeit() + +# ----- + +def test2(c): + return locator(c) + +print repr(test2(call)) +t = Timer("test2(%r)" % call, "from __main__ import test2") +print t.timeit() diff --git a/components/rtgui/utils/perfect_hash/example-Python/Graph.py b/components/rtgui/utils/perfect_hash/example-Python/Graph.py new file mode 100644 index 0000000000..f2927719b4 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-Python/Graph.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +""" +This example shows how to use the class Graph. + +The class implements a graph with 'N' vertices. First, you connect the +graph with edges, which have a desired value associated. Then the vertex +values are assigned, which will fail if the graph is cyclic. The vertex +values are assigned such that the two values corresponding to an edge add +up to the desired edge value (mod N). +""" +import sys + +sys.path.append('..') +from perfect_hash import Graph + +G = Graph(3) +assert G.assign_vertex_values() == True + +# Now we make an edge between vertex 0 and 1 with desired edge value 2: +G.connect(0, 1, 2) + +# Make another edge 1:2 with desired edge value 1: +G.connect(1, 2, 1) + +# The graph is still acyclic, and assigning values works: +assert G.assign_vertex_values() == True +assert G.vertex_values == [0, 2, 2] + +# What do these values mean? +# When you add the values for edge 0:1 you get 0 + 2 = 2, as desired. +# For edge 1:2 you add 2 + 2 = 4 = 1 (mod 3), as desired. + +# Adding edge 0:2 produces a loop, so the graph is no longer acyclic. +# Assigning values fails. +G.connect(0, 2, 0) + +assert G.assign_vertex_values() == False + + +print 'OK' diff --git a/components/rtgui/utils/perfect_hash/example-Python/Makefile b/components/rtgui/utils/perfect_hash/example-Python/Makefile new file mode 100644 index 0000000000..4f6dd13850 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-Python/Makefile @@ -0,0 +1,15 @@ + + +all: + true + + +clean: + true + + +test: + ./generate_hash.py + ./PerfHash.py + ./Graph.py + diff --git a/components/rtgui/utils/perfect_hash/example-Python/PerfHash.py b/components/rtgui/utils/perfect_hash/example-Python/PerfHash.py new file mode 100644 index 0000000000..49131c2b63 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-Python/PerfHash.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +""" +This example shows how to use the class PerfHash. + +This class is designed for creating perfect hash tables at run time, +which should be avoided, in particulat inserting new keys is +prohibitively expensive since a new perfect hash table needs to be +constructed. However, this class can be usefull for testing. + +For practical programming purposes in Python the class PerfHash +should never be used because Python's built-in dictionary is very +efficient and always faster than PerfHash. +""" + +import sys + +sys.path.append('..') +from perfect_hash import PerfHash + + +month = dict(zip('jan feb mar apr may jun jul aug sep oct mov dec'.split(), + range(1, 13))) + +d = PerfHash(month) + + +for m in month: + assert month[m] == d[m] + +d[True] = False + +assert d[True] == False + +for i in xrange(10): # very expensive + d[i] = 2*i*i + 3*i -7 + +assert d[4] == 37 + + +print 'OK' diff --git a/components/rtgui/utils/perfect_hash/example-Python/generate_hash.py b/components/rtgui/utils/perfect_hash/example-Python/generate_hash.py new file mode 100644 index 0000000000..dfe9f92186 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example-Python/generate_hash.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +""" +This example shows how to use the function generate_hash. + +generate_hash(kdic, Hash) + +returns hash functions f1 and f2, and G for a perfect minimal hash. +Input is dictionary 'kdic' with the keys and desired hash values. +'Hash' is a random hash function generator, that means Hash(N) returns a +returns a random hash function which returns hash values from 0..N-1. +""" + +import sys +import random, string + +sys.path.append('..') +from perfect_hash import generate_hash + + + +month = dict(zip('jan feb mar apr may jun jul aug sep oct mov dec'.split(), + range(1, 13))) + +def mkRandHash(N): + """ + Return a random hash function which returns hash values from 0..N-1. + """ + junk = "".join(random.choice(string.letters + string.digits) + for i in xrange(10)) + return lambda key: hash(junk + str(key)) % N + + +f1, f2, G = generate_hash(month, mkRandHash) + +for k, h in month.items(): + assert h == ( G[f1(k)] + G[f2(k)] ) % len(G) + +print 'OK' diff --git a/components/rtgui/utils/perfect_hash/example1-C/Makefile b/components/rtgui/utils/perfect_hash/example1-C/Makefile new file mode 100644 index 0000000000..59b7ef0d67 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/Makefile @@ -0,0 +1,31 @@ + +CC = gcc -Wall + + +lookup: main.o states-code.o + $(CC) -o $@ $^ + + +main.o: main.c states-code.h states.dat.h + $(CC) -c $< + + +states-code.o: states-code.c states-code.h + $(CC) -c $< + + +states-code.c: states.dat states-tmpl.c + ../perfect_hash.py -vvvv --splitby '|' --keycol 2 $^ + + +states.dat.h: states.dat + ./mk_header.py >$@ + + +clean: + rm lookup *.o states.dat.h states-code.c + + +test: + ./lookup 'NY' + ./lookup 'QW' diff --git a/components/rtgui/utils/perfect_hash/example1-C/main.c b/components/rtgui/utils/perfect_hash/example1-C/main.c new file mode 100644 index 0000000000..0d36bcea45 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/main.c @@ -0,0 +1,33 @@ + +#include + +#include "states-code.h" + +struct { + char *name; + char *abbr; + int pop; +} states[] = { +#include "states.dat.h" +}; + + +int main (int argc, char *argv[]) +{ + if (argc != 2) { + printf ("Usage: %s \n", argv[0]); + return 2; + } + + char *abbr = argv[1]; + int hashval; + + if ((hashval = has_key(abbr)) == -1) + printf ("'%s' is not an abbreviation for a state.\n", abbr); + else + printf ("The state of %s has a population of %g million.\n", + states[hashval].name, + 1e-6 * states[hashval].pop); + + return 0; +} diff --git a/components/rtgui/utils/perfect_hash/example1-C/mk_header.py b/components/rtgui/utils/perfect_hash/example1-C/mk_header.py new file mode 100644 index 0000000000..646c0787be --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/mk_header.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +for line in file('states.dat'): + line = line.strip() + if line.startswith('#'): + continue + + row = tuple(entry.strip() for entry in line.split('|')) + + print ' { "%s", "%s", %s },' % row diff --git a/components/rtgui/utils/perfect_hash/example1-C/states-code.h b/components/rtgui/utils/perfect_hash/example1-C/states-code.h new file mode 100644 index 0000000000..5717b92d32 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/states-code.h @@ -0,0 +1,6 @@ + + +/* Return hash value of abbreviation 'abbr' if found, -1 otherwise */ +int has_key (const char *abbr); + + diff --git a/components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c b/components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c new file mode 100644 index 0000000000..001ca6e5ce --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c @@ -0,0 +1,42 @@ + +#include + +#include "states-code.h" + + +static int T1[] = { $S1 }; + +static int T2[] = { $S2 }; + +static int G[] = { $G }; + +static char *K[] = { $K }; + +static int hash_g (const char *key, const int *T) +{ + int i, sum = 0; + + for (i = 0; key[i] != '\0'; i++) { + sum += T[i] * key[i]; + sum %= $NG; + } + return G[sum]; +} + +static int perfect_hash (const char *key) +{ + if (strlen (key) > $NS) + return 0; + + return (hash_g (key, T1) + hash_g (key, T2)) % $NG; +} + +int has_key (const char *abbr) +{ + int hash_value = perfect_hash (abbr); + + if (hash_value < $NK && strcmp(abbr, K[hash_value]) == 0) + return hash_value; + + return -1; +} diff --git a/components/rtgui/utils/perfect_hash/example1-C/states.dat b/components/rtgui/utils/perfect_hash/example1-C/states.dat new file mode 100644 index 0000000000..5538309450 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example1-C/states.dat @@ -0,0 +1,52 @@ +# Name | Abr | Population +#--------------+------+--------- +Alabama | AL | 4335400 +Alaska | AK | 611500 +Arizona | AZ | 4664600 +Arkansas | AR | 2531000 +California | CA | 33198100 +Colorado | CO | 3930700 +Connecticut | CT | 3271100 +Delaware | DE | 736900 +Florida | FL | 15012200 +Georgia | GA | 7562200 +Hawaii | HI | 1188400 +Idaho | ID | 1221500 +Illinois | IL | 11981700 +Indiana | IN | 5882500 +Iowa | IA | 2854700 +Kansas | KS | 2603200 +Kentucky | KY | 3921000 +Louisiana | LA | 4361200 +Maine | ME | 1243700 +Maryland | MD | 5122400 +Massachusetts | MA | 6133500 +Michigan | MI | 9825100 +Minnesota | MN | 4704200 +Mississippi | MS | 2739700 +Missouri | MO | 5421400 +Montana | MT | 886400 +Nebraska | NE | 1661400 +Nevada | NV | 1828700 +New Hampshire | NH | 1179100 +New Jersey | NJ | 8078300 +New Mexico | NM | 1738700 +New York | NY | 18197800 +North Carolina | NC | 7483100 +North Dakota | ND | 640000 +Ohio | OH | 11197900 +Oklahoma | OK | 3328100 +Oregon | OR | 3266800 +Pennsylvania | PA | 12044200 +Rhode Island | RI | 987000 +South Carolina | SC | 3781800 +South Dakota | SD | 738500 +Tennessee | TN | 5398200 +Texas | TX | 19274300 +Utah | UT | 2071500 +Vermont | VT | 590400 +Virginia | VA | 6768400 +Washington | WA | 5674900 +West Virginia | WV | 1813200 +Wisconsin | WI | 5224500 +Wyoming | WY | 479500 diff --git a/components/rtgui/utils/perfect_hash/example2-C/Makefile b/components/rtgui/utils/perfect_hash/example2-C/Makefile new file mode 100644 index 0000000000..865e8cf7eb --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example2-C/Makefile @@ -0,0 +1,22 @@ + +CC = gcc -Wall + +a.out: main.c keys.code.h + $(CC) $< + + +keys.code.h: keys.dat keys.tmpl.h + ../perfect_hash.py $^ + + +keys.dat: + ./mk_rnd_keys.py 100 >keys.dat + + +clean: + rm keys.dat keys.code.h a.out + + +test: + ./a.out + diff --git a/components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h b/components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h new file mode 100644 index 0000000000..550bdb089d --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h @@ -0,0 +1,13 @@ + +#define NK $NK /* number of keys */ +#define NG $NG /* number of vertices */ +#define NS $NS /* length of array T1 and T2 */ + +int T1[] = { $S1 }; + +int T2[] = { $S2 }; + +int G[] = { $G }; + +char *K[] = { $K }; + diff --git a/components/rtgui/utils/perfect_hash/example2-C/main.c b/components/rtgui/utils/perfect_hash/example2-C/main.c new file mode 100644 index 0000000000..c19db892b8 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example2-C/main.c @@ -0,0 +1,51 @@ + +#include +#include +#include +#include + +#include "keys.code.h" + +int hash_g (char *s, int *T) +{ + int i, f = 0; + + for (i = 0; s[i] != '\0'; i++) { + f += T[i] * s[i]; + f %= NG; + } + return G[f]; +} + +int hash (char *k) +{ + if (strlen (k) > NS) + return 0; + + return (hash_g (k, T1) + hash_g (k, T2)) % NG; +} + +bool has_key (char *k) +{ + int h = hash (k); + + return h < NK && strcmp(k, K[h]) == 0; +} + +int main () +{ + int i; + + char *junk = "acnhuvn5yushvghnw7og5siuhgsiuhnglsh45vgghwn"; + + assert (has_key(junk) == 0); + assert (hash(junk) == 0); + + for (i = 0; i < NK; i++) { + assert (has_key(K[i]) == true); + assert (hash(K[i]) == i); + } + puts ("OK"); + + return 0; +} diff --git a/components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py b/components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py new file mode 100644 index 0000000000..81f964e9ff --- /dev/null +++ b/components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# ./mk_rnd_keys.py 10000 | sort | uniq | shuf >keywords.txt + +import sys +from random import choice, randint +from string import digits, uppercase, lowercase + +def key(): + return ''.join(choice(uppercase + lowercase + digits) + for i in xrange(randint(6, 20))) + +N = int(sys.argv[1]) + + +for n in xrange(N): + print key() diff --git a/components/rtgui/utils/perfect_hash/graph/Makefile b/components/rtgui/utils/perfect_hash/graph/Makefile new file mode 100644 index 0000000000..dc84f85fdb --- /dev/null +++ b/components/rtgui/utils/perfect_hash/graph/Makefile @@ -0,0 +1,23 @@ + + + +animals.ps: animals.dot + neato -Tps $< -Gstart=100 -o $@ + + +animals.dot: animals.py + ./py2dot -l $< -o $@ + + +animals.py: ../animals.txt + ../perfect_hash.py $< >$@ + + +clean: + rm animals.py animals.dot animals.ps + + +test: + true + + diff --git a/components/rtgui/utils/perfect_hash/graph/example-pipeline b/components/rtgui/utils/perfect_hash/graph/example-pipeline new file mode 100644 index 0000000000..86f58cdb38 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/graph/example-pipeline @@ -0,0 +1,4 @@ +#!/bin/bash + +../perfect_hash.py ../animals.txt | ./py2dot | neato -Tps -Gstart=100 -o out.ps + diff --git a/components/rtgui/utils/perfect_hash/graph/py2dot b/components/rtgui/utils/perfect_hash/graph/py2dot new file mode 100644 index 0000000000..920c70386a --- /dev/null +++ b/components/rtgui/utils/perfect_hash/graph/py2dot @@ -0,0 +1,216 @@ +#!/usr/bin/env python + +class Graph: + def __init__(self, N): + self.N = N # number of vertices + + # maps a vertex number to the list of (vertices, edge value) + # to which it is connected by edges. + self.adjacent = [[] for n in xrange(N)] + + def connect(self, vertex1, vertex2, edge_value): + """ + Connect 'vertex1' and 'vertex2' with an edge, with associated + value 'value' + """ + # Add vertices to each other's adjacent list + self.adjacent[vertex1].append( (vertex2, edge_value) ) + self.adjacent[vertex2].append( (vertex1, edge_value) ) + + def check(self): + """ + See if vertex values add up to edge values (mod N). + """ + for vertex in xrange(self.N): + for neighbor, edge_value in self.adjacent[vertex]: + assert (self.vertex_values[vertex] + + self.vertex_values[neighbor]) % self.N == edge_value + + def calc_tree_sizes(self): + """ + After running this method, the attribute size will contain a list, + which maps the vertices to the size of the tree that vertex belongs + to. + """ + visited = self.N * [-1] # -1 unvisited, otherwise the number of tree + treenum = 0 + + # Loop over all vertices, taking unvisited ones as roots. + for root in xrange(self.N): + if visited[root] >= 0: + continue + + # explore tree starting at 'root' + # Stack of vertices to visit, a list of tuples (parent, vertex) + tovisit = [ (None, root) ] + while tovisit: + parent, vertex = tovisit.pop() + visited[vertex] = treenum + + # Loop over adjacent vertices, but skip the vertex we arrived + # here from the first time it is encountered. + skip = True + for neighbor, edge_value in self.adjacent[vertex]: + if skip and neighbor == parent: + skip = False + continue + + if visited[neighbor] >= 0: + # We visited here before, so the graph is cyclic. + exit('Hmm, graph is cyclic.') + + tovisit.append( (vertex, neighbor) ) + + treenum += 1 + + # maps the tree number to number of vertices within that tree + treesizes = treenum * [0] + for tree in visited: + treesizes[tree] += 1 + + self.size = [treesizes[visited[v]] for v in xrange(self.N)] + + if verbose: + freq = (self.N+1) * [0] + for size in treesizes: + freq[size] += 1 + + sys.stderr.write(' Size Trees\n') + for i, f in enumerate(freq): + if f: + sys.stderr.write('%5i %5i\n' % (i, f)) + if i == minsize-1: + sys.stderr.write('--------------\n') + + def write(self, fo, labels = False): + self.calc_tree_sizes() + + fo.write('graph G {\n' + ' size = "8,8";\n' + ' edge [color="#ff0000"]\n') + if labels: + fo.write(' node [color="#a0e0ee", style=filled];\n') + + for vertex, value in enumerate(self.vertex_values): + if self.size[vertex] < minsize: continue + fo.write(' { node [label="%i: %i"] v%i }\n' % ( + vertex, value, vertex)) + else: + fo.write(' node [color="#3377a0", label="",\n' + ' style=filled, shape=circle]\n') + + for vertex in xrange(self.N): # edges + if self.size[vertex] < minsize: continue + for neighbor, edge_value in self.adjacent[vertex]: + if neighbor > vertex: continue + fo.write(' v%i -- v%i%s;\n' % + (vertex, neighbor, + (' [label="%s: %i"]' % (K[edge_value], edge_value)) + if labels else '')) + fo.write('}\n') + fo.close() + + +if __name__ == '__main__': + import sys + from optparse import OptionParser + + usage = "usage: %prog [options] [PYCODE]" + + description = """\ +Given the python code for a perfect hash function which was generated by +perfect_hash.py, e.g. by '$ ../perfect_hash.py animals.txt >animals.py', +this program will create the graph which was used in determining the +perfect hash function. The input python code may also be given to stdin. +The output is saved as in the .dot format which is used by the Graphviz +tools (see http://www.graphviz.org/) to generate a picture of the graph. +""" + + parser = OptionParser(usage = usage, + description = description, + prog = sys.argv[0]) + + parser.add_option("-l", "--labels", + action = "store_true", + help = "Be verbose") + + parser.add_option("-m", "--minsize", + action = "store", + default = 1, + type = "int", + help = "Include only trees in the output which " + "have at least INT vertices. " + "Default is %default, i.e. all trees are " + "included within the output.", + metavar = "INT") + + parser.add_option("-o", "--output", + action = "store", + help = "Specify output FILE explicitly. " + "Default, is stdout. ", + metavar = "FILE") + + parser.add_option("-v", "--verbose", + action = "store_true", + help = "Be verbose") + + options, args = parser.parse_args() + + if options.minsize > 0: + minsize = options.minsize + else: + parser.error("minimal size of trees has to be larger than zero") + + verbose = options.verbose + + if len(args) > 1: + parser.error("incorrect number of arguments") + + # --------------------- end parsing and checking ----------------------- + + if verbose: + sys.stderr.write('minsize (of trees): %i\n' % minsize) + sys.stderr.write('labels (in output): %s\n' % options.labels) + + # ------------ input filehandle + + if len(args)==1: + try: + fi = file(args[0]) + except IOError : + exit("Error: Can't open `%s' for reading." % args[0]) + else: + fi = sys.stdin + + # ------------ read input, i.e. execute code + + exec(fi.read()) + + # ------------ make graph + + g = Graph(len(G)) + g.vertex_values = G + for key, hashval in zip(K, H): + g.connect(hash_f(key, S1), + hash_f(key, S2), + hashval) + g.check() + + # ------------ output filehandle + + if options.output: + try: + fo = file(options.output, 'w') + except IOError : + exit("Error: Can't open `%s' for writing." % options.output) + else: + fo = sys.stdout + + # ------------ write output, i.e. generate .dot output + + g.write(fo, options.labels) + + +# Local Variables: +# mode: python +# End: diff --git a/components/rtgui/utils/perfect_hash/perfect_hash.py b/components/rtgui/utils/perfect_hash/perfect_hash.py new file mode 100644 index 0000000000..e981877634 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/perfect_hash.py @@ -0,0 +1,870 @@ +#!/usr/bin/env python +""" +Generate a minimal perfect hash function for the keys in a file, +desired hash values may be specified within this file as well. +A given code template is filled with parameters, such that the +output is code which implements the hash function. +Templates can easily be constructed for any programming language. + +The code is based on an a program A.M. Kuchling wrote: +http://www.amk.ca/python/code/perfect-hash + +The algorithm the program uses is described in the paper +'Optimal algorithms for minimal perfect hashing', +Z. J. Czech, G. Havas and B.S. Majewski. +http://citeseer.ist.psu.edu/122364.html + +The algorithm works like this: + +1. You have K keys, that you want to perfectly hash against some + desired hash values. + +2. Choose a number N larger than K. This is the number of + vertices in a graph G, and also the size of the resulting table G. + +3. Pick two random hash functions f1, f2, that return values from 0..N-1. + +4. Now, for all keys, you draw an edge between vertices f1(key) and f2(key) + of the graph G, and associate the desired hash value with that edge. + +5. Check if G is acyclic, i.e. has no loops; if no, go back to step 2. + +6. Assign values to each vertex such that, for each edge, you can add + the values for the two vertices and get the desired (hash) value + for that edge. This task is easy, because the graph is acyclic. + This is done by picking a vertex, and assigning it a value of 0. + Then do a depth-first search, assigning values to new vertices so that + they sum up properly. + +7. f1, f2, and vertex values of G now make up a perfect hash function. + + +For simplicity, the implementation of the algorithm combines steps 5 and 6. +That is, we check for loops in G and assign the vertex values in one procedure. +If this procedure succeeds, G is acyclic and the vertex values are assigned. +If the procedure fails, G is cyclic, and we go back to step 2, replacing G +with a new graph, and thereby discarding the vertex values from the failed +attempt. +""" +__author__ = 'Ilan Schnell , 2008 (and AMK 2000)' +__license__ = 'GNU GPL 2' +__version__ = '0.1' + + +import sys, random, string, cStringIO, StringIO + +verbose = False +trails = 5 + + +class Graph: + """ + Implements a graph with 'N' vertices. First, you connect the graph with + edges, which have a desired value associated. Then the vertex values + are assigned, which will fail if the graph is cyclic. The vertex values + are assigned such that the two values corresponding to an edge add up to + the desired edge value (mod N). + + Example: + >>> G = Graph(3) + >>> G.assign_vertex_values() + True + + Now we make an edge between vertex 0 and 1 with desired edge value 2: + >>> G.connect(0, 1, 2) + + Make another edge 1:2 with desired edge value 1: + >>> G.connect(1, 2, 1) + + The graph is still acyclic, and assigning values works: + >>> G.assign_vertex_values() + True + >>> G.vertex_values + [0, 2, 2] + + What do these values mean? + When you add the values for edge 0:1 you get 0 + 2 = 2, as desired. + For edge 1:2 you add 2 + 2 = 4 = 1 (mod 3), as desired. + + Adding edge 0:2 produces a loop, so the graph is no longer acyclic. + Assigning values fails. + >>> G.connect(0, 2, 0) + >>> G.assign_vertex_values() + False + """ + def __init__(self, N): + self.N = N # number of vertices + + # maps a vertex number to the list of tuples (vertices, edge value) + # to which it is connected by edges. + self.adjacent = [[] for n in xrange(N)] + + def connect(self, vertex1, vertex2, edge_value): + """ + Connect 'vertex1' and 'vertex2' with an edge, with associated + value 'value' + """ + # Add vertices to each other's adjacent list + self.adjacent[vertex1].append( (vertex2, edge_value) ) + self.adjacent[vertex2].append( (vertex1, edge_value) ) + + def assign_vertex_values(self): + """ + Try to assign the vertex values, such that, for each edge, you can + add the values for the two vertices involved and get the desired + value for that edge, i.e. the desired hash key. + This will fail when the graph is cyclic. + + This is done by a Depth-First Search of the graph. If the search + finds a vertex that was visited before, there's a loop and False is + returned immediately, i.e. the assignment is terminated. + On success (when the graph is acyclic) True is returned. + """ + self.vertex_values = self.N * [-1] # -1 means unassigned + + visited = self.N * [False] + + # Loop over all vertices, taking unvisited ones as roots. + for root in xrange(self.N): + if visited[root]: + continue + + # explore tree starting at 'root' + self.vertex_values[root] = 0 # set arbitrarily to zero + + # Stack of vertices to visit, a list of tuples (parent, vertex) + tovisit = [ (None, root) ] + while tovisit: + parent, vertex = tovisit.pop() + visited[vertex] = True + + # Loop over adjacent vertices, but skip the vertex we arrived + # here from the first time it is encountered. + skip = True + for neighbor, edge_value in self.adjacent[vertex]: + if skip and neighbor == parent: + skip = False + continue + + if visited[neighbor]: + # We visited here before, so the graph is cyclic. + return False + + tovisit.append( (vertex, neighbor) ) + + # Set new vertex's value to the desired edge value, + # minus the value of the vertex we came here from. + self.vertex_values[neighbor] = \ + ( edge_value - self.vertex_values[vertex] ) % self.N + + # check if all vertices have a valid value + for vertex in xrange(self.N): + assert self.vertex_values[vertex] >= 0 + + # We got though, so the graph is acyclic, + # and all values are now assigned. + return True + + +def generate_hash(kdic, Hash): + """ + Return hash functions f1 and f2, and G for a perfect minimal hash. + Input is dictionary 'kdic' with the keys and desired hash values. + 'Hash' is a random hash function generator, that means Hash(N) returns a + returns a random hash function which returns hash values from 0..N-1. + """ + # N is the number of vertices in the graph G + N = 1 if not kdic else (max(kdic.values()) + 1) + if verbose >= 2: + sys.stderr.write('N = %i\n' % N) + + trail = 0 # Number of trial graphs so far + while True: + if (trail % trails) == 0: # trails failures, increase N slightly + if trail > 0: + N = max(N+1, int(1.05*N)) + if verbose: + sys.stderr.write('\n') + sys.stderr.write('Generating graphs N = %i ' % N) + trail += 1 + + if verbose: + sys.stderr.write('.') + sys.stderr.flush() + + G = Graph(N) # Create graph with N vertices + f1 = Hash(N) # Create 2 random hash functions + f2 = Hash(N) + + # Connect vertices given by the values of the two hash functions + # for each key. Associate the desired hash value with each edge. + for key, hashval in kdic.iteritems(): + G.connect(f1(key), f2(key), hashval) + + # Try to assign the vertex values. This will fail when the graph + # is cyclic. But when the graph is acyclic it will succeed and we + # break out, because we're done. + if G.assign_vertex_values(): + break + + if verbose: + sys.stderr.write('\nAcyclic graph found after %i trails.\n' % trail) + + if verbose >= 2: + sys.stderr.write('N = %i\n' % N) + if verbose: + sys.stderr.write('Checking generated hash function... ') + + # Sanity check the result by actually verifying that all the keys + # hash to the right value. + for key, hashval in kdic.iteritems(): + assert hashval == ( G.vertex_values[f1(key)] + + G.vertex_values[f2(key)] ) % N + + if verbose: + sys.stderr.write('OK\n') + + return f1, f2, G.vertex_values + + +class Hash1: + """ + Random hash function generator. + For simplicity and speed, this doesn't implement any byte-level hashing + scheme. Instead, a random string is generated and prefixing to str(key), + and then Python's hashing function is used. + """ + def __init__(self, N): + self.N = N + self.salt = "".join(random.choice(string.letters + string.digits) + for i in xrange(8)) + + def __call__(self, key): + return hash(self.salt + str(key)) % self.N + + template = """ +def perfect_hash(key): + return (G[ hash('$S1' + str(key)) % $NG ] + + G[ hash('$S2' + str(key)) % $NG ]) % $NG +""" + +class Hash2: + """ + Random hash function generator. + Simple byte level hashing, each byte is multiplied in sequence to a table + containing random numbers modulo N, and then these products are summed up. + The table with random numbers is dynamically expanded whenever + a key longer than the current table size is encountered. + """ + def __init__(self, N): + self.N = N + self.salt = [] + + def __call__(self, key): + skey = key + while len(self.salt) < len(skey): # add more salt if necessary + self.salt.append(random.randint(0, self.N-1)) + + return sum(self.salt[i] * ord(c) + for i, c in enumerate(skey)) % self.N + + template = """ +S1 = [$S1] +S2 = [$S2] + +def hash_f(key, T): + return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG + +def perfect_hash(key): + return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG +""" + + +class PerfHash: + """ + This class is designed for creating perfect hash tables at run time, + which should be avoided, in particulat inserting new keys is + prohibitively expensive since a new perfect hash table needs to be + constructed. However, this class can be usefull for testing. + + >>> d = PerfHash({'foo':(429, 'bar'), 42:True, False:'baz'}) + >>> d['foo'], d[42], d[False] + ((429, 'bar'), True, 'baz') + >>> d[False] = (1, 2) + >>> d[False] + (1, 2) + >>> d.has_key('foo') + True + >>> d.has_key(True) + False + """ + def __init__(self, dic): + self.klst = [] + self.objs = [] + kdic = {} + for hashval, (key, obj) in enumerate(dic.iteritems()): + self.klst.append(key) + self.objs.append(obj) + kdic[key] = hashval + + self.N = len(dic) + self.f1, self.f2, self.G = generate_hash(kdic, Hash1) + + def __setitem__(self, newkey, newobj): + dic = {} + for key in self.klst: + dic[key] = self[key] + dic[newkey] = newobj + self.__init__(dic) + + def hashval(self, key): + return ( self.G[self.f1(key)] + self.G[self.f2(key)] ) % len(self.G) + + def __getitem__(self, key): + h = self.hashval(key) + if h < self.N and key == self.klst[h]: + return self.objs[h] + else: + raise IndexError + + def has_key(self, key): + h = self.hashval(key) + return h < self.N and key == self.klst[h] + + +class Format: + """ + >>> class o: + ... pass + >>> o.delimiter = ': ' + >>> o.width = 75 + >>> o.indent = 4 + >>> x = Format( o ) + >>> x( range(10) ) + '0: 1: 2: 3: 4: 5: 6: 7: 8: 9' + >>> o.delimiter = '; ' + >>> x = Format( o ) + >>> x( range(5) ) + '0; 1; 2; 3; 4' + >>> o.delimiter = ' ' + >>> x = Format( o ) + >>> x( range(5), quote = True ) + '"0" "1" "2" "3" "4"' + >>> x(42) + '42' + >>> x('Hello') + 'Hello' + """ + def __init__(self, options): + names = ['width', 'indent', 'delimiter'] + + for name in names: + setattr(self, name, getattr(options, name)) + + if verbose >=2: + sys.stderr.write("Format options:\n") + for name in names: + sys.stderr.write(' %s: %r\n' % (name, getattr(self, name))) + + def __call__(self, data, quote = False): + if type(data) != type([]): + return str(data) + + lendel = len(self.delimiter) + aux = StringIO.StringIO() + pos = 20 + for i, elt in enumerate(data): + last = bool(i == len(data)-1) + + s = ('"%s"' if quote else '%s') % elt + + if pos + len(s) + lendel > self.width: + aux.write('\n' + (self.indent * ' ')) + pos = self.indent + + aux.write(s) + pos += len(s) + if not last: + aux.write(self.delimiter) + pos += lendel + + return aux.getvalue() + + +def keyDict(keys_hashes): + """ + Checks a list with (key, hashvalue) tupels and returns dictionary. + + >>> d = keyDict([(1, 2), (3, 4), (5, 6)]) + >>> d[3] + 4 + """ + K = len(keys_hashes) # number of keys + if verbose >= 2: + sys.stderr.write('K = %i\n' % K) + + kdic = dict(keys_hashes) + if len(kdic) < K: + sys.stderr.write('Warning: Input contains duplicate keys\n') + + if len(set(kdic.values())) < K: + sys.stderr.write('Warning: Input contains duplicate hash values\n') + + return kdic + + + +def generate_code(keys_hashes, template, Hash, options, extra_subs): + """ + Takes a list of key value pairs and inserts the generated parameter + lists into the 'template' strinng. 'Hash' is the random hash function + generator, and the optional keywords are formating options. + The return value is the substituted code template. + """ + f1, f2, G = generate_hash(keyDict(keys_hashes), Hash) + + assert f1.N == f2.N == len(G) + assert len(f1.salt) == len(f2.salt) + + fmt = Format(options) + + return string.Template(template).substitute( + NS = len(f1.salt), + S1 = fmt(f1.salt), + S2 = fmt(f2.salt), + NG = len(G), + G = fmt(G), + NK = len(keys_hashes), + K = fmt([key for key, hashval in keys_hashes], quote = True), + H = fmt([hashval for key, hashval in keys_hashes]), + **extra_subs) + + + +def read_table(filename, options): + """ + Reads keys and desired hash value pairs from a file. If no column + for the hash value is specified, a sequence of hash values is generated, + from 0 to N-1, where N is the number of rows found in the file. + """ + if verbose >= 2: + sys.stderr.write("Reading table from file `%s' to extract keys.\n" % + filename) + try: + f = file(filename) + except IOError : + exit("Error: Could not open `%s' for reading." % filename) + + keys_hashes = [] + hashval = -1 + + if verbose >= 2: + sys.stderr.write("Reader options:\n") + for name in ['comment', 'splitby', 'keycol', 'hashcol']: + sys.stderr.write(' %s: %r\n' % + (name, getattr(options, name))) + + for n, line in enumerate(f): + line = line.strip() + if not line or line.startswith(options.comment): + continue + + if line.count(options.comment): # strip content after comment + line = line.split(options.comment)[0].strip() + + row = [col.strip() for col in line.split(options.splitby)] + + try: + key = row[options.keycol-1] + except IndexError : + exit("%s:%i: Error: Cannot read key, not enough columns." % + (filename, n+1)) + + if options.hashcol: + try: + val = row[options.hashcol-1] + except IndexError : + exit("%s:%i: Error: Cannot read hash value, not enough columns." + % (filename, n+1)) + try: + hashval = int(val) + except ValueError : + exit("%s:%i: Error: Cannot convert `%s' to int." % + (filename, n+1, row[options.hashcol-1])) + else: + hashval += 1 + + keys_hashes.append( (key, hashval) ) + + f.close() + + if not keys_hashes: + exit("Error: no keys found in file `%s'." % filename) + + return keys_hashes + + + +def print_keys_hashes(keys_hashes): + fmt = '%-20s %10s' + head = fmt % ('Key', 'Hash value') + sys.stderr.write('\n' + head + '\n') + sys.stderr.write(len(head)*'-' + '\n') + for tup in keys_hashes: + sys.stderr.write(fmt % tup + '\n') + sys.stderr.write('\n') + +def read_template(filename): + if verbose >= 2: + sys.stderr.write("Reading template from file `%s'.\n" % filename) + + try: + f = file(filename) + except IOError : + fatal_error("Error: Could not open `%s' for reading." % filename) + + return f.read() + + +def builtin_template(Hash): + return """\ +# ======================================================================= +# ================= Python code for perfect hash function =============== +# ======================================================================= + +G = [$G] +""" + Hash.template + """ +# ============================ Sanity check ============================= + +K = [$K] +H = [$H] + +assert len(K) == len(H) == $NK + +for k, h in zip(K, H): + assert perfect_hash(k) == h +""" + + +def print_code(code, name, width = 78): + def center(s): + v = (width - len(s))/2 + return '='*v + s + '='*v + sys.stderr.write(center(' BEGIN %s ' % name) + '\n') + sys.stderr.write(code + '\n') + sys.stderr.write(center(' END %s ' % name) + '\n') + + +def self_test(options): + import doctest + global verbose + print 'Starting self tests ...' + + def random_word(): + return ''.join(random.choice(string.letters + string.digits) + for i in xrange(random.randint(1, 20))) + + def flush_dot(): + sys.stdout.write('.') + sys.stdout.flush() + + def run(K, Hash): + flush_dot() + + keys = [chr(65+i) for i in xrange(K)] + hashes = range(K) + + random.shuffle(keys) + random.shuffle(hashes) + + code = generate_code(zip(keys, hashes), + builtin_template(Hash), + Hash, + options) + exec(code) in {} + + verbose = False + for Hash in [Hash1, Hash2]: + for K in xrange(0, 27): + run(K, Hash) + print + + verbose = options.verbose + N = 250 + for Hash in [Hash1, Hash2]: + if verbose: + print 'Generating approximately %i key/hash pairs ...' % N + kh = {} + for i in xrange(N): + kh[random_word()] = i + + if verbose: + print 'Generating code for %i key/hash pairs ...' % len(kh) + code = generate_code(kh.items(), + builtin_template(Hash), + Hash, + options) + if verbose: + print 'Executing code ...' + flush_dot() + exec(code) in {} + + flush_dot() + d = PerfHash(dict([(100-i, i*i) for i in xrange(500)])) + for i in xrange(500): + assert d[100-i] == i*i + flush_dot() + d[None] = True + assert d[None] == True + + if verbose: + print 'Running doctest ...' + + verbose = False + failure_count, test_count = doctest.testmod(report = True, verbose = False) + print + if failure_count: + sys.stderr.write('FAILED\n') + sys.exit(2) + else: + sys.stderr.write('%i tests passed.\n' % test_count) + sys.stderr.write('OK\n') + sys.exit(0) + + +if __name__ == '__main__': + from optparse import OptionParser + + usage = "usage: %prog [options] KEYS_FILE [TMPL_FILE]" + + description = """\ +Generates code for perfect hash functions from +a file with keywords and a code template. +If no template file is provided, a small built-in Python template +is processed and the output code is written to stdout. +""" + + parser = OptionParser(usage = usage, + description = description, + prog = sys.argv[0], + version = "%prog 0.1") + + parser.add_option("--delimiter", + action = "store", + default = ", ", + help = "Delimiter for list items used in output, " + "the default delimiter is '%default'", + metavar = "STR") + + parser.add_option("--indent", + action = "store", + default = 2, + type = "int", + help = "Make INT spaces at the beginning of a " + "new line when generated list is wrapped. " + "Default is %default", + metavar = "INT") + + parser.add_option("--width", + action = "store", + default = 76, + type = "int", + help = "Maximal width of generated list when " + "wrapped. Default width is %default", + metavar = "INT") + + parser.add_option("--comment", + action = "store", + default = "#", + help = "STR is the character, or sequence of " + "characters, which marks the beginning " + "of a comment (which runs till " + "the end of the line), in the input " + "KEYS_FILE. " + "Default is '%default'", + metavar = "STR") + + parser.add_option("--splitby", + action = "store", + default = ",", + help = "STR is the character by which the columns " + "in the input KEYS_FILE are split. " + "Default is '%default'", + metavar = "STR") + + parser.add_option("--keycol", + action = "store", + default = 1, + type = "int", + help = "Specifies the column INT in the input " + "KEYS_FILE which contains the keys. " + "Default is %default, i.e. the first column.", + metavar = "INT") + + parser.add_option("--hashcol", + action = "store", + default = 0, + type = "int", + help = "Specifies the column INT in the input " + "KEYS_FILE which contains the desired " + "hash values. " + "By default the hash values are given by the " + "sequence 0..N-1.", + metavar = "INT") + + parser.add_option("--trails", + action = "store", + default = 5, + type = "int", + help = "Specifies the number of trails before " + "N is increased. A small INT will give " + "compute faster, but the array G will be " + "large. A large INT will take longer to " + "compute but G will be smaller. " + "Default is %default", + metavar = "INT") + + parser.add_option("--hft", + action = "store", + default = 2, + type = "int", + help = "Hash function type INT (see documentation), " + "The default is %default", + metavar = "INT") + + parser.add_option("-e", "--execute", + action = "store_true", + help = "Execute the generated code within " + "the Python interpreter.") + + parser.add_option("-o", "--output", + action = "store", + help = "Specify output FILE explicitly. " + "`-o std' means standard output. " + "`-o no' means no output. " + "By default, the file name is obtained " + "from the name of the template file by " + "substituting `tmpl' to `code'.", + metavar = "FILE") + + parser.add_option("--test", + action = "store_true", + help = "Perform self test") + + parser.add_option("-v", "--verbose", + action = "count", + help = "Be verbose, " + "use -vv to be even more verbose") + + options, args = parser.parse_args() + print type(options), '\n', repr(options) + + if options.trails > 0: + trails = options.trails + else: + parser.error("trails before increasing N has to be larger than zero") + + verbose = options.verbose + + if options.test: + self_test(options) + + if len(args) not in (1, 2): + parser.error("incorrect number of arguments") + + if len(args) == 2 and not args[1].count('tmpl'): + parser.error("template filename does not contain 'tmpl'") + + if options.hft == 1: + Hash = Hash1 + elif options.hft == 2: + Hash = Hash2 + else: + parser.error("Hash function %i not implemented.") + + # --------------------- end parsing and checking -------------- + + # ---------------- keys_file + + keys_file = args[0] + + if verbose: + sys.stderr.write("keys_file = %r\n" % keys_file) + + # ---------------- keys_hashes + + keys_hashes = read_table(keys_file, options) + + if verbose >= 3: + print_keys_hashes(keys_hashes) + + # ---------------- tmpl_file + + if len(args) == 2: + tmpl_file = args[1] + else: + tmpl_file = None + + if verbose: + sys.stderr.write("tmpl_file = %r\n" % tmpl_file) + + # ---------------- template + + if tmpl_file: + template = read_template(tmpl_file) + else: + template = builtin_template(Hash) + + if verbose >= 3: + print_code(template, 'TEMPLATE') + + # ---------------- outname + + if options.output: + outname = options.output + + else: + if tmpl_file: + if tmpl_file.count('tmpl'): + outname = tmpl_file.replace('tmpl', 'code') + else: + exit("Hmm, template filename does not contain 'tmpl'") + else: + outname = 'std' + + if verbose: + sys.stderr.write("outname = %r\n" % outname) + + # ---------------- outstream + + if outname == 'std': + outstream = sys.stdout + + elif outname == 'no': + outstream = None + + else: + try: + outstream = open(outname, 'w') + except IOError : + exit("Error: Could not open `%s' for writing." % outname) + + # ---------------- generated code + + code = generate_code(keys_hashes, template, Hash, options) + if verbose >= 3: + print_code(code, 'GENERATED CODE') + + # ---------------- execute code + + if options.execute or template == builtin_template(Hash): + if verbose: + sys.stderr.write('Executing code...\n') + exec(code) + + # ---------------- write code to output stream + + if outstream: + outstream.write(code) + if not outname == 'std': + outstream.close() diff --git a/components/rtgui/utils/perfect_hash/run b/components/rtgui/utils/perfect_hash/run new file mode 100644 index 0000000000..c7fe1f22e2 --- /dev/null +++ b/components/rtgui/utils/perfect_hash/run @@ -0,0 +1,32 @@ +#!/bin/bash + +function showpwd () +{ + echo '=============' `pwd` +} + +# perform programs self test +showpwd +./perfect_hash.py --test || exit 1 + +# update documentation +for folder in doc +do + cd $folder + showpwd + make + cd .. +done + +# run examples +for folder in example* graph +do + cd $folder + showpwd + make || exit 1 + make test || exit 1 + make clean + cd .. +done + +rm perfect_hash.pyc diff --git a/components/rtgui/utils/stract_cjk.py b/components/rtgui/utils/stract_cjk.py new file mode 100644 index 0000000000..afea09897c --- /dev/null +++ b/components/rtgui/utils/stract_cjk.py @@ -0,0 +1,163 @@ +#encoding: utf-8 +from perfect_hash import perfect_hash + +import re, string, os, random + +cur_dir = os.path.abspath(os.path.dirname(__file__)) + +unicode_chinese_re = u'[\u2E80-\u2EFF\u2F00-\u2FDF\u3000-\u303F\u31C0-\u31EF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FBF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]' +match_re = re.compile(unicode_chinese_re) + +def _get_font_lib(f): + reading_data = False + data = [] + for i in f.readlines(): + if i.strip() == 'FONT_BMP_DATA_BEGIN': + reading_data = True + continue + if i.strip() == 'FONT_BMP_DATA_END': + break + if reading_data: + line = [k for k in i.strip().split(',') if k] + data.extend([int(k, 16) for k in line]) + return data + +class font_lib(object): + def __init__(self, f, width, height, encoding): + self.width = width + self.height = height + self._lib = _get_font_lib(f) + # byte per charactor + self._bpc = (width+7)//8*height + self.encoding = encoding + self._finished_push = False + + self.char_dict = {} + + def get_char_data(self, char): + #char_gb = char.encode(self.encoding) + + # copied from font_hz_bmp.c + sec, idx = [ord(i) - 0xA0 for i in char] + #print 'sec %d, idx %d for' % (sec, idx), char + start = (94 * (sec-1) + (idx-1)) * self._bpc + return self._lib[start:start+self._bpc] + + def push_char(self, c): + self.char_dict[c] = self.char_dict.get(c, 0) + 1 + + def push_file(self, f): + try: + for i in f: + t = re.findall(match_re, unicode(i.decode(self.encoding))) + if t: + for c in t: + self.push_char(c.encode(self.encoding)) + except UnicodeDecodeError as e: + try: + print 'error in decoding %s' % f.name + except: + print 'error in decoding string %s' % f + # re-raise the exception and terminate the building process + raise + + def _finish_push(self): + if self._finished_push: + return + + self._char_li = zip(self.char_dict.keys(), self.char_dict.values()) + self._char_li.sort(key=lambda x:x[1], reverse=True) + self._finished_push = True + + #for i in self._char_li: + #print i[0], i[1] + + def get_hash_map(self): + self._finish_push() + li = [] + for i, k in enumerate(self._char_li): + li.append((k[0], i)) + return li + + def get_new_font_lib(self): + self._finish_push() + dat = [] + for c, f in self._char_li: + dat.extend(self.get_char_data(c)) + return dat + + def finish(self): + return self.get_hash_map(), self.get_new_font_lib() + +class mph_options(object): + 'mock object for options' + def __init__(self, verbose=4, delimiter=', ', indent=4, width=80): + self.verbose = verbose + self.delimiter = delimiter + self.indent = indent + self.width = width + +def gen_char_mph(font_lib): + template = open(os.path.join(cur_dir, '..', 'common', 'font_mph-tmpl.c'), 'r').read() + opt = mph_options() + hmap, flib = font_lib.finish() + #print 'compact font lib: %d chars included.' % len(hmap) + #for i in hmap: + #print i[0], repr(i[0]), i[1] + code = perfect_hash.generate_code(hmap, template, perfect_hash.Hash2, opt, + extra_subs={ + 'width':str(font_lib.width), + 'height':str(font_lib.height), + 'font_data':', '.join([hex(i) for i in flib])}) + + return code + +# {name:[file_name, height, width, encoding, instance]} +_font_map = {'hz16':{'fname':'common/hz16font.c', + 'height':16, + 'width':16, + 'encoding':'GB2312', + 'flib':None}, + 'hz12':{'fname':'common/hz12font.c', + 'height':12, + 'width':12, + 'encoding':'GB2312', + 'flib':None} + } + +def get_font_lib(name): + if name not in _font_map.keys(): + return None + + if _font_map[name]['flib'] is None: + _font_map[name]['flib'] = font_lib(open( + os.path.join(cur_dir, '..', _font_map[name]['fname']), 'r'), + _font_map[name]['height'], + _font_map[name]['width'], + _font_map[name]['encoding']) + return _font_map[name]['flib'] + +def gen_cmp_font_file(): + for i in _font_map: + fl = _font_map[i]['flib'] + if fl is not None: + code = gen_char_mph(fl) + with open(os.path.join(cur_dir, '..', 'common', 'font_cmp_%s.c' % i), 'w') as f: + f.write(code) + +if __name__ == '__main__': + import sys + + lib = get_font_lib('hz16') + libn = get_font_lib('hz16') + assert(lib is libn) + + lib.push_file(open(sys.argv[1], 'rb')) + + hmap, flib = lib.finish() + for i in hmap: + print i[0], i[1] + + assert(len(flib) == 32 * len(hmap)) + + print gen_char_mph(lib) diff --git a/components/rtgui/widgets/box.c b/components/rtgui/widgets/box.c index 47c704b7c9..448f47ea36 100644 --- a/components/rtgui/widgets/box.c +++ b/components/rtgui/widgets/box.c @@ -73,7 +73,7 @@ static void rtgui_box_layout_vertical(struct rtgui_box *box, struct rtgui_rect * { rtgui_widget_t *widget = rtgui_list_entry(node, struct rtgui_widget, sibling); if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++; - else total_height += widget->mini_height; + else total_height += widget->min_height; } /* calculate the height for each spaces */ @@ -98,8 +98,8 @@ static void rtgui_box_layout_vertical(struct rtgui_box *box, struct rtgui_rect * /* reset rect */ rtgui_rect_moveto(rect, -rect->x1, -rect->y1); - rect->x2 = widget->mini_width; - rect->y2 = widget->mini_height; + rect->x2 = widget->min_width; + rect->y2 = widget->min_height; /* left in default */ rtgui_rect_moveto(rect, next_x, next_y); @@ -166,7 +166,7 @@ static void rtgui_box_layout_horizontal(struct rtgui_box *box, struct rtgui_rect { rtgui_widget_t *widget = rtgui_list_entry(node, struct rtgui_widget, sibling); if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++; - else total_width += widget->mini_width; + else total_width += widget->min_width; } if (space_count != 0) @@ -191,8 +191,8 @@ static void rtgui_box_layout_horizontal(struct rtgui_box *box, struct rtgui_rect /* reset rect */ rtgui_rect_moveto(rect, -rect->x1, -rect->y1); - rect->x2 = widget->mini_width; - rect->y2 = widget->mini_height; + rect->x2 = widget->min_width; + rect->y2 = widget->min_height; /* top in default */ rtgui_rect_moveto(rect, next_x, next_y); diff --git a/components/rtgui/widgets/button.c b/components/rtgui/widgets/button.c index ca15acb89a..ceca58f008 100644 --- a/components/rtgui/widgets/button.c +++ b/components/rtgui/widgets/button.c @@ -104,7 +104,8 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e break; case RTGUI_EVENT_MOUSE_BUTTON: - if (RTGUI_WIDGET_IS_HIDE(widget)) return RT_FALSE; + if (RTGUI_WIDGET_IS_HIDE(widget)) + return RT_FALSE; { struct rtgui_event_mouse *emouse = (struct rtgui_event_mouse *)event; @@ -159,9 +160,6 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e /* need callback */ rt_bool_t need_cb = RT_FALSE; - win = RTGUI_WIN(RTGUI_WIDGET(btn)->toplevel); - win->last_mevent_widget = RTGUI_WIDGET(btn); - /* we need to decide whether the callback will be invoked * before the flag has changed. Moreover, we cannot invoke * it directly here, because the button might be destroyed @@ -174,14 +172,20 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e need_cb = RT_TRUE; } - /* it's a normal button */ + /* if the button will handle the mouse up event here, it + * should not be the last_mevent_widget. Take care that + * don't overwrite other widgets. */ + win = RTGUI_WIN(RTGUI_WIDGET(btn)->toplevel); if (emouse->button & RTGUI_MOUSE_BUTTON_DOWN) { btn->flag |= RTGUI_BUTTON_FLAG_PRESS; + win->last_mevent_widget = RTGUI_WIDGET(btn); } else { btn->flag &= ~RTGUI_BUTTON_FLAG_PRESS; + if (win->last_mevent_widget == RTGUI_WIDGET(btn)) + win->last_mevent_widget = RT_NULL; } /* draw button */ diff --git a/components/rtgui/widgets/combobox.c b/components/rtgui/widgets/combobox.c index 50cac173b1..ece6cb2e1b 100644 --- a/components/rtgui/widgets/combobox.c +++ b/components/rtgui/widgets/combobox.c @@ -48,7 +48,7 @@ rt_bool_t rtgui_combobox_pdwin_onitem(struct rtgui_object *object, struct rtgui_ if (combo->on_selected != RT_NULL) combo->on_selected(RTGUI_OBJECT(combo), RT_NULL); - rtgui_win_hiden(pd_win); + rtgui_win_hide(pd_win); rtgui_widget_update(RTGUI_WIDGET(combo)); return RT_FALSE; @@ -56,7 +56,7 @@ rt_bool_t rtgui_combobox_pdwin_onitem(struct rtgui_object *object, struct rtgui_ rt_bool_t rtgui_combobox_pdwin_ondeactive(struct rtgui_object *object, struct rtgui_event *event) { - rtgui_win_hiden(RTGUI_WIN(object)); + rtgui_win_hide(RTGUI_WIN(object)); return RT_TRUE; } @@ -226,7 +226,7 @@ rt_bool_t rtgui_combobox_event_handler(struct rtgui_object *object, struct rtgui if (focused->widget != RT_NULL) { /* hide pull down window */ - rtgui_win_hiden(RTGUI_WIN(box->pd_win)); + rtgui_win_hide(RTGUI_WIN(box->pd_win)); rtgui_combobox_ondraw(box); } } @@ -255,7 +255,7 @@ static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_object *object, struc if (box == RT_NULL) return RT_TRUE; /* hide pull down window */ - rtgui_win_hiden(RTGUI_WIN(box->pd_win)); + rtgui_win_hide(RTGUI_WIN(box->pd_win)); /* clear pull down button state */ box->pd_pressed = RT_FALSE; diff --git a/components/rtgui/widgets/digfont.c b/components/rtgui/widgets/digfont.c new file mode 100644 index 0000000000..0d081f94ad --- /dev/null +++ b/components/rtgui/widgets/digfont.c @@ -0,0 +1,309 @@ +/* + * File : digfont.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-12-21 pife first version + */ + +#include +#include +#include +#include + +#define DIGFONT_V 1 +#define DIGFONT_H 0 + +int rtgui_digitfont_create(struct rtgui_digitfont * font) +{ + int i; + int half; + int space; + int seg35_y; + int hight; + struct rtgui_digitfont_data * data, *databuf; + struct rtgui_digitfont_data temp, temp2;; + + data= rt_malloc(sizeof(struct rtgui_digitfont_data) * 7 * font->seg1_nr); + if (data== RT_NULL) + { + rt_kprintf("out of memory.\n"); + goto __err; + } + databuf = font->data = data; + + data = &temp; + half = font->seg1_nr >> 1; + space = font->seg1_hspace; + seg35_y = font->seg1_vspace + font->seg2_len + (half<<1) - font->seg1_vspace; + hight = (font->seg1_vspace << 1) + font->seg2_len + font->seg3_len + (half << 1) - 1; + + //seg 1 + data->type = DIGFONT_H; + data->x = font->seg1_hspace; + data->y = 0; + data->len = font->seg1_len; + + *databuf++ = *data; + for(i=1; iseg1_nr; i++) + { + data->len -= 2; + data->x ++; + data->y ++; + *databuf++ = *data; + } + + //seg 2 + data->type = DIGFONT_V; + data->x = (font->seg1_hspace << 1) + font->seg1_len -1; + data->y = font->seg1_vspace ; + data->len = font->seg2_len; + *databuf++ = *data; + for(i=1; iseg1_nr; i++) + { + if (i >= half) + { + data->len -= 2; + } + data->x --; + data->y ++; + *databuf++ = *data; + } + + //seg 3 + data->type = DIGFONT_V; + data->x = (font->seg1_hspace << 1) + font->seg1_len -1; + data->y = seg35_y; + data->len = font->seg3_len; + *databuf++ = *data; + temp2 = *data; + for(i=1; iseg1_nr; i++) + { + if (i < half) + data->y --; + else + { + data->len -= 2; + data->y ++; + } + + data->x --; + *databuf++ = *data; + } + + // seg4 + data->type = DIGFONT_H; + data->x = font->seg1_hspace; + data->y = hight -1; + data->len = font->seg1_len; + *databuf++ = *data; + for(i=1; iseg1_nr; i++) + { + data->len -= 2; + data->x ++; + data->y --; + *databuf++ = *data; + } + + //seg5 + data->type = DIGFONT_V; + data->x = 0; + data->y = seg35_y; + data->len = font->seg3_len; + *databuf++ = *data; + + for(i=1; iseg1_nr; i++) + { + if (i < half) + data->y --; + else + { + data->len -= 2; + data->y ++; + } + + data->x ++; + *databuf++ = *data; + } + + //seg 6 + data->type = DIGFONT_V; + data->x = 0; + data->y = font->seg1_vspace ; + data->len = font->seg2_len; + *databuf++ = *data; + for(i=1; iseg1_nr; i++) + { + if (i >= half) + { + data->len -= 2; + } + data->x ++; + data->y ++; + *databuf++ = *data; + } + + //seg7 + data->type = DIGFONT_H; + data->x = font->seg1_hspace + half - 1; + data->y = font->seg1_vspace + font->seg2_len + half -1; + data->len = (font->seg1_hspace << 1) + font->seg1_len - \ + ((font->seg1_hspace + half -1) << 1); + *databuf++ = *data; + temp2 = *data; + for(i=0; ix ++; + data->y --; + data->len -= 2; + *databuf++ = *data; + } + + *data = temp2; + for (i=0; ix ++; + data->y ++; + data->len -= 2; + *databuf++ = *data; + } + + return 0; + +__err: + return -1; +} + +int rtgui_dc_draw_digitfont(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect) +{ + int i, size; + struct rtgui_digitfont_data * data; + + size = font->seg1_nr * 7; + data = font->data; + + for(i=0; itype == DIGFONT_H) + rtgui_dc_draw_hline(dc, rect->x1 + data->x, \ + rect->x1 + data->x + data->len, rect->y1 + data->y); + else + rtgui_dc_draw_vline(dc, rect->x1 + data->x, rect->y1 + data->y, \ + rect->y1 + data->y + data->len); + + data++; + } +} + +const char digtube_code_table[] = +{ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,}; + +int rtgui_dc_draw_digitfont_code(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect, char code) +{ + int i,j; + struct rtgui_digitfont_data * data; + rtgui_color_t color; + + data = font->data; + + color = RTGUI_DC_FC(dc); + for(i=0; i<7; i++) + { + if (code & (1 << i)) + RTGUI_DC_FC(dc) = color; + else + RTGUI_DC_FC(dc) = RTGUI_DC_BC(dc); + + for (j=0; jseg1_nr; j++) + { + if (data->type == DIGFONT_H) + rtgui_dc_draw_hline(dc, rect->x1 + data->x, \ + rect->x1 + data->x + data->len, rect->y1 + data->y); + else + rtgui_dc_draw_vline(dc, rect->x1 + data->x, rect->y1 + data->y, \ + rect->y1 + data->y + data->len); + + data++; + } + } + RTGUI_DC_FC(dc) = color; + + return 0; +} + +int rtgui_get_digfont_metrics(struct rtgui_digitfont * font, rtgui_rect_t * rect) +{ + int half = font->seg1_nr >> 1; + rect->x1 = 0; + rect->y1 = 0; + rect->x2 = (font->seg1_hspace << 1) + font->seg1_len; + rect->y2 = (font->seg1_vspace << 1) + font->seg2_len + font->seg3_len + (half << 1) - 1; + return 0; +} + +/* debug */ +struct rtgui_digitfont digitfont_40 = +{ + 34, //int seg1_len; + 3, //int seg1_hspace; + 1, //int seg1_vpace; + 9, //int seg1_nr; //9 + 30, //int seg2_len; + 30, //int seg3_len; + RT_NULL, +}; + +#ifdef _WIN32 +#include +#include +#include +#include +static char fontbuf[80]; +int digfont_file(char * name, struct rtgui_digitfont * font) +{ + int i; + int size; + FILE * file; + struct rtgui_digitfont_data * data; + + if (font->data == RT_NULL) + rtgui_digitfont_create(font); + + /* create a file to store data */ + file = fopen(name, "wb + "); + if (file == RT_NULL) + { + rt_kprintf("open < % s > failed.\n", name); + return -1; + } + data = font->data; + size = font->seg1_nr * 7; + + for( i=0; iseg1_nr)) == 0) + { + sprintf(fontbuf, "\n/* seg <%d> */\n", i/font->seg1_nr + 1); + fwrite(fontbuf, strlen(fontbuf), 1, file); + } + + sprintf(fontbuf, " { % 2d, % 2d, % 2d, % 2d}, \n", data->x, data->y, data->len, data->type); + fwrite(fontbuf, strlen(fontbuf), 1, file); + data ++; + } + fclose(file); + + return 0; +} +#if defined(RT_USING_FINSH) +#include +FINSH_FUNCTION_EXPORT(digfont_file, create the font file of digit font) +#endif + +#endif \ No newline at end of file diff --git a/components/rtgui/widgets/digtube.c b/components/rtgui/widgets/digtube.c new file mode 100644 index 0000000000..e5ce5484ea --- /dev/null +++ b/components/rtgui/widgets/digtube.c @@ -0,0 +1,174 @@ +/* + * File : digfont.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-12-21 pife first version + */ + +#include +#include + +static void _rtgui_digtube_constructor(struct rtgui_digtube * digtube) +{ + RTGUI_WIDGET_TEXTALIGN(digtube) = RTGUI_ALIGN_CENTER; + + /* init widget and set event handler */ + rtgui_object_set_event_handler(RTGUI_OBJECT(digtube), rtgui_digtube_event_handler); +} + +static void _rtgui_digtube_destructor(struct rtgui_digtube *digtube) +{ +#ifndef RTGUI_DIGTUBE_USE_CONST_FONT + /* release font memory */ + rt_free(digtube->digitfont.data); + digtube->digitfont.data = RT_NULL; +#endif +} + +DEFINE_CLASS_TYPE(digtube, "digtube", + RTGUI_WIDGET_TYPE, + _rtgui_digtube_constructor, + _rtgui_digtube_destructor, + sizeof(struct rtgui_digtube)); + +rt_bool_t rtgui_digtube_event_handler(struct rtgui_object *object, struct rtgui_event *event) +{ + struct rtgui_digtube *digtube; + struct rtgui_dc *dc; + rtgui_rect_t rect; + rtgui_rect_t text_rect; + rtgui_color_t color; + char * disbuf; + char tempbuf[8]; + int i; + + RTGUI_WIDGET_EVENT_HANDLER_PREPARE + + digtube = RTGUI_DIGTUBE(object); + switch (event->type) + { + case RTGUI_EVENT_PAINT: + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(object)); + if (dc == RT_NULL) + break; + rtgui_widget_get_rect(RTGUI_WIDGET(object), &rect); + rtgui_dc_fill_rect(dc, &rect); + + if (! (digtube->tube_style & RTGUI_DIGTUBE_STYLE_NOBACKFONT)) + { + color = RTGUI_DC_BC(dc); + RTGUI_DC_BC(dc) = digtube->digit_bc; + } + + if (digtube->tube_style & RTGUI_DIGTUBE_STYLE_DISCODES) + disbuf = (char *) (digtube->value); + else + { + const char * format = + digtube->tube_style & RTGUI_DIGTUBE_STYLE_DISHEXNUM ? + "%7x" : "%7d"; + + disbuf = &tempbuf[0]; + rt_snprintf(disbuf, 8, format, digtube->value); + + /* */ + for (i=0; i<7; i++) + { + if (disbuf[i] == ' ') + disbuf[i] = 0; + else + { + disbuf[i] = (disbuf[i] >= '0' && disbuf[i] <= '9') ? disbuf[i] - '0': + disbuf[i] - 'a' + 10; + + disbuf[i] = digtube_code_table[disbuf[i]]; + } + } + + disbuf = tempbuf + 7 - digtube->tube_count; + } + + text_rect.x1 = 0; + text_rect.y1 = 0; + text_rect.x2 = (digtube->digit_width + digtube->digit_space) * digtube->tube_count + -digtube->digit_space; + text_rect.y2 = digtube->digit_hight; + + rtgui_rect_moveto_align(&rect, &text_rect, RTGUI_DC_TEXTALIGN(dc)); + for (i=0; itube_count; i++) + { + rtgui_dc_draw_digitfont_code(dc, &digtube->digitfont, &text_rect, disbuf[i]); + text_rect.x1 += digtube->digit_width + digtube->digit_space; + } + + if (! (digtube->tube_style & RTGUI_DIGTUBE_STYLE_NOBACKFONT)) + RTGUI_DC_BC(dc) = color; + rtgui_dc_end_drawing(dc); + break; + default: + return rtgui_widget_event_handler(object, event); + } + + return RT_FALSE; +} + +rtgui_digtube_t *rtgui_digtube_create( + struct rtgui_digitfont * digitfont, + int count, + void * value, + int style) +{ + struct rtgui_digtube *digtube; + rtgui_rect_t rect; + + RT_ASSERT(count <= 7 && count > 0) + + digtube = (struct rtgui_digtube *) rtgui_widget_create(RTGUI_DIGTUBE_TYPE); + if (digtube == RT_NULL) + return RT_NULL; + + /* set field */ + if (digitfont == RT_NULL) + digitfont = &digitfont_40; + + rt_memcpy(& digtube->digitfont, digitfont, sizeof(struct rtgui_digitfont)); + +#ifndef RTGUI_DIGTUBE_USE_CONST_FONT + if (digtube->digitfont.data == RT_NULL) + rtgui_digitfont_create(& digtube->digitfont); +#endif + + /* set default rect */ + rtgui_get_digfont_metrics(&digtube->digitfont, &rect); + digtube->digit_width = rect.x2; + digtube->digit_hight = rect.y2; + digtube->tube_count = count; + digtube->digit_space = RTGUI_DIGTUBE_DEFAULT_SPACE; + + rect.x2 = (rect.x2 + digtube->digit_space) * count - digtube->digit_space; + rect.y2 = rect.y2; + + RTGUI_WIDGET_BACKGROUND(digtube) = rtgui_theme_default_bc(); + RTGUI_WIDGET_FOREGROUND(digtube) = RTGUI_DIGTUBE_DEFAULT_FC; + rtgui_widget_set_rect(RTGUI_WIDGET(digtube), &rect); + + /* set display value */ + digtube->digit_bc = RTGUI_DIGTUBE_DEFAULT_DIGIT_BC; + digtube->value = value; + digtube->tube_style = style; + + return digtube; +} + +void rtgui_digtube_destroy(rtgui_digtube_t *digtube) +{ + rtgui_widget_destroy(RTGUI_WIDGET(digtube)); +} \ No newline at end of file diff --git a/components/rtgui/widgets/filelist_view.c b/components/rtgui/widgets/filelist_view.c index effb42c251..78d05c68d0 100644 --- a/components/rtgui/widgets/filelist_view.c +++ b/components/rtgui/widgets/filelist_view.c @@ -250,7 +250,7 @@ static rt_bool_t rtgui_filelist_view_on_folder_item(rtgui_object_t *object, stru view = RTGUI_FILELIST_VIEW(menu->user_data); /* hide window */ - rtgui_win_hiden(menu); + rtgui_win_hide(menu); switch (listbox->current_item) { diff --git a/components/rtgui/widgets/menu.c b/components/rtgui/widgets/menu.c index 07a3a4dd15..ce6f719120 100644 --- a/components/rtgui/widgets/menu.c +++ b/components/rtgui/widgets/menu.c @@ -61,7 +61,7 @@ static rt_bool_t _rtgui_menu_onitem(struct rtgui_object *object, struct rtgui_ev if (!RTGUI_WIDGET_IS_HIDE(menu->sub_menu)) { /* hide this sub menu */ - rtgui_win_hiden(RTGUI_WIN(menu->sub_menu)); + rtgui_win_hide(RTGUI_WIN(menu->sub_menu)); return RT_FALSE; } @@ -91,9 +91,9 @@ static rt_bool_t _rtgui_menu_onitem(struct rtgui_object *object, struct rtgui_ev /* hide sub-menu */ if (menu->sub_menu != RT_NULL) { - rtgui_menu_hiden(menu->sub_menu); + rtgui_menu_hide(menu->sub_menu); } - rtgui_menu_hiden(menu); + rtgui_menu_hide(menu); } return RT_FALSE; } @@ -183,7 +183,7 @@ static rt_bool_t rtgui_menu_on_deactivate(struct rtgui_object *object, rtgui_eve return RT_TRUE; } - rtgui_win_hiden(RTGUI_WIN(menu)); + rtgui_win_hide(RTGUI_WIN(menu)); if (menu->on_menuhide != RT_NULL) { menu->on_menuhide(RTGUI_OBJECT(menu), RT_NULL); @@ -282,13 +282,13 @@ void rtgui_menu_pop(struct rtgui_menu *menu, int x, int y) rtgui_win_show(RTGUI_WIN(menu), RT_FALSE); } -void rtgui_menu_hiden(struct rtgui_menu *menu) +void rtgui_menu_hide(struct rtgui_menu *menu) { - rtgui_win_hiden(RTGUI_WIN(menu)); + rtgui_win_hide(RTGUI_WIN(menu)); /* un-select item */ menu->items_list->current_item = -1; if (menu->parent_menu != RT_NULL) - rtgui_menu_hiden(menu->parent_menu); + rtgui_menu_hide(menu->parent_menu); } diff --git a/components/rtgui/widgets/notebook.c b/components/rtgui/widgets/notebook.c index b0d1846e65..f3a6da232c 100644 --- a/components/rtgui/widgets/notebook.c +++ b/components/rtgui/widgets/notebook.c @@ -539,7 +539,8 @@ void rtgui_notebook_set_current_by_index(struct rtgui_notebook *notebook, rt_uin widget = notebook->childs[notebook->current].widget; rtgui_widget_show(widget); rtgui_widget_update_clip(widget); - rtgui_widget_update(widget); + /* the whole notebook need an update */ + rtgui_widget_update(RTGUI_WIDGET(notebook)); rtgui_widget_focus(widget); } } diff --git a/components/rtgui/widgets/radiobox.c b/components/rtgui/widgets/radiobox.c index 47dc92e9db..4eeb620221 100644 --- a/components/rtgui/widgets/radiobox.c +++ b/components/rtgui/widgets/radiobox.c @@ -228,14 +228,14 @@ void rtgui_radiobox_set_orientation(struct rtgui_radiobox *radiobox, int orienta if (radiobox->orient == RTGUI_HORIZONTAL) { /* HORIZONTAL */ - rtgui_widget_set_miniheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT); - rtgui_widget_set_miniwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH); + rtgui_widget_set_minheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT); + rtgui_widget_set_minwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH); } else { /* VERTICAL */ - rtgui_widget_set_miniwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT); - rtgui_widget_set_miniheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH); + rtgui_widget_set_minwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT); + rtgui_widget_set_minheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH); } #endif } diff --git a/components/rtgui/widgets/slider.c b/components/rtgui/widgets/slider.c index e592183f07..01ef2a340b 100644 --- a/components/rtgui/widgets/slider.c +++ b/components/rtgui/widgets/slider.c @@ -255,14 +255,14 @@ void rtgui_slider_set_orientation(struct rtgui_slider *slider, int orientation) if (slider->orient == RTGUI_HORIZONTAL) { /* HORIZONTAL */ - rtgui_widget_set_miniheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT); - rtgui_widget_set_miniwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH); + rtgui_widget_set_minheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT); + rtgui_widget_set_minwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH); } else { /* VERTICAL */ - rtgui_widget_set_miniwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT); - rtgui_widget_set_miniheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH); + rtgui_widget_set_minwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT); + rtgui_widget_set_minheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH); } #endif } diff --git a/components/rtgui/widgets/staticline.c b/components/rtgui/widgets/staticline.c index 2187f0131c..b3ee043f0d 100644 --- a/components/rtgui/widgets/staticline.c +++ b/components/rtgui/widgets/staticline.c @@ -73,14 +73,14 @@ void rtgui_staticline_set_orientation(rtgui_staticline_t *staticline, int orient if (orientation == RTGUI_HORIZONTAL) { /* HORIZONTAL */ - rtgui_widget_set_miniheight(RTGUI_WIDGET(staticline), 2); - rtgui_widget_set_miniwidth(RTGUI_WIDGET(staticline), 100); + rtgui_widget_set_minheight(RTGUI_WIDGET(staticline), 2); + rtgui_widget_set_minwidth(RTGUI_WIDGET(staticline), 100); } else { /* VERTICAL */ - rtgui_widget_set_miniwidth(RTGUI_WIDGET(staticline), 2); - rtgui_widget_set_miniheight(RTGUI_WIDGET(staticline), 100); + rtgui_widget_set_minwidth(RTGUI_WIDGET(staticline), 2); + rtgui_widget_set_minheight(RTGUI_WIDGET(staticline), 100); } #endif } diff --git a/components/rtgui/widgets/textbox.c b/components/rtgui/widgets/textbox.c index 53642aeed3..6cc46e05f4 100644 --- a/components/rtgui/widgets/textbox.c +++ b/components/rtgui/widgets/textbox.c @@ -54,6 +54,14 @@ static void _rtgui_textbox_constructor(rtgui_textbox_t *box) rtgui_textbox_set_mask_char(box, '*'); rtgui_font_get_metrics(RTGUI_WIDGET_FONT(box), "H", &rect); + rtgui_widget_set_minheight(RTGUI_WIDGET(box), + rtgui_rect_height(rect) + RTGUI_TEXTBOX_BORDER_WIDTH * 2); + /* at least, we want to display one char. */ + rtgui_widget_set_minwidth(RTGUI_WIDGET(box), + rtgui_rect_width(rect) + RTGUI_TEXTBOX_BORDER_WIDTH * 2 \ + + RTGUI_WIDGET_DEFAULT_MARGIN /* there is a margin in the beginning + of the text. */ + ); box->font_width = rtgui_rect_width(rect); box->on_enter = RT_NULL; box->dis_length = 0; @@ -531,13 +539,13 @@ void rtgui_textbox_ondraw(rtgui_textbox_t *box) rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect); fc = RTGUI_WIDGET_FOREGROUND(box); - rtgui_rect_inflate(&rect, -1); + rtgui_rect_inflate(&rect, -RTGUI_TEXTBOX_BORDER_WIDTH); /* fill widget rect with white color */ RTGUI_WIDGET_BACKGROUND(box) = white; rtgui_dc_fill_rect(dc, &rect); - rtgui_rect_inflate(&rect, 1); + rtgui_rect_inflate(&rect, RTGUI_TEXTBOX_BORDER_WIDTH); /* draw border */ RTGUI_WIDGET_FOREGROUND(box) = RTGUI_RGB(123, 158, 189); rtgui_dc_draw_rect(dc, &rect); @@ -610,29 +618,27 @@ char rtgui_textbox_get_mask_char(rtgui_textbox_t *box) return box->mask_char; } -void rtgui_textbox_set_line_length(rtgui_textbox_t *box, rt_size_t length) +rt_err_t rtgui_textbox_set_line_length(rtgui_textbox_t *box, rt_size_t length) { - rt_uint8_t *new_line; + char *new_line; - RT_ASSERT(box != RT_NULL); + RT_ASSERT(box != RT_NULL); - /* invalid length */ - if (length <= 0) - return; + /* invalid length */ + if (length <= 0) + return -RT_ERROR; - new_line = rtgui_malloc(length); - if (length < box->line_length) - { - rt_memcpy(new_line, box->text, length - 1); - new_line[length] = '\0'; - } - else - { - rt_memcpy(new_line, (const char *)box->text, rt_strlen((const char *)box->text)); - } + new_line = rtgui_realloc(box->text, length+1); + if (new_line == RT_NULL) + return -RT_ENOMEM; - /* set line length */ - box->line_length = length; + if (length < box->line_length) + new_line[length] = '\0'; + + box->line_length = length; + box->text = new_line; + + return RT_EOK; } /* get textbox text area */ diff --git a/components/rtgui/widgets/widget.c b/components/rtgui/widgets/widget.c index 83c87ba1b9..9340a5394a 100644 --- a/components/rtgui/widgets/widget.c +++ b/components/rtgui/widgets/widget.c @@ -135,9 +135,9 @@ void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect) rtgui_container_layout(RTGUI_CONTAINER(widget)); } - /* reset mini width and height */ - widget->mini_width = rtgui_rect_width(widget->extent); - widget->mini_height = rtgui_rect_height(widget->extent); + /* reset min width and height */ + widget->min_width = rtgui_rect_width(widget->extent); + widget->min_height = rtgui_rect_height(widget->extent); /* it's not empty, fini it */ if (rtgui_region_not_empty(&(widget->clip))) @@ -184,21 +184,29 @@ void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect) } RTM_EXPORT(rtgui_widget_get_extent); -void rtgui_widget_set_miniwidth(rtgui_widget_t *widget, int width) +void rtgui_widget_set_minsize(rtgui_widget_t *widget, int width, int height) +{ + RT_ASSERT(widget != RT_NULL); + widget->min_width = width; + widget->min_height = height; +} +RTM_EXPORT(rtgui_widget_set_minsize); + +void rtgui_widget_set_minwidth(rtgui_widget_t *widget, int width) { RT_ASSERT(widget != RT_NULL); - widget->mini_width = width; + widget->min_width = width; } -RTM_EXPORT(rtgui_widget_set_miniwidth); +RTM_EXPORT(rtgui_widget_set_minwidth); -void rtgui_widget_set_miniheight(rtgui_widget_t *widget, int height) +void rtgui_widget_set_minheight(rtgui_widget_t *widget, int height) { RT_ASSERT(widget != RT_NULL); - widget->mini_height = height; + widget->min_height = height; } -RTM_EXPORT(rtgui_widget_set_miniheight); +RTM_EXPORT(rtgui_widget_set_minheight); /* * This function moves widget and its children to a logic point diff --git a/components/rtgui/widgets/window.c b/components/rtgui/widgets/window.c index cb93ee9e92..78971a4649 100644 --- a/components/rtgui/widgets/window.c +++ b/components/rtgui/widgets/window.c @@ -178,7 +178,7 @@ static rt_bool_t _rtgui_win_deal_close(struct rtgui_win *win, return RT_FALSE; } - rtgui_win_hiden(win); + rtgui_win_hide(win); win->flag |= RTGUI_WIN_FLAG_CLOSED; @@ -280,7 +280,7 @@ rt_base_t rtgui_win_show(struct rtgui_win *win, rt_bool_t is_modal) /* set main window */ if (app->main_object == RT_NULL) - rtgui_app_set_main_win(win); + rtgui_app_set_main_win(app, win); if (is_modal == RT_TRUE) { @@ -328,7 +328,7 @@ void rtgui_win_end_modal(struct rtgui_win *win, rtgui_modal_code_t modal_code) } RTM_EXPORT(rtgui_win_end_modal); -void rtgui_win_hiden(struct rtgui_win *win) +void rtgui_win_hide(struct rtgui_win *win) { RT_ASSERT(win != RT_NULL); @@ -351,7 +351,7 @@ void rtgui_win_hiden(struct rtgui_win *win) win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE; } } -RTM_EXPORT(rtgui_win_hiden); +RTM_EXPORT(rtgui_win_hide); rt_err_t rtgui_win_activate(struct rtgui_win *win) { @@ -469,7 +469,7 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even break; case RTGUI_EVENT_WIN_HIDE: - rtgui_win_hiden(win); + rtgui_win_hide(win); break; case RTGUI_EVENT_WIN_CLOSE: @@ -538,27 +538,37 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even break; case RTGUI_EVENT_MOUSE_BUTTON: - /* check whether has widget which handled mouse event before */ - if (win->last_mevent_widget != RT_NULL) - { - RTGUI_OBJECT(win->last_mevent_widget)->event_handler( - RTGUI_OBJECT(win->last_mevent_widget), - event); - - /* clean last mouse event handled widget */ - win->last_mevent_widget = RT_NULL; - } - else if (rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win), - (struct rtgui_event_mouse *)event) == RT_FALSE) { + rt_bool_t res = rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win), + (struct rtgui_event_mouse *)event); #ifndef RTGUI_USING_SMALL_SIZE if (RTGUI_WIDGET(object)->on_mouseclick != RT_NULL) { - return RTGUI_WIDGET(object)->on_mouseclick(object, event); + RTGUI_WIDGET(object)->on_mouseclick(object, event); } #endif + /* check whether has widget which handled mouse event before. + * + * Note #1: that the widget should have already received mouse down + * event and we should only feed the mouse up event to it here. + * + * Note #2: the widget is responsible to clean up + * last_mevent_widget on mouse up event(but not overwrite other + * widgets). If not, it will receive two mouse up events. + */ + if (((struct rtgui_event_mouse *)event)->button & RTGUI_MOUSE_BUTTON_UP + && win->last_mevent_widget != RT_NULL) + { + RTGUI_OBJECT(win->last_mevent_widget)->event_handler( + RTGUI_OBJECT(win->last_mevent_widget), + event); + + /* clean last mouse event handled widget */ + win->last_mevent_widget = RT_NULL; + } + + return res; } - break; case RTGUI_EVENT_MOUSE_MOTION: #if 0 @@ -623,7 +633,7 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even return RT_TRUE; break; - default : + default: return rtgui_container_event_handler(object, event); } diff --git a/examples/gui/SConscript b/examples/gui/SConscript index b4d2e952f8..1d82cccdb0 100644 --- a/examples/gui/SConscript +++ b/examples/gui/SConscript @@ -43,6 +43,7 @@ demo_view_edit.c demo_view_bmp.c demo_plot.c mywidget.c +demo_view_digtube.c """) if GetDepend('RTGUI_USING_FONT_COMPACT'): diff --git a/examples/gui/demo_application.c b/examples/gui/demo_application.c index d57987943b..45ce95251a 100644 --- a/examples/gui/demo_application.c +++ b/examples/gui/demo_application.c @@ -33,7 +33,7 @@ static void application_entry(void *parameter) struct rtgui_app *app; struct rtgui_rect rect; - app = rtgui_app_create(rt_thread_self(), "gui_demo"); + app = rtgui_app_create("gui_demo"); if (app == RT_NULL) return; @@ -95,6 +95,7 @@ static void application_entry(void *parameter) demo_view_notebook(); demo_view_mywidget(); demo_plot(); + demo_view_digtube(); #if defined(RTGUI_USING_DFS_FILERW) demo_view_edit(); diff --git a/examples/gui/demo_plot.c b/examples/gui/demo_plot.c index fa524aefa7..14595cb1e9 100644 --- a/examples/gui/demo_plot.c +++ b/examples/gui/demo_plot.c @@ -42,7 +42,7 @@ struct rtgui_container* demo_plot(void) curve1->min_x = 0; curve1->max_x = sizeof(sin_ydata)/sizeof(sin_ydata[0]); curve1->min_y = -100; - curve1->min_y = 100; + curve1->max_y = 100; curve1->color = red; rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve1), RTGUI_MV_VIEW(plot)); @@ -51,22 +51,25 @@ struct rtgui_container* demo_plot(void) RTGUI_MV_MODEL(curve2)->length = sizeof(cos_ydata)/sizeof(cos_ydata[0]); curve2->min_x = 0; curve2->max_x = sizeof(cos_ydata)/sizeof(cos_ydata[0]); - curve1->min_y = -50; - curve1->min_y = 50; + curve2->min_y = -50; + curve2->max_y = 50; curve2->color = blue; rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve2), RTGUI_MV_VIEW(plot)); curve3 = rtgui_plot_curve_create(); rtgui_plot_curve_set_x(curve3, cos_ydata); rtgui_plot_curve_set_y(curve3, sin_ydata); + curve3->min_x = -50; + curve3->max_x = 50; + curve3->min_y = -100; + curve3->max_y = 100; RTGUI_MV_MODEL(curve3)->length = sizeof(sin_ydata)/sizeof(sin_ydata[0]); curve3->color = black; rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve3), RTGUI_MV_VIEW(plot)); rtgui_widget_get_rect(RTGUI_WIDGET(cnt), &rect); rtgui_widget_set_rect(RTGUI_WIDGET(plot), &rect); - rtgui_plot_set_base(plot, - -rtgui_rect_width(rect)/3, rtgui_rect_height(rect)/2); + rtgui_plot_set_base(plot, -100, -300); rtgui_container_add_child(cnt, RTGUI_WIDGET(plot)); diff --git a/examples/gui/demo_view_benchmark.c b/examples/gui/demo_view_benchmark.c index 005db4799f..8664759b5c 100644 --- a/examples/gui/demo_view_benchmark.c +++ b/examples/gui/demo_view_benchmark.c @@ -110,7 +110,7 @@ rt_bool_t benchmark_event_handler(struct rtgui_object *object, rtgui_event_t *ev if (running) { /* stop */ - rtgui_app_set_onidle(RT_NULL); + rtgui_app_set_onidle(rtgui_app_self(), RT_NULL); _draw_default(object, event); } else @@ -118,7 +118,7 @@ rt_bool_t benchmark_event_handler(struct rtgui_object *object, rtgui_event_t *ev /* run */ ticks = rt_tick_get(); area = 0; - rtgui_app_set_onidle(_onidle); + rtgui_app_set_onidle(rtgui_app_self(), _onidle); } running = !running; diff --git a/examples/gui/demo_view_box.c b/examples/gui/demo_view_box.c index f2ab96baa9..51e264aefe 100644 --- a/examples/gui/demo_view_box.c +++ b/examples/gui/demo_view_box.c @@ -34,7 +34,7 @@ rtgui_container_t *demo_view_box(void) button = rtgui_button_create("button 2"); rtgui_container_add_child(RTGUI_CONTAINER(panel), RTGUI_WIDGET(button)); - rtgui_widget_set_miniheight(RTGUI_WIDGET(button), 25); + rtgui_widget_set_minheight(RTGUI_WIDGET(button), 25); RTGUI_WIDGET_ALIGN(button) = RTGUI_ALIGN_EXPAND; rtgui_container_layout(RTGUI_CONTAINER(panel)); diff --git a/examples/gui/demo_view_button.c b/examples/gui/demo_view_button.c index 45c688cfac..2fc73727bb 100644 --- a/examples/gui/demo_view_button.c +++ b/examples/gui/demo_view_button.c @@ -1,13 +1,13 @@ /* - * 程序清单:button控件演示 + * 嵥buttonؼʾ * - * 这个例子会在创建出的container上添加几个不同类型的button控件 + * ӻڴcontainerӼͬ͵buttonؼ */ #include "demo_view.h" #include -/* 创建用于演示button控件的视图 */ +/* ʾbuttonؼͼ */ rtgui_container_t *demo_view_button(void) { rtgui_rect_t rect; @@ -15,64 +15,64 @@ rtgui_container_t *demo_view_button(void) rtgui_button_t *button; rtgui_font_t *font; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("Button View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个button控件 */ + /* һbuttonؼ */ button = rtgui_button_create("Red"); - /* 设置label控件的前景色为红色 */ + /* labelؼǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(button) = red; - /* 设置button的位置 */ + /* buttonλ */ rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个button控件 */ + /* һbuttonؼ */ button = rtgui_button_create("Blue"); - /* 设置label控件的前景色为蓝色 */ + /* labelؼǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(button) = blue; - /* 设置button的位置 */ + /* buttonλ */ rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个button控件 */ + /* һbuttonؼ */ button = rtgui_button_create("12 font"); - /* 设置字体为12点阵的asc字体 */ + /* Ϊ12asc */ font = rtgui_font_refer("asc", 12); RTGUI_WIDGET_FONT(button) = font; - /* 设置button的位置 */ + /* buttonλ */ rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个button控件 */ + /* һbuttonؼ */ button = rtgui_button_create("16 font"); - /* 设置字体为16点阵的asc字体 */ + /* Ϊ16asc */ font = rtgui_font_refer("asc", 16); RTGUI_WIDGET_FONT(button) = font; - /* 设置button的位置 */ + /* buttonλ */ rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); diff --git a/examples/gui/demo_view_checkbox.c b/examples/gui/demo_view_checkbox.c index 8e4e118681..0dc3c751dc 100644 --- a/examples/gui/demo_view_checkbox.c +++ b/examples/gui/demo_view_checkbox.c @@ -1,13 +1,13 @@ /* - * 程序清单:checkbox控件演示 + * 嵥checkboxؼʾ * - * 这个例子会在创建出的container上添加几个checkbox控件 + * ӻڴcontainerӼcheckboxؼ */ #include "demo_view.h" #include -/* 创建用于演示checkbox控件的视图 */ +/* ʾcheckboxؼͼ */ rtgui_container_t *demo_view_checkbox(void) { rtgui_rect_t rect; @@ -15,64 +15,64 @@ rtgui_container_t *demo_view_checkbox(void) rtgui_checkbox_t *checkbox; rtgui_font_t *font; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("CheckBox View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个checkbox控件 */ + /* һcheckboxؼ */ checkbox = rtgui_checkbox_create("Red", RT_TRUE); - /* 设置前景色为红色 */ + /* ǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(checkbox) = red; - /* 设置checkbox的位置 */ + /* checkboxλ */ rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(checkbox)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个checkbox控件 */ + /* һcheckboxؼ */ checkbox = rtgui_checkbox_create("Blue", RT_TRUE); - /* 设置前景色为蓝色 */ + /* ǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(checkbox) = blue; - /* 设置checkbox的位置 */ + /* checkboxλ */ rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(checkbox)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个checkbox控件 */ + /* һcheckboxؼ */ checkbox = rtgui_checkbox_create("12 font", RT_TRUE); - /* 设置字体为12点阵 */ + /* Ϊ12 */ font = rtgui_font_refer("asc", 12); RTGUI_WIDGET_FONT(checkbox) = font; - /* 设置checkbox的位置 */ + /* checkboxλ */ rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(checkbox)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5 + 25 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个checkbox控件 */ + /* һcheckboxؼ */ checkbox = rtgui_checkbox_create("16 font", RT_TRUE); - /* 设置字体为16点阵 */ + /* Ϊ16 */ font = rtgui_font_refer("asc", 16); RTGUI_WIDGET_FONT(checkbox) = font; - /* 设置checkbox的位置 */ + /* checkboxλ */ rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(checkbox)); diff --git a/examples/gui/demo_view_combobox.c b/examples/gui/demo_view_combobox.c index 7542131e7e..4d57a175e0 100644 --- a/examples/gui/demo_view_combobox.c +++ b/examples/gui/demo_view_combobox.c @@ -1,7 +1,7 @@ /* - * 程序清单:label控件演示 + * 嵥labelؼʾ * - * 这个例子会在创建出的container上添加几个不同类型的label控件 + * ӻڴcontainerӼͬ͵labelؼ */ #include "demo_view.h" #include @@ -15,25 +15,25 @@ struct rtgui_listbox_item items[] = {"item 5", RT_NULL}, }; -/* 创建用于演示combobox控件的视图 */ +/* ʾcomboboxؼͼ */ rtgui_container_t *demo_view_combobox(void) { rtgui_rect_t rect; rtgui_container_t *container; rtgui_combobox_t *box; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("ComboBox View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ box = rtgui_combobox_create(items, sizeof(items) / sizeof(items[0]), &rect); - /* container是一个container控件,调用add_child方法添加这个box控件 */ + /* containerһcontainerؼadd_childboxؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(box)); return container; diff --git a/examples/gui/demo_view_digtube.c b/examples/gui/demo_view_digtube.c new file mode 100644 index 0000000000..cff1d34f5e --- /dev/null +++ b/examples/gui/demo_view_digtube.c @@ -0,0 +1,56 @@ +#include "demo_view.h" +#include + +/* digit tube codes: "ERROR" */ +static char digitbuf[5] = {0x79, 0x77, 0x77, 0x3F, 0x77}; + +rtgui_container_t * demo_view_digtube(void) +{ + struct rtgui_rect rect; + rtgui_container_t *container; + struct rtgui_digtube * digtube; + struct rtgui_digitfont digitfont; + + container = demo_view("Digit Tube View"); + /* add digtube 1: use the default digit font */ + digtube = rtgui_digtube_create(RT_NULL, 5, (void *)4213, 0); + rtgui_container_add_child(container, RTGUI_WIDGET(digtube)); + + demo_view_get_rect(container, &rect); + rect.y2 = rect.y1 + 80; + rtgui_widget_set_rect(RTGUI_WIDGET(digtube), &rect); + + /* add digtube 2: show hex */ + digitfont.seg1_len = 20; + digitfont.seg1_hspace = 4; + digitfont.seg1_nr = 3; + digitfont.seg2_len = 20; + digitfont.seg3_len = 20; + digitfont.seg1_vspace = 1; + digitfont.data = RT_NULL; + + digtube = rtgui_digtube_create(&digitfont, 5, (void *)0xABC, RTGUI_DIGTUBE_STYLE_NOBACKFONT | RTGUI_DIGTUBE_STYLE_DISHEXNUM); + rtgui_container_add_child(container, RTGUI_WIDGET(digtube)); + rect.y1 = rect.y2 + 10;; + rect.y2 = rect.y1 + 60; + rtgui_widget_set_rect(RTGUI_WIDGET(digtube), &rect); + + /* add digtube 3: show custom codes table */ + digitfont.seg1_len = 25; + digitfont.seg1_hspace = 5; + digitfont.seg1_nr = 5; + digitfont.seg2_len = 25; + digitfont.seg3_len = 25; + digitfont.seg1_vspace = 1; + digitfont.data = RT_NULL; + digtube = rtgui_digtube_create(&digitfont, 5, (void *)digitbuf, RTGUI_DIGTUBE_STYLE_DISCODES); + rtgui_container_add_child(container, RTGUI_WIDGET(digtube)); + rect.y1 = rect.y2 + 5; + rect.y2 = rect.y1 + 80; + rtgui_widget_set_rect(RTGUI_WIDGET(digtube), &rect); + RTGUI_WIDGET_BACKGROUND(digtube) = RTGUI_RGB(0x00, 0x00, 0x00); + RTGUI_WIDGET_FOREGROUND(digtube) = RTGUI_RGB(0x00, 0xFF, 0x00); + digtube->digit_bc = RTGUI_RGB(0x00, 0xFF, 0xFF); + + return container; +} \ No newline at end of file diff --git a/examples/gui/demo_view_edit.c b/examples/gui/demo_view_edit.c index 3ee31b7994..fd3f81e949 100644 --- a/examples/gui/demo_view_edit.c +++ b/examples/gui/demo_view_edit.c @@ -1,7 +1,7 @@ /* - * 程序清单:edit控件演示 + * 嵥editؼʾ * - * 这个例子会在conatiner上进行edit控件的演示 + * ӻconatinerϽeditؼʾ */ #include "demo_view.h" @@ -22,14 +22,14 @@ void demo_edit_readin_file(struct rtgui_object *object, struct rtgui_event *even RT_ASSERT(object != RT_NULL); button = RTGUI_BUTTON(object); - /* 取得edit指针 */ + /* ȡeditָ */ edit = RTGUI_EDIT(RTGUI_WIDGET(button)->user_data); - /* 判断文件是否存在 */ + /* жļǷ */ file = rtgui_filerw_create_file(filename, "rb"); if (file == RT_NULL) { - /* 不存在存在,则创建它 */ + /* ڴ,򴴽 */ rt_kprintf("file:\"%s\" does not exist!\n", filename); return; @@ -49,15 +49,15 @@ void demo_edit_saveas_file(struct rtgui_object *object, struct rtgui_event *even RT_ASSERT(object != RT_NULL); button = RTGUI_BUTTON(object); - /* 取得edit指针 */ + /* ȡeditָ */ edit = RTGUI_EDIT(RTGUI_WIDGET(button)->user_data); - /* 判断文件是否存在, 如果存在则删除之 */ + /* жļǷ, ɾ֮ */ file = rtgui_filerw_create_file(filename, "rb"); if (file != RT_NULL) { rtgui_filerw_close(file); - /* 如果是在win32中调试, 请手工删除该文件吧, NT中文件是只读的,unlink删除不掉 */ + /* win32е, ֹɾļ, NTļֻ,unlinkɾ */ if (rtgui_filerw_unlink(filename) == -1) rt_kprintf("Could not delete %s\n", filename); } @@ -95,7 +95,7 @@ rt_bool_t demo_edit_event_handler(struct rtgui_object* object, struct rtgui_even return result; } -/* 创建用于演示edit控件的视图 */ +/* ʾeditؼͼ */ rtgui_container_t *demo_view_edit(void) { rtgui_rect_t rect; @@ -104,7 +104,7 @@ rtgui_container_t *demo_view_edit(void) struct rtgui_label *label; struct rtgui_button *button; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("Edit View"); edit = rtgui_edit_create(container, 10, 35, 220, 200); @@ -117,14 +117,14 @@ rtgui_container_t *demo_view_edit(void) "rtgui_edit_insert_line\n" "rtgui_edit_delete_line\n" "rtgui_edit_connect_line\n" - "双字节测试\n" + "˫ֽڲ\n" "a\n" "b\n" "c\n" "d\n" "1234567890\n"); - /* 创建一个按钮, 读取某个文件 */ + /* һť, ȡijļ */ demo_view_get_rect(container, &rect); rect.x1 += 10; rect.x2 = rect.x1 + 100; @@ -134,10 +134,10 @@ rtgui_container_t *demo_view_edit(void) rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); rtgui_button_set_onbutton(button, demo_edit_readin_file); - /* 使用user_data传递edit指针 */ + /* ʹuser_dataeditָ */ RTGUI_WIDGET(button)->user_data = (rt_uint32_t)edit; - /* 创建一个按钮, 保存为某个文件 */ + /* һť, Ϊijļ */ demo_view_get_rect(container, &rect); rect.x1 += 130; rect.x2 = rect.x1 + 100; @@ -147,10 +147,10 @@ rtgui_container_t *demo_view_edit(void) rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); rtgui_container_add_child(container, RTGUI_WIDGET(button)); rtgui_button_set_onbutton(button, demo_edit_saveas_file); - /* 使用user_data传递edit指针 */ + /* ʹuser_dataeditָ */ RTGUI_WIDGET(button)->user_data = (rt_uint32_t)edit; - /* 创建一个标签, 显示EDIT的主要参数 */ + /* һǩ, ʾEDITҪ */ demo_view_get_rect(container, &rect); rect.x1 += 10; rect.x2 = rect.x1 + 220; @@ -165,7 +165,7 @@ rtgui_container_t *demo_view_edit(void) RTGUI_WIDGET(edit)->user_data = (rt_uint32_t)label; rtgui_object_set_event_handler(RTGUI_OBJECT(edit), demo_edit_event_handler); - /* 创建一个按钮, 读取EDIT的内存消耗 */ + /* һť, ȡEDITڴ */ demo_view_get_rect(container, &rect); rect.x1 += 150; rect.x2 = rect.x1 + 80; diff --git a/examples/gui/demo_view_label.c b/examples/gui/demo_view_label.c index a8e87142d6..7355cca648 100644 --- a/examples/gui/demo_view_label.c +++ b/examples/gui/demo_view_label.c @@ -1,12 +1,12 @@ /* - * 程序清单:label控件演示 + * 嵥labelؼʾ * - * 这个例子会在创建出的container上添加几个不同类型的label控件 + * ӻڴcontainerӼͬ͵labelؼ */ #include "demo_view.h" #include -/* 创建用于演示label控件的视图 */ +/* ʾlabelؼͼ */ rtgui_container_t *demo_view_label(void) { rtgui_rect_t rect; @@ -14,89 +14,89 @@ rtgui_container_t *demo_view_label(void) rtgui_label_t *label; rtgui_font_t *font; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("Label View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("Red Left"); - /* 设置label控件上的文本对齐方式为:左对齐 */ + /* labelؼϵı뷽ʽΪ */ RTGUI_WIDGET_TEXTALIGN(label) = RTGUI_ALIGN_LEFT; - /* 设置label控件的前景色为红色 */ + /* labelؼǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(label) = red; - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("Blue Right"); - /* 设置label控件上的文本对齐方式为:右对齐 */ + /* labelؼϵı뷽ʽΪҶ */ RTGUI_WIDGET_TEXTALIGN(label) = RTGUI_ALIGN_RIGHT; - /* 设置label控件的前景色为蓝色 */ + /* labelؼǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(label) = blue; - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("Green Center"); - /* 设置label控件的前景色为绿色 */ + /* labelؼǰɫΪɫ */ RTGUI_WIDGET_FOREGROUND(label) = green; - /* 设置label控件上的文本对齐方式为:右对齐 */ + /* labelؼϵı뷽ʽΪҶ */ RTGUI_WIDGET_TEXTALIGN(label) = RTGUI_ALIGN_CENTER_HORIZONTAL; - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5 + 25 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("12 font"); - /* 设置字体为12点阵的asc字体 */ + /* Ϊ12asc */ font = rtgui_font_refer("asc", 12); RTGUI_WIDGET_FONT(label) = font; - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.y1 += 5 + 25 + 25 + 25 + 25; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("16 font"); - /* 设置字体为16点阵的asc字体 */ + /* Ϊ16asc */ font = rtgui_font_refer("asc", 16); RTGUI_WIDGET_FONT(label) = font; - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); return container; diff --git a/examples/gui/demo_view_listbox.c b/examples/gui/demo_view_listbox.c index 1829c81fb0..9b7f4ed302 100644 --- a/examples/gui/demo_view_listbox.c +++ b/examples/gui/demo_view_listbox.c @@ -1,7 +1,7 @@ /* - * 程序清单:label控件演示 + * 嵥labelؼʾ * - * 这个例子会在创建出的container上添加几个不同类型的label控件 + * ӻڴcontainerӼͬ͵labelؼ */ #include "demo_view.h" #include @@ -149,13 +149,13 @@ static rt_bool_t on_items(struct rtgui_object *object, struct rtgui_event *event /* get listbox */ box = RTGUI_LISTBOX(object); - /* 打印当前的项 */ + /* ӡǰ */ rt_kprintf("current item: %d\n", box->current_item); return RT_TRUE; } -/* 创建用于演示label控件的视图 */ +/* ʾlabelؼͼ */ rtgui_container_t *demo_view_listbox(void) { rtgui_rect_t rect; @@ -163,7 +163,7 @@ rtgui_container_t *demo_view_listbox(void) rtgui_label_t *label; rtgui_listbox_t *box; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("ListBox Demo"); if (item_icon == RT_NULL) @@ -171,24 +171,24 @@ rtgui_container_t *demo_view_listbox(void) (const rt_uint8_t *)image_xpm, sizeof(image_xpm), RT_TRUE); items[1].image = item_icon; - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个label控件 */ + /* һlabelؼ */ label = rtgui_label_create("listbox: "); - /* 设置label的位置 */ + /* labelλ */ rtgui_widget_set_rect(RTGUI_WIDGET(label), &rect); - /* container是一个container控件,调用add_child方法添加这个label控件 */ + /* containerһcontainerؼadd_childlabelؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(label)); rect.y1 = rect.y2 + 3; rect.y2 = 250; box = rtgui_listbox_create(items, sizeof(items) / sizeof(struct rtgui_listbox_item), &rect); rtgui_listbox_set_onitem(box, on_items); - /* container是一个container控件,调用add_child方法添加这个listbox控件 */ + /* containerһcontainerؼadd_childlistboxؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(box)); return container; diff --git a/examples/gui/demo_view_menu.c b/examples/gui/demo_view_menu.c index 45a170999f..e49ceca239 100644 --- a/examples/gui/demo_view_menu.c +++ b/examples/gui/demo_view_menu.c @@ -1,7 +1,7 @@ /* - * 程序清单:menu控件演示 + * 嵥menuؼʾ * - * 这个例子会在创建出的container上添加几个不同类型的label控件 + * ӻڴcontainerӼͬ͵labelؼ */ #include "demo_view.h" #include @@ -46,27 +46,27 @@ static rt_bool_t _onmenu(struct rtgui_object *object, struct rtgui_event *event) return RT_TRUE; } -/* 创建用于演示menu控件的视图 */ +/* ʾmenuؼͼ */ rtgui_container_t *demo_view_menu(void) { rtgui_rect_t rect; rtgui_container_t *container; rtgui_button_t *button; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("MENU View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.x1 + 100; rect.y1 += 5; rect.y2 = rect.y1 + 20; - /* 创建一个button控件 */ + /* һbuttonؼ */ button = rtgui_button_create("Pop Menu"); - /* 设置button的位置 */ + /* buttonλ */ rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect); - /* container是一个container控件,调用add_child方法添加这个button控件 */ + /* containerһcontainerؼadd_childbuttonؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(button)); rtgui_button_set_onbutton(button, _onmenu); diff --git a/examples/gui/demo_view_mywidget.c b/examples/gui/demo_view_mywidget.c index effe4d3507..622cc5a5bd 100644 --- a/examples/gui/demo_view_mywidget.c +++ b/examples/gui/demo_view_mywidget.c @@ -1,41 +1,41 @@ /* - * 程序清单:自定义控件演示 + * 嵥Զؼʾ * - * 这个例子会在创建出的container上添加两个自定义控件 + * ӻڴcontainerԶؼ */ #include "demo_view.h" #include "mywidget.h" -/* 创建用于演示自定义控件的视图 */ +/* ʾԶؼͼ */ rtgui_container_t *demo_view_mywidget(void) { rtgui_container_t *container; rtgui_rect_t rect; rtgui_mywidget_t *mywidget; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("MyWidget View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 = rect.y1 + 80; rect.y1 += 5; rect.y2 = rect.y1 + 80; - /* 创建一个自定义控件 */ + /* һԶؼ */ mywidget = rtgui_mywidget_create(&rect); - /* container是一个container控件,调用add_child方法添加这个自控件 */ + /* containerһcontainerؼadd_childԿؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(mywidget)); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 25; rect.x2 = rect.y1 + 40; rect.y1 += 5 + 100; rect.y2 = rect.y1 + 40; - /* 创建一个自定义控件 */ + /* һԶؼ */ mywidget = rtgui_mywidget_create(&rect); - /* container是一个container控件,调用add_child方法添加这个自控件 */ + /* containerһcontainerؼadd_childԿؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(mywidget)); return container; diff --git a/examples/gui/demo_view_notebook.c b/examples/gui/demo_view_notebook.c index 0573b3ac05..07bc84c966 100644 --- a/examples/gui/demo_view_notebook.c +++ b/examples/gui/demo_view_notebook.c @@ -1,7 +1,7 @@ /* - * 程序清单:notebook控件演示 + * 嵥notebookؼʾ * - * 这个例子会在创建出的container上演示notebook控件 + * ӻڴcontainerʾnotebookؼ */ #include "demo_view.h" @@ -25,7 +25,7 @@ const static struct rtgui_listbox_item items2[] = {"new list #2", RT_NULL}, }; -/* 创建用于演示notebook控件的视图 */ +/* ʾnotebookؼͼ */ rtgui_container_t *demo_view_notebook(void) { rtgui_rect_t rect; @@ -33,14 +33,14 @@ rtgui_container_t *demo_view_notebook(void) struct rtgui_notebook *notebook; rtgui_listbox_t *box; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("Notebook View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); notebook = rtgui_notebook_create(&rect, RTGUI_NOTEBOOK_BOTTOM); - /* container是一个container控件,调用add_child方法添加这个notebook控件 */ + /* containerһcontainerؼadd_childnotebookؼ */ rtgui_container_add_child(container, RTGUI_WIDGET(notebook)); box = rtgui_listbox_create(items, sizeof(items) / sizeof(struct rtgui_listbox_item), &rect); diff --git a/examples/gui/demo_view_radiobox.c b/examples/gui/demo_view_radiobox.c index 45fe343a5a..7d72d550a6 100644 --- a/examples/gui/demo_view_radiobox.c +++ b/examples/gui/demo_view_radiobox.c @@ -1,13 +1,13 @@ /* - * 程序清单:radiobox控件演示 + * 嵥radioboxؼʾ * - * 这个例子会在创建出的container上添加两个不同方向的radiobox控件 + * ӻڴcontainerͬradioboxؼ */ #include "demo_view.h" #include -/* 用于显示垂直方向的radio文本项数组 */ +/* ʾֱradioı */ static char *radio_item_v[5] = { "one", @@ -17,52 +17,52 @@ static char *radio_item_v[5] = "item 2" }; -/* 用于显示水平方向的radio文本项数组 */ +/* ʾˮƽradioı */ static char *radio_item_h[3] = { "one", "two", "three" }; -/* 创建用于演示radiobox控件的视图 */ +/* ʾradioboxؼͼ */ rtgui_container_t *demo_view_radiobox(void) { rtgui_rect_t rect; rtgui_container_t *container; rtgui_radiobox_t *radiobox; - /* 先创建一个演示用的视图 */ + /* ȴһʾõͼ */ container = demo_view("RadioBox View"); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5; rect.y2 = rect.y1 + 5 * 25; - /* 创建一个垂直方向显示的radiobox控件,文本项是radio_item_v数组,共5个项 */ + /* һֱʾradioboxؼıradio_item_v飬5 */ radiobox = rtgui_radiobox_create("Radio Box", RTGUI_VERTICAL, radio_item_v, 5); - /* 设置当前选择的数组是第0项 */ + /* õǰѡǵ0 */ rtgui_radiobox_set_selection(radiobox, 0); - /* 添加radiobox控件到视图中 */ + /* radioboxؼͼ */ rtgui_container_add_child(container, RTGUI_WIDGET(radiobox)); - /* 设置radiobox控件的位置信息 */ + /* radioboxؼλϢ */ rtgui_widget_set_rect(RTGUI_WIDGET(radiobox), &rect); - /* 获得视图的位置信息 */ + /* ͼλϢ */ demo_view_get_rect(container, &rect); rect.x1 += 5; rect.x2 -= 5; rect.y1 += 5 + 5 * 25; rect.y2 = rect.y1 + 60; - /* 创建一个水平方向显示的radiobox控件,文本项是radio_item_h数组,共3个项 */ + /* һˮƽʾradioboxؼıradio_item_h飬3 */ radiobox = rtgui_radiobox_create("Radio Box", RTGUI_HORIZONTAL, radio_item_h, 3); - /* 设置当前选择的数组是第0项 */ + /* õǰѡǵ0 */ rtgui_radiobox_set_selection(radiobox, 0); - /* 添加radiobox控件到视图中 */ + /* radioboxؼͼ */ rtgui_container_add_child(container, RTGUI_WIDGET(radiobox)); - /* 设置radiobox控件的位置信息 */ + /* radioboxؼλϢ */ rtgui_widget_set_rect(RTGUI_WIDGET(radiobox), &rect); return container;